Hi,
I need help to better understand the mechanism responsible for adjusting the time in my country. Every six months there is a shift of the hour backwards or forwards, in connection with these I would like to implement a mechanism responsible for updating the time correctly.
My main problem is that I do not understand the mechanism of how the time update works when there is a situation where there is no connection to a WiFi network or an external connection (no internet outside the local network). In my application, the ESP8266 is responsible for controlling the gate and must maintain continuous loop processing to continuously check the status of the photocells (whether the beam has been broken - if so, the circuit must stop the gate operation for safety reasons). Therefore, I can't allow the chip to have any delays caused, for example, by a failed WiFi connection (for example, the ESP8266 chip thinks it has a WiFi connection, but it was interrupted and if a GET request was sent it would cause about 0.2 delay).
So will it be safe to use a time update mechanism, on a chip that needs to check the continuity of signals? How will the library react if the ESP8266 sends a query to the NTP server and receives no response? Is there a risk that using this mechanism will cause minor delays of, say, 0.2s or 0.1s?
I still have an idea to involve an additional ESP8266 module that will send the current date to the main module every 1 second, is this a good idea? I know for sure that receiving requests generates almost no delay.
Code:
/*
NTP TZ DST - bare minimum
NetWork Time Protocol - Time Zone - Daylight Saving Time
Our target for this MINI sketch is:
- get the SNTP request running
- set the timezone
- (implicit) respect daylight saving time
- how to "read" time to be printed to Serial.Monitor
This example is a stripped down version of the NTP-TZ-DST (v2)
And works for ESP8266 core 2.7.4 and 3.0.2
by noiasca
2020-09-22
*/
#ifndef STASSID
#define STASSID "your-ssid" // set your SSID
#define STAPSK "your-password" // set your wifi password
#endif
/* Configuration of NTP */
#define MY_NTP_SERVER "at.pool.ntp.org"
#define MY_TZ "CET-1CEST,M3.5.0/02,M10.5.0/03"
/* Necessary Includes */
#include <ESP8266WiFi.h> // we need wifi to get internet access
#include <time.h> // time() ctime()
/* Globals */
time_t now; // this is the epoch
tm tm; // the structure tm holds time information in a more convenient way
void showTime() {
time(&now); // read the current time
localtime_r(&now, &tm); // update the structure tm with the current time
Serial.print("year:");
Serial.print(tm.tm_year + 1900); // years since 1900
Serial.print("\tmonth:");
Serial.print(tm.tm_mon + 1); // January = 0 (!)
Serial.print("\tday:");
Serial.print(tm.tm_mday); // day of month
Serial.print("\thour:");
Serial.print(tm.tm_hour); // hours since midnight 0-23
Serial.print("\tmin:");
Serial.print(tm.tm_min); // minutes after the hour 0-59
Serial.print("\tsec:");
Serial.print(tm.tm_sec); // seconds after the minute 0-61*
Serial.print("\twday");
Serial.print(tm.tm_wday); // days since Sunday 0-6
if (tm.tm_isdst == 1) // Daylight Saving Time flag
Serial.print("\tDST");
else
Serial.print("\tstandard");
Serial.println();
}
void setup() {
Serial.begin(115200);
Serial.println("\nNTP TZ DST - bare minimum");
configTime(MY_TZ, MY_NTP_SERVER); // --> Here is the IMPORTANT ONE LINER needed in your sketch!
// start network
WiFi.persistent(false);
WiFi.mode(WIFI_STA);
WiFi.begin(STASSID, STAPSK);
while (WiFi.status() != WL_CONNECTED) {
delay(200);
Serial.print ( "." );
}
Serial.println("\nWiFi connected");
// by default, the NTP will be started after 60 secs
}
void loop() {
showTime();
delay(1000); // dirty delay
}
In safety-critical situation, the answer is "never." You require a extremely accurate off-board time module and set it annually on battery change when a human is involved at the gate.
This should be rather straightforward with an external chrono. Study example code for how annual DST works; Example code from Adafruit is well written.
The RTC will still need to adjust to summer or winter time. There is code for this over the internet, check this library for example
Text is in French but I’m sure Google translate will help. You’ll need to adjust the library for your time zone / when 1h is added or removed if you are not in the EU
Not sure if this is applicable for ESP8266, but for ESP32, I'd set the external RTC to UTC and never change it. Same with the ESP's internal RTC.
You'd set the TZ environmental variable as appropriate for the location ... there are lots of references online for this. Then, on initialization, you'd set the internal RTC to the UTC time reported by the external RTC by calling settimeofday().
After that you'd get local time (automatically converted for time zone and DST) by simply calling localtime().
For periodically truing up the internal RTC with the external RTC, you'd call adjtime(). This gives a smooth adjustment and guarantees that readings of the internal RTC are monotonic.
All of the above are standard POSIX functions and the technique will work without a network connection or NTP. Of course, the external RTC must be properly set to begin with and must be continuously powered.
I don't understand this. If you have an external RTC, why would you bother with the internal one? As I see it, the only reason for having the internal RTC is to update it with NTP and pass that on to the external RTC. I don't know if the internal RTC is actually necessary to do this.
What function does knowing the time serve you in your program?
If you were to upgrade from an ESP8266 to an ESP32 you wouldn't have this problem since the chip is dual-core. One core (0) performs all the Wifi functions so you can do whatever you want on core 1. You don't even get any of those nasty watchdog timeouts from using delays like you do when an 8266 is connected to Wifi.
Querying the external RTC every time you want to know the time is inefficient. They typically connect via I2C which is glacially slow compared to the processor’s speed. It would spend the majority of its time waiting for the transaction to complete rather than doing useful work. Getting the time from internal resources is much faster.
Using the internal RTC provides POSIX’s the automatic time zone and DST conversion based on the TZ string. You don’t have to resort to hacky methods of determining when the time changes and / or manually adjusting the external RTC.
You could also conceive of a hybrid synchronization scheme that adjusts the internal RTC using NTP as primary and synchs to the external RTC as backup when there's no network connection. In either case, the internal RTC would be synched and used to provide the time when required by the application code.
If your ESP8266 delay will absolutely trip the watchdog time if called for too long. There is only one core and it has to perform WiFi functions on a strict schedule and if it is blocked from doing so, the watchdog timer will trip. Trust me, I've had it happen many, MANY times.
Sorry I don’t believe it’s the case for the delay function
Agree it’s the case if you do an active wait loop without calling yield() or one of the « system » function that calls yield for you. delayMicroseconds() will also bite if you wait for too long but then what’s the point of using the microsecond version if you want to wait a long time ?
The simplest way would be to test it but I don’t have an esp8266 at hand for the moment
If I remember correctly the software watchdog kicks in after 3.2 seconds so we should know pretty quickly (the hardware watchdog should trigger as well in less than 10s - I think I’ve read it’s 8s or so)
This does not depend on the movement of the gate, and the important thing is to read the states of the photocells. For example, someone may go out on foot and the photocell must register this to close the gate. Such an action is very, very fast.
Thanks for the advice, but I would prefer to work it out without additional external parts, since I also no longer have free ports. On the other hand, I still thought if it is not possible to send the time information data from the external ESP8266, and this will be rather the simplest method.
Could you elaborate on that? Why wouldn't they be? I will admit that this is the first time I have heard this.
Mainly, this is used for the logging system of any information that happened on the ESP8266. Therefore, it is important that this information be attached to the execution times.
I thought about it, however, the board is extensive and I have no intention of rewiring all connections (pins).
Adding the complexity of an extra processor and dealing with processor-to-processor communications is rarely the best solution. In most cases it's an ugly hack. I suspect that's the case here too.
@misiekd stay on one microcontroller. If you run out of pins, use port expanders.
One Microcontroller: One Problem --> The sketch.
Two Microcontrollers: Three problems --> Two sketches and the communication between the two controllers!
Yes, it is not so nice solution, but can be very easy. I mean send a GET request with date and the main microcontroller only receive it and save to variable.
That's all it takes, and most importantly, I still don't expose the main microcontroller to sending information outside of it, meaning I don't expose it to situations where the WiFi connection is not available or has been broken or other waits.
The date is saved only if it is received immediately, there is no unnecessary waiting.
I2C is a bus - you can connect several I2C devices to the same I2C bus
if the i2c pins are blocked by other (non i2c) devices use other pins for I2C and define the I2C pins with Wire.begin(sdaPin,sclPin)
if the i2c pins are blocked by other (non i2c) devices use the default pins and put the current device which blocks pin 4 and 5 to pins of the port expander
...