Arduino ESP8266 and NTP

I am starting to get involved with these mini wifi boards. I am creating a web app that allows me to manage these boards.

Part of the app is a webservice that allows the boards to get certain types of info.

can you perform a http request with your sketch?

If yes, this tells you the time: http://www.foxhollow.ca/nodemgr/?time
this tells you the date: http://www.foxhollow.ca/nodemgr/?date

You tell your mini board to retrieve the data from the above URL and you get the date/time in plain ascii.

I have created some interesting functions like 'weekend'. It will tell your board if is the weekend or weekday (for processes that need to act differently on weekdays/weekends)

more info here: http://www.foxhollow.ca/nodemgr/?info

This is an easy to install php based web app that I have running on a Linux server. I am not sure if it is of use to any other person.

This is interesting, but how to get a date in 24-hour format?

Working code with this library:

#include "ESP8266.h"
#include <SoftwareSerial.h>
SoftwareSerial espSerial(10, 11); // RX:D11, TX:D10 

#define HOST_NAME   "82.209.243.241"
#define HOST_PORT   (123)

ESP8266 wifi(espSerial);

void setup()
{
  Serial.begin(9600);
  Serial.print("setup begin\r\n");
  Serial.print("Join AP success\r\n");
  Serial.print("IP: ");
  Serial.println(wifi.getLocalIP().c_str());

  if (wifi.disableMUX()) {
    Serial.print("single ok\r\n");
  } else {
    Serial.print("single err\r\n");
  }

  Serial.print("setup end\r\n");
}
void loop()
{
  ntpupdate();
  delay(20000);
}

void ntpupdate()
{
  uint8_t buffer[128] = {0};

  if (wifi.registerUDP(HOST_NAME, HOST_PORT)) {
    Serial.print("register udp ok\r\n");
  } else {
    Serial.print("register udp err\r\n");
  }

  static const char PROGMEM
  timeReqA[] = { 227,  0,  6, 236 },
               timeReqB[] = {  49, 78, 49,  52 };
  // Assemble and issue request packet
  uint8_t       buf[48];
  memset(buf, 0, sizeof(buf));
  memcpy_P( buf    , timeReqA, sizeof(timeReqA));
  memcpy_P(&buf[12], timeReqB, sizeof(timeReqB));


  //    char *buf = "Hello, this is client!";
  wifi.send((const uint8_t*)buf, 48);

  uint32_t len = wifi.recv(buffer, sizeof(buffer), 10000);
  if (len > 0) {
    Serial.print("UNIX TIME IS:");

    // Serial.print(buffer[42]);
    unsigned long t = (((unsigned long)buffer[40] << 24) |
                       ((unsigned long)buffer[41] << 16) |
                       ((unsigned long)buffer[42] <<  8) |
                       (unsigned long)buffer[43]) - 2208988800UL;

    Serial.println(t);
  }

  if (wifi.unregisterUDP()) {
    Serial.print("unregister udp ");
    Serial.println(" ok");
  } else {
    Serial.print("unregister udp ");
    Serial.println(" err");
  }

}

adminarduinocc:
This is interesting, but how to get a date in 24-hour format?

If you pull up the info page you can see that you can ask for any part of the date/time.

However, give me an example of how you would like it to appear and I'll add a new function called "time24"

I am guessing 17:01:12 for 5:01pm 12secs in the afternoon


Update: http://www.foxhollow.ca/nodemgr/index.php?info
http://www.foxhollow.ca/nodemgr/index.php?time24 (display in 24hour format)

This is your personal website? As far as it shows the exact time? Can I use it to synchronize the time? Can you add a function to display the time in Unix format? Unix time - Wikipedia

adminarduinocc:
This is your personal website? As far as it shows the exact time? Can I use it to synchronize the time? Can you add a function to display the time in Unix format? Unix time - Wikipedia

Yes. It is my website and I use NTP to keep the time correct. I do not care if you sync against my server.

The plan is to finish a few functions and release the app so you can run it on your own Linux box (but I'll keep my box going). I like the registration and alert features... more on those later.

ps: I added "unixtime" to the webservice.

http://www.foxhollow.ca/nodemgr?unixtime

and updated the command list on the info screen: http://www.foxhollow.ca/nodemgr?info

Working code with standasrt AT commands:

void ntpupdate()
{
  const byte NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message
  byte packetBuffer[ NTP_PACKET_SIZE];
  
Serial.println("AT+CIPSTART=\"UDP\",\"91.226.136.136\",123");
  delay(500);
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
 
 // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
 
 packetBuffer[0] = 0b11100011; // LI, Version, Mode
  packetBuffer[1] = 0; // Stratum, or type of clock
  packetBuffer[2] = 6; // Polling Interval
  packetBuffer[3] = 0xEC; // Peer Clock Precision
 
 // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12] = 49;
  packetBuffer[13] = 0x4E;
  packetBuffer[14] = 49;
  packetBuffer[15] = 52;
  Serial.print("AT+CIPSEND=");
  Serial.println(NTP_PACKET_SIZE);
  delay(500);
  for (uint32_t i = 0; i < NTP_PACKET_SIZE; i++) {
    Serial.write(packetBuffer[i]);
  }

  int counta = 0;
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  if (Serial.find("+IPD,48:"))
  {
    dbgSerial.println("Server answer : ");

    int i = 0;
    while (Serial.available() > 0) {
      byte ch = Serial.read();
      if (i < NTP_PACKET_SIZE)
      {
        packetBuffer[i] = ch;
      }
      i++;
      if ( ( i < NTP_PACKET_SIZE ) && ( Serial.available() == 0 ) )
      {
        while (Serial.available() == 0) // you may have to wait for some bytes
        {
          counta += 1;
          dbgSerial.print("!");
          delay(100);
          if (counta == 15) {
            exit;
          }
        }
      }
    }
  }
   //the timestamp starts at byte 40 of the received packet and is four bytes,
  // or two words, long. First, esxtract the two words:

  unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
  unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
  // combine the four bytes (two words) into a long integer
  // this is NTP time (seconds since Jan 1 1900):
  unsigned long secsSince1900 = highWord << 16 | lowWord;
  dbgSerial.print("Seconds since Jan 1 1900 = " );
  dbgSerial.println(secsSince1900);

  // now convert NTP time into everyday time:
  dbgSerial.print("Unix time = ");
  // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
  const unsigned long seventyYears = 2208988800UL;
  // subtract seventy years:
  unsigned long epoch = secsSince1900 - seventyYears;
  // print Unix time:
  dbgSerial.println(epoch);

  // print the hour, minute and second:
  dbgSerial.print("The UTC time is "); // UTC is the time at Greenwich Meridian (GMT)
  dbgSerial.print((epoch % 86400L) / 3600); // print the hour (86400 equals secs per day)
  dbgSerial.print(':');
  if ( ((epoch % 3600) / 60) < 10 ) {
    // In the first 10 minutes of each hour, we'll want a leading '0'
    dbgSerial.print('0');
  }
  dbgSerial.print((epoch % 3600) / 60); // print the minute (3600 equals secs per minute)
  dbgSerial.print(':');
  if ( (epoch % 60) < 10 ) {
    // In the first 10 seconds of each minute, we'll want a leading '0'
    dbgSerial.print('0');
  }
  dbgSerial.println(epoch % 60); // print the second
  dbgSerial.println(" ");
  Serial.println("AT+CIPCLOSE");
   }

Check out this: UdpNTPClient
It is basically the same example of the standard Arduino WiFi library adapted for the WiFiEsp library that works with ESP8266 module.

twim:
Check out this: UdpNTPClient
It is basically the same example of the standard Arduino WiFi library adapted for the WiFiEsp library that works with ESP8266 module.

Good job! Thanks!
Will this code work without Arduino board? For example, if you connect Esp8266 and tm1637?

twim:
Check out this: UdpNTPClient
It is basically the same example of the standard Arduino WiFi library adapted for the WiFiEsp library that works with ESP8266 module.

give me the same Unix time
17
packet received
Seconds since Jan 1 1900 = 0
Unix time = 2085978496
The UTC time is 6:28:16
48
packet received
Seconds since Jan 1 1900 = 0
Unix time = 2085978496
The UTC time is 6:28:16

void ntpupdate()
{
  String cmd = "AT+CIPSTART=\"UDP\",\"";
  uint8_t i;
  cmd += ntp;
  cmd += "\",123\r\n";
  sendData(cmd, 5000, DEBUG);
  delay(500);
  memset(buffer, 0, BUFFER_SIZE); 
 // Initialize values needed to form NTP request
  // (see URL above for details on the packets) 
  buffer[0] = 0b11100011; // LI, Version, Mode
  buffer[1] = 0; // Stratum, or type of clock
  buffer[2] = 6; // Polling Interval
  buffer[3] = 0xEC; // Peer Clock Precision 
 // 8 bytes of zero for Root Delay & Root Dispersion
  buffer[12] = 49;
  buffer[13] = 0x4E;
  buffer[14] = 49;
  buffer[15] = 52;
  Serial.println("Send request");
  esp8266.print("AT+CIPSEND=");
  esp8266.println(NTP_PACKET_SIZE);
  delay(20);
  if (esp8266.find(">"))
  {
    Serial.println("Read >");
    for (i = 0; i < NTP_PACKET_SIZE; i++) 
    {
    esp8266.write(buffer[i]);
    delay(5);
    } 
    delay(200);
    memset(buffer, 0, NTP_PACKET_SIZE);  
    Serial.println("Server answer : ");
    i = 0;
    long int time_ = millis();    
    if (esp8266.find("+IPD,48:"))
    {
      Serial.println("Found +IPD,48:");
      while( (time_+4000) > millis())
      {
          while((esp8266.available()) && (i < NTP_PACKET_SIZE))
          {
              byte ch = esp8266.read();
              if (ch < 0x10) Serial.print('0');
              Serial.print(ch,HEX);
              Serial.print(' ');
              if ( (((i+1) % 15) == 0) ) { Serial.println(); }
              buffer[i] = ch; // read the next character.
              i++;           
          }
      }
      Serial.println();
      Serial.print("Read bytes - ");
      Serial.println(i);
      if (i == NTP_PACKET_SIZE) {
       Serial.println();
       Serial.print(buffer[40],HEX);
       Serial.print(" ");
       Serial.print(buffer[41],HEX);
       Serial.print(" ");
       Serial.print(buffer[42],HEX);
       Serial.print(" ");
       Serial.print(buffer[43],HEX);
       Serial.print(" = ");
         
       //the timestamp starts at byte 40 of the received packet and is four bytes,
       // or two words, long. First, esxtract the two words:
        
       unsigned long highWord = word(buffer[40], buffer[41]);
       unsigned long lowWord = word(buffer[42], buffer[43]);
       // combine the four bytes (two words) into a long integer
       // this is NTP time (seconds since Jan 1 1900):
       unsigned long secsSince1900 = highWord << 16 | lowWord;
       Serial.print("Seconds since Jan 1 1900 = " );
       Serial.println(secsSince1900);
        
       // now convert NTP time into everyday time:
       Serial.print("Unix time = ");
       // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
       const unsigned long DST = 3600*timeZone
       const unsigned long seventyYears = 2208988800UL - DST;
       // subtract seventy years:
       unsigned long epoch = secsSince1900 - seventyYears;
       // print Unix time:
       Serial.println(epoch);    
       // print the hour, minute and second:
       Serial.print("The UTC time is "); // UTC is the time at Greenwich Meridian (GMT)
       Serial.print((epoch % 86400L) / 3600); // print the hour (86400 equals secs per day)
       Serial.print(':');
       if ( ((epoch % 3600) / 60) < 10 ) {
        // In the first 10 minutes of each hour, we'll want a leading '0'
          Serial.print('0');
          }
       Serial.print((epoch % 3600) / 60); // print the minute (3600 equals secs per minute)
       Serial.print(':');
       if ( (epoch % 60) < 10 ) {
          // In the first 10 seconds of each minute, we'll want a leading '0'
            Serial.print('0');
          }
       Serial.println(epoch % 60); // print the second
       Serial.println(" ");
     }      
  } else {
      Serial.println("Not Found +IPD,48:");
      }
  } else {
      Serial.println("No answer to server ");
   }
  esp8266.println("AT+CIPCLOSE");
 
  
}

Often, instead of 48 bytes, only half comes

This is a few years old, and it seems things have changed, i couldn't get this to work. So, this is possibly the least graceful way of getting the time w/ an ESP8266, but after spending days trying to learn how to program Arduino, most everything above was too advance for me to figure out, except that I could tell the time from the NTP server was not always coming back in the same position, and was taking more than just 4 bytes. I have no idea why, but I can copy and paste hex into an online converter:)

Here is my solution to getting the current time, hopefully it helps somebody else.

ESP8266 is connected to a Mega2560 via Serial 3
If you have a Mega w/ builtin WiFi, it seems they are also connected to Serial 3

HardwareSerial & dbgTerminal = Serial;
HardwareSerial & espSerial = Serial3;

String sntptime, day, month, daynum, hour, minute, second, year;

// Get the data from the WiFi module and send it to the debug serial port
String GetResponse(String AT_Command, int wait){
String tmpData;

espSerial.println(AT_Command);
delay(200);
while (espSerial.available() >0 ) {
char c = espSerial.read();
tmpData += c;

if ( tmpData.indexOf(AT_Command) > -1 )
tmpData = "";
else
tmpData.trim();

}
return tmpData;
}

String GetTime()
{

// Uses the modem's SNTP feature to get the time
//the time always comes back 3 letter day, 3 letter month, 2 digit day number, 2 digit hr, : 2 digit minute, : 2 digit second, 4 digit year

sntptime = GetResponse("AT+CIPSNTPTIME?", 100);

// Serial.println(sntptime);
sntptime.remove(0,13); // Remove 13 characters starting at index=0
sntptime.remove(20);
// Serial.print("removed first 13 letters from sntptime = ");
// Serial.println(sntptime);
day=sntptime;
day.remove(3); // Remove from from index=3 through the end of the string
// Serial.print("Day = ");
// Serial.println(day);
month=sntptime;
month.remove(0,3);
month.remove(3);
// Serial.print("Month = ");
// Serial.println(month);
daynum=sntptime;
daynum.remove(0,6);
daynum.remove(2);
// Serial.print("Day number = ");
// Serial.println(daynum);
hour=sntptime;
hour.remove(0,8);
hour.remove(2);
// Serial.print("Hour = ");
// Serial.println(hour);
minute=sntptime;
minute.remove(0,11);
minute.remove(2);
// Serial.print("Minutes = ");
// Serial.println(minute);
second=sntptime;
second.remove(0,14);
second.remove(2);
// Serial.print("Seconds = ");
// Serial.println(second);
year=sntptime;
year.remove(0,16);
year.remove(4);
// Serial.print("Year = ");
// Serial.println(year);

return sntptime;

}

mpopgun:
This is a few years old, and it seems things have changed, . . .

Now that you have resurrected this three year old post you might as well take advantage of the latest changes. Now that the ESP8266 core has been updated with some of the ESP32 code retrieving the date and time information from an NTP server involves just a few lines of code.

Take a look at this thread from a few weeks ago.

The code I posted in that thread also shows how to use strftime() to display the date and time once you have gotten the raw information from the NTP server.

Don

floresta:
Now that you have resurrected this three year old post you might as well take advantage of the latest changes. Now that the ESP8266 core has been updated with some of the ESP32 code retrieving the date and time information from an NTP server involves just a few lines of code.

Take a look at this thread from a few weeks ago.

The code I posted in that thread also shows how to use strftime() to display the date and time once you have gotten the raw information from the NTP server.

Don

Very cool! TY
I have a mega with an esp connected via serial 3, using AT commands...I don't think i can use those built in functions can I?

That was always my hurdle, everybody had a card with wifi built in and could use built in fuctions, the code above mine is the only example i could find that used AT commands but they were advanced and formatted the UDP packets. However the packets coming back from the server didn't have data consistently in the same packets.

If there is some reason that you must use the Mega along with the ESP8266 (instead of just using the ESP8266 alone) then you could look into the possibility of doing just the NTP stuff on the ESP8266. Then you could send the resulting UNIX timestamp to the Mega and do the rest there.

Don