Zápisník experimentátora
Hierarchy: ESP8266
I did a few experiments with the NTP server and ESP8266. Downloading time and converting to UTC is well described directly in demo examples. Conversion of time to the time zone and use of daylight saving time is hardly documented. In this example we will learn how to do this conversion. We will use the libraries that have been prepared for us by skilled programmers.
I have taken advantage of NodeMCU (v. 0.9), but the same results would be achieved with any board on which ESP8266 is.
I tested the code in IDE 1.8.2.
The whole trick of transferring NTP time to local time is concealed in the appropriate use of libraries.
The program prints the current time in several time zones at regular intervals. The example of the listing is in the preview.
sending NTP packet... packet received, length=48 Seconds since Jan 1 1900 = 3709508909 Unix time = 1500520109 03:08:29 Thu 20 Jul 2017 UTC Universal Coordinated Time 05:08:29 Thu 20 Jul 2017 CEST Bratislava 23:08:29 Wed 19 Jul 2017 EDT New York 13:08:29 Thu 20 Jul 2017 AEST Sydney
The introductory part of the program is completely taken from the exemplary example of ESP8266. Only the password setting is changed. It is not directly in the program, but stored safely outside of it. For more details, see the article Inserting the macro definition into the Arduino program.
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <TimeLib.h>
#include <Timezone.h>
// Safe stored password
// http://www.arduinoslovakia.eu/blog/2017/6/vlozenie-definicie-makra-do-programu-v-arduine?lang=en
#if defined(_SSID)
const char* ssid = _SSID;
const char* pass = _PWD;
#else
char ssid[] = "*************"; // your network SSID (name)
char pass[] = "********"; // your network password
#endif
unsigned int localPort = 2390; // local port to listen for UDP packets
IPAddress timeServerIP; // time.nist.gov NTP server address
const char* ntpServerName = "time.nist.gov";
const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message
byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
// A UDP instance to let us send and receive packets over UDP
WiFiUDP udp;
Next time zones. The author of the Arduino Timezone Library
has proposed a convenient way to define any time zone. You only need to know the time-change rule from summer to winter and vice versa, and the rest will make classes TimeChangeRule
and Timezone
.
//Central European Time (Frankfurt, Paris)
TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 120}; //Central European Summer Time
TimeChangeRule CET = {"CET", Last, Sun, Oct, 3, 60}; //Central European Standard Time
Timezone CE(CEST, CET);
//Australia Eastern Time Zone (Sydney, Melbourne)
TimeChangeRule aEDT = {"AEDT", First, Sun, Oct, 2, 660}; //UTC + 11 hours
TimeChangeRule aEST = {"AEST", First, Sun, Apr, 3, 600}; //UTC + 10 hours
Timezone ausET(aEDT, aEST);
//US Eastern Time Zone (New York, Detroit)
TimeChangeRule usEDT = {"EDT", Second, Sun, Mar, 2, -240}; //Eastern Daylight Time = UTC - 4 hours
TimeChangeRule usEST = {"EST", First, Sun, Nov, 2, -300}; //Eastern Standard Time = UTC - 5 hours
Timezone usET(usEDT, usEST);
Now I will skip most of the code and focus only on converting the time we've got from the NTP server. Its function can be guessed from the source code itself. First, time is converted from base in 1900 to base in 1970, and then conversion is required to a specific time zone. The result is printed with printTime. You see, this is nothing complicated.
If you write a program to respond to local time, it's a good time to store time in a UTC (for example, in the DS1307), and only if necessary convert it, compare it to a defined action time, and take action.
udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer
//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;
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 seventyYears = 2208988800UL;
// subtract seventy years:
unsigned long epoch = secsSince1900 - seventyYears;
// print Unix time:
Serial.println(epoch);
TimeChangeRule *tcr;
time_t utc;
utc = epoch;
printTime(utc, "UTC", "Universal Coordinated Time");
printTime(CE.toLocal(utc, &tcr), tcr -> abbrev, "Bratislava");
printTime(usET.toLocal(utc, &tcr), tcr -> abbrev, "New York");
printTime(ausET.toLocal(utc, &tcr), tcr -> abbrev, "Sydney");
The source code is located on the GitHub server.
23.07.2017