forked from esp8266/Arduino
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathNTP-TZ-DST.ino
260 lines (210 loc) · 7.31 KB
/
NTP-TZ-DST.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
/*
NTP-TZ-DST (v2)
NetWork Time Protocol - Time Zone - Daylight Saving Time
This example shows:
- how to read and set time
- how to set timezone per country/city
- how is local time automatically handled per official timezone definitions
- how to change internal sntp start and update delay
- how to use callbacks when time is updated
This example code is in the public domain.
*/
#ifndef STASSID
#define STASSID "your-ssid"
#define STAPSK "your-password"
#endif
// initial time (possibly given by an external RTC)
#define RTC_UTC_TEST 1510592825 // 1510592825 = Monday 13 November 2017 17:07:05 UTC
// This database is autogenerated from IANA timezone database
// https://www.iana.org/time-zones
// and can be updated on demand in this repository
#include <TZ.h>
// "TZ_" macros follow DST change across seasons without source code change
// check for your nearest city in TZ.h
// espressif headquarter TZ
//#define MYTZ TZ_Asia_Shanghai
// example for "Not Only Whole Hours" timezones:
// Kolkata/Calcutta is shifted by 30mn
//#define MYTZ TZ_Asia_Kolkata
// example of a timezone with a variable Daylight-Saving-Time:
// demo: watch automatic time adjustment on Summer/Winter change (DST)
#define MYTZ TZ_Europe_London
////////////////////////////////////////////////////////
#include <ESP8266WiFi.h>
#include <coredecls.h> // settimeofday_cb()
#include <Schedule.h>
#include <PolledTimeout.h>
#include <time.h> // time() ctime()
#include <sys/time.h> // struct timeval
#include <sntp.h> // sntp_servermode_dhcp()
// for testing purpose:
extern "C" int clock_gettime(clockid_t unused, struct timespec *tp);
////////////////////////////////////////////////////////
static timeval tv;
static timespec tp;
static time_t now;
static uint32_t now_ms, now_us;
static esp8266::polledTimeout::periodicMs showTimeNow(60000);
static int time_machine_days = 0; // 0 = now
static bool time_machine_running = false;
// OPTIONAL: change SNTP startup delay
// a weak function is already defined and returns 0 (RFC violation)
// it can be redefined:
//uint32_t sntp_startup_delay_MS_rfc_not_less_than_60000 ()
//{
// //info_sntp_startup_delay_MS_rfc_not_less_than_60000_has_been_called = true;
// return 60000; // 60s (or lwIP's original default: (random() % 5000))
//}
// OPTIONAL: change SNTP update delay
// a weak function is already defined and returns 1 hour
// it can be redefined:
//uint32_t sntp_update_delay_MS_rfc_not_less_than_15000 ()
//{
// //info_sntp_update_delay_MS_rfc_not_less_than_15000_has_been_called = true;
// return 15000; // 15s
//}
#define PTM(w) \
Serial.print(" " #w "="); \
Serial.print(tm->tm_##w);
void printTm(const char* what, const tm* tm) {
Serial.print(what);
PTM(isdst); PTM(yday); PTM(wday);
PTM(year); PTM(mon); PTM(mday);
PTM(hour); PTM(min); PTM(sec);
}
void showTime() {
gettimeofday(&tv, nullptr);
clock_gettime(0, &tp);
now = time(nullptr);
now_ms = millis();
now_us = micros();
Serial.println();
printTm("localtime:", localtime(&now));
Serial.println();
printTm("gmtime: ", gmtime(&now));
Serial.println();
// time from boot
Serial.print("clock: ");
Serial.print((uint32_t)tp.tv_sec);
Serial.print("s / ");
Serial.print((uint32_t)tp.tv_nsec);
Serial.println("ns");
// time from boot
Serial.print("millis: ");
Serial.println(now_ms);
Serial.print("micros: ");
Serial.println(now_us);
// EPOCH+tz+dst
Serial.print("gtod: ");
Serial.print((uint32_t)tv.tv_sec);
Serial.print("s / ");
Serial.print((uint32_t)tv.tv_usec);
Serial.println("us");
// EPOCH+tz+dst
Serial.print("time: ");
Serial.println((uint32_t)now);
// timezone and demo in the future
Serial.printf("timezone: %s\n", getenv("TZ") ? : "(none)");
// human readable
Serial.print("ctime: ");
Serial.print(ctime(&now));
// LwIP v2 is able to list more details about the currently configured SNTP servers
for (int i = 0; i < SNTP_MAX_SERVERS; i++) {
IPAddress sntp = *sntp_getserver(i);
const char* name = sntp_getservername(i);
if (sntp.isSet()) {
Serial.printf("sntp%d: ", i);
if (name) {
Serial.printf("%s (%s) ", name, sntp.toString().c_str());
} else {
Serial.printf("%s ", sntp.toString().c_str());
}
Serial.printf("IPv6: %s Reachability: %o\n",
sntp.isV6() ? "Yes" : "No",
sntp_getreachability(i));
}
}
Serial.println();
// subsecond synchronisation
gettimeofday(&tv, nullptr);
time_t sec = tv.tv_sec;
do {
gettimeofday(&tv, nullptr);
Serial.printf("time(): %u gettimeofday(): %u.%06u",
(uint32_t)time(nullptr),
(uint32_t)tv.tv_sec, (uint32_t)tv.tv_usec);
if (tv.tv_sec == sec) {
Serial.println(" second unchanged");
} else {
Serial.println(" <-- second changed");
}
delay(50);
} while (tv.tv_sec == sec);
Serial.println();
}
void time_is_set_scheduled() {
// everything is allowed in this function
if (time_machine_days == 0) {
time_machine_running = !time_machine_running;
}
// time machine demo
if (time_machine_running) {
if (time_machine_days == 0)
Serial.printf("---- settimeofday() has been called - possibly from SNTP\n"
" (starting time machine demo to show libc's automatic DST handling)\n\n");
now = time(nullptr);
const tm* tm = localtime(&now);
Serial.printf("future=%3ddays: DST=%s - ",
time_machine_days,
tm->tm_isdst ? "true " : "false");
Serial.print(ctime(&now));
gettimeofday(&tv, nullptr);
constexpr int days = 30;
time_machine_days += days;
if (time_machine_days > 360) {
tv.tv_sec -= (time_machine_days - days) * 60 * 60 * 24;
time_machine_days = 0;
} else {
tv.tv_sec += days * 60 * 60 * 24;
}
settimeofday(&tv, nullptr);
} else {
showTime();
}
}
void setup() {
Serial.begin(115200);
Serial.println("\nStarting...\n");
// setup RTC time
// it will be used until NTP server will send us real current time
time_t rtc = RTC_UTC_TEST;
timeval tv = { rtc, 0 };
settimeofday(&tv, nullptr);
// install callback - called when settimeofday is called (by SNTP or us)
// once enabled (by DHCP), SNTP is updated every hour
settimeofday_cb(time_is_set_scheduled);
// NTP servers may be overriden by your DHCP server for a more local one
// (see below)
// ----> Here is the ONLY ONE LINE needed in your sketch
configTime(MYTZ, "pool.ntp.org");
// Here is the ONLY ONE LINE needed in your sketch <----
// pick a value from TZ.h (search for this file in your filesystem) for MYTZ
// former configTime is still valid, here is the call for 7 hours to the west
// with an enabled 30mn DST
//configTime(7 * 3600, 3600 / 2, "pool.ntp.org");
// OPTIONAL: disable obtaining SNTP servers from DHCP
//sntp_servermode_dhcp(0); // 0: disable obtaining SNTP servers from DHCP (enabled by default)
// start network
WiFi.persistent(false);
WiFi.mode(WIFI_STA);
WiFi.begin(STASSID, STAPSK);
// don't wait for network, observe time changing
// when NTP timestamp is received
Serial.printf("Time is currently set by a constant:\n");
showTime();
}
void loop() {
if (showTimeNow) {
showTime();
}
}