Important changes to forums and questions
All forums and questions are now archived. To start a new conversation or read the latest updates go to forums.mbed.com.
8 years, 11 months ago. This question has been closed. Reason: Off Topic
ESP8266 - How to get NTP time?
Hi mbed friends,
can I get NTP time using an ESP8266 ESP-01 Serial Wireless WIFI Module?
In order to connect the NUCLEO-F746ZG to the internet via wifi, I use this ESP8266 module: https://nurdspace.nl/ESP8266 Some useful documentation was found here: https://alselectro.wordpress.com/2015/05/05/wifi-module-esp8266-1-getting-started-with-at-commands/
Mine use firmware (AT+GMR):
AT version:1.1.0.0(May 11 2016 18:09:56) SDK version:1.5.4(baaeaebb) Ai-Thinker Technology Co. Ltd.
If I use below library it connects to wifi: https://developer.mbed.org/teams/components/code/ESP8266/
I do something like this:
#define ESP8266_TX PC_6 // PC_6 Serial6_TX
#define ESP8266_RX PC_7 // PC_7 Serial6_RX
#define ESP8266_RST PE_11 // D5 Reset
ESP8266 esp(ESP8266_TX, ESP8266_RX, true); // tx, rx, debug
esp.startup(ESP8266_AP_STATION_MODE);
esp.connect("SSID", "Passwd");
printf("IP %s\n", esp.getIPAddress());
That works! Then I attempt to get NTP time, like this, but the return size = -1 (time-out, notting received):
// esp.open("UDP", 1, "1.nl.pool.ntp.org", 123);
esp.open("UDP", 1, "129.250.35.250", 123);
const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message
unsigned char packetBuffer[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
// [4]-[11]: 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;
esp.send(1, packetBuffer, NTP_PACKET_SIZE);
wait(1.0);
uint32_t recv_size = esp.recv(1, packetBuffer, NTP_PACKET_SIZE);
printf("Size %d\n", recv_size);
esp.close(1);
// combine the four bytes (two words) into a long integer
// this is NTP time (seconds since Jan 1 1900):
uint32_t secsSince1900 = (packetBuffer[40] << 24) | (packetBuffer[41] << 16) | (packetBuffer[42] << 8) | packetBuffer[43];
printf("TS: %ul\n", secsSince1900);
Update: The returned size of -1 is probably a bug in ESP8266 Library. I "fixed" it (-1 should be reported when failing to receive a package, I think):
int32_t ESP8266::recv(int id, void *data, uint32_t amount)
{
// Receive network data:
// +IPD
// Receive network data from single connection:
// +IPD,len:data
// Receive network data from multiple connection:
// +IPD,id,len:data
// Parameters:
// id: id no. of connection
// len: data length
// data: data received
uint32_t recv_amount;
int recv_id;
if (!(_parser.recv("+IPD,%d,%d:", &recv_id, &recv_amount)
&& recv_id == id
&& recv_amount <= amount
&& _parser.read((char*)data, recv_amount)
&& _parser.recv("OK"))) {
return recv_amount;
// return -1;
}
return recv_amount;
}
The timestamp value is much higher than I expected: 3687018995 instead of 1478030195. This is because NTP counts from 1900 and the Unix time stamp counts from 1970. NTP uses an epoch of 1900-01-01 00:00:00, so the offset should be 2208988800 seconds to 1970-01-01 00:00:00. And the difference in seconds will be calculated like: (70*365 + 17)*86400 = 2208988800.
ESP8266Interface looked more promising, it possibly can be combined with the NTPClient library. Si I tried ESP8266Interface, but it hangs at init and does not connect to wifi. It is possibly that doesn't work with the Ai-Thinker firmware.
ESP8266Interface esp(ESP8266_TX, ESP8266_RX, ESP8266_RST, "SSID", "Passwd", 115200); // tx, rx, reset, ssid, phrase, baud
printf("Init... ");
esp.init(); //Reset // <--- Hangs here
printf("OK\n");
printf("Connecting... ");
esp.connect(); //Use DHCP
printf("OK\n");
printf("IP %s\n", esp.getIPAddress());
Has anybody done this before?
In the mean time, I continued troubleshooting, and got the first method working. I shares above how it was done.
Kind regards, Jack.
Now, I have a bit more time to play with mbed stuff. :-)
I'm playing with the ESP8266 and NTP, and added a function in a ESP8266 Library to get the NTP time. This seems to work very well, picks up fast and sure:
bool ESP8266::getNTP(uint32_t *secsSince1970, char * NTPpool) { unsigned char packetBuffer[NTP_PACKET_SIZE]; memset(packetBuffer, 0x00, 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 // [4]-[11]: 8 bytes of zero for Root Delay & Root Dispersion packetBuffer[12] = 49; packetBuffer[13] = 0x4E; packetBuffer[14] = 49; packetBuffer[15] = 52; setTimeout(50); uint32_t recv_size = 0; int tries1 = 10; while ((recv_size != NTP_PACKET_SIZE) && (tries1 > 0)) { tries1--; open("UDP", 1, NTPpool, 123); // NTPpool = "1.nl.pool.ntp.org" send(1, packetBuffer, NTP_PACKET_SIZE); int tries2 = 100; while ((recv_size != NTP_PACKET_SIZE) && (tries2 > 0)) { tries2--; recv_size = recv(1, packetBuffer, NTP_PACKET_SIZE); } } close(1); *secsSince1970 = ((packetBuffer[40] << 24) | (packetBuffer[41] << 16) | (packetBuffer[42] << 8) | packetBuffer[43]) - NTP_OFFSET; return recv_size == NTP_PACKET_SIZE ? true : false; }Note: NTP uses an epoch of 1900-01-01 00:00:00, so the offset should be 2208988800 seconds to 1970-01-01 00:00:00. (70*365 + 17)*86400 = 2208988800
And for the RTC:
void DS3231::setDateTimeSecsSince1970(uint32_t secsSince1970) { time_t secondsEpoch = (time_t)(secsSince1970 + timeZoneOffset); t = *localtime(&secondsEpoch); t.tm_year += 1900; // adjust for tm structure required values t.tm_mon += 1; // adjust for tm structure required values setDateTime(t.tm_mday, t.tm_mon, t.tm_year, t.tm_hour, t.tm_min, t.tm_sec); set_time(secsSince1970); }In main, I did this:
oled.printf("Get NTP: "); uint32_t secsSince1970 = 0; bool succes = esp.getNTP(&secsSince1970, "1.nl.pool.ntp.org"); if (succes) oled.printf("Succes!\n"); else oled.printf("FAILED!\n"); ds3231.setDateTimeSecsSince1970(secsSince1970); // Get updated time using timezone secsSince1970 = ds3231.getDateTimeSecsSince1970(); strftime(buffer, 32, "%A\n%d-%m-%Y %H:%M:%S", localtime(&secsSince1970)); oled.gotoxy(0, 5); oled.printf("%s\n", buffer);I hope I help somebody with this. Any comments or recommendations are welcome, I'm not yet an mbed expert. :-)
Regards, Jack.
posted by Jack Berkhout 04 Nov 2016