Outils pour utilisateurs

Outils du site


issue203:micro-ci_micro-la

Ceci est une ancienne révision du document !


Greetings fellow Beings. I hope you have already read my How-To Python in the Real World #149 in this issue, because that is the actual beginning of this article. Consider this the second half of it. So if not, please jump back to the contents page (usually page #2) and read that first. I’ll wait. Ready now? GREAT! We’re talking about Time change from Standard Time to Daylight Saving time and back to Standard time. Why is that important? Well, if you have a Microcontroller that is dealing with time sensitive logging or needs to do something at a particular time, your device needs to know what the actual correct time is at all times. You might be thinking to yourself that this isn’t a big deal, especially if you use Thonny as your IDE for programming your device. Have you ever noticed that when you get the current time on your device is correct? That’s because, by default, Thonny sets the time on the device and more times than not, it is also set, again by default, to use the local time from the computer you are running Thonny on. That is a good thing, isn’t it? Well, yes. Most of the time.

Let’s say that you have a program that you are going to test that requires the time and date to be set. You test it under Thonny and it runs just fine. Now, you save the program to the device as main.py so that it will run when the device is powered on. Now you close Thonny and unplug then replug in the device. Assuming the device and your program have some sort of display showing the time, the time will display “00:00:00”. Even if you’ve connected to the network, unless you have connected to an NTP server (time server), the time is not set. That’s why having Thonny auto set the time and date isn’t always a good idea. How do we keep that from happening? There are four options that can be turned on or off by clicking in the small squares (Radiobuttons in the Tkinter world). Click on the two center options (‘Synchronize device’s real time clock’ and ‘Use local time in the real time clock’) to turn off the options. Then restart Thonny. Originally, I had planned on a full project including code for this article. However, there have been many stumbling blocks keeping me from doing this. Not the least of which is a problem in the ntptime function of MicroPython. It seems that this is across all the types of Microcontrollers, not just the RPi-PicoW. So, my fallback plan is to explain how it SHOULD be done, then try to lay out a plan on how it should be implemented (at least until things get settled in the MicroPython world) and give you the project code next month.

NTPTIME The MicroPython firmware has a module called ntptime that, assuming your device supports internet communication, will go out to a special Internet address and ask for the time. HOWEVER, the time that is returned is not what you would think it is. It is a very large integer that specifies the number of seconds since midnight Jan 1, 1900, and then an offset is applied to that to adjust it to either the number of seconds from Jan 1, 1970 or Jan 1, 2000. This is known as the EPOCH. This depends on the Microcontroller you are using. You really shouldn’t have to worry about the deep-down internal calculations, since the ntptime module should deal with that for you. What you DO need to worry about is that there are two times that are kept on the system. One is gmtime and one is localtime. As you might guess, gmtime is UTC (Universal Coordinated Time) or Greenwich Mean Time. This number never gets Daylight Saving Time applied to it. Now you would think that localtime would have at least the timezone applied to it and at best the DST value applied to it. As John Belushi used to say… “BUT NOOOOOOOOOOOOOOOOOOO”. In the world of MicroPython (at least currently), gmtime and localtime are both the same. This has caused a large discussion that you can follow if you wish at https://github.com/orgs/micropython/discussions/12378. As I said just above, time zones are not currently implemented in MicroPython. To make matters a bit crazier, there are two versions of gmtime and localtime. There is one set in the time module and one in the utime module. Currently they all point to the same values.

So, if you are interested in getting the correct time for wherever your Microcontroller is located at that moment, you have to play a bunch of games. So, since there is no consensus on this subject, let’s look at the games we can play to get the values that we want/need, at least for now. The VERY simplest solution at this point is to write your own localtime function that will take the timezone information and return a proper localtime. However, you really don’t need to do that, since I found one for you. User MrEbbinghaus posted a quick solution on August 31, 2023 at https://github.com/orgs/micropython/discussions/11173#discussioncomment-6876888 a one-line solution (not counting comments) that works pretty well. I copied the small function (since I already have time imported in my code) and named it “localtime2”. That way, there is no naming conflict. Now, you would think that the TZ_OFFSET value should be simply the hour offset, either positive or negative based on your offset. Here where I live, “Standard” time is 6 hours behind UTC and “Daylight Saving Time” is 5 hours behind UTC. So I should use -6 as the TZ_OFFSET during “Standard” time and -5 as the offset during “Daylight Saving Time”, right?

NOOOOOOOOOO You have to convert that hour offset to seconds first. WHAT? Yep. Now, we all know that there are 60 seconds in a minute and 60 minutes in an hour, so that would be 60*60*-6 (-21600) or 60*60*-5 (-18000). THOSE are the numbers you need to send into the “replacement” localtime function . To make matters worse, the ntptime module is NOT very user friendly. Nor is the NTP Timeserver. Many times, the ntptime server doesn’t return anything at all and sometimes it returns a value that will crash your program. When that happens, the “current thinking” is that the NTP server is sending you a KoD or “Kiss-’o-Death” packet that basically says you have made too many calls in too short a time. According to the RFC4430: Best Practices document for the NTP servers: “A client MUST NOT under any conditions use a poll interval less than 15 seconds.”

Not something that is known by just everyone! But, ok. How can we handle this better than a try/Except loop? It seems that Peter Hinch (who I’ve mentioned more than once in my MTMT articles) has created a ‘portable’ NTP module of his own. You can find it at https://github.com/peterhinch/micropython-samples/blob/master/ntptime/ntptime.py . I would copy the code and place it in a module all on its own with a name like “port_ntptime”. The nice thing about Peter’s module, is that not only can you pass a timezone value (again in seconds) it also will return either the proper time value (in seconds) OR a 0 if the NTP Server failed to respond in time. There’s a discussion of this at https://github.com/peterhinch/micropython-samples/blob/master/README.md#414-ntp-time and a larger discussion at https://forum.micropython.org/viewtopic.php?t=12726.

Unfortunately, Peters module doesn’t actually set the time, it just gets the time. So, here is how you can use his code and still get the time set properly: trials=10 while trials > 0: lt=port_ntptime.time() Lt is the return value. Check to see if it is 0 or not. If it is, then call the ntptime.settime() function. If not, sleep for 15 seconds and then try again (top right). The ntptime.settime() function will force the corrected time into utime.gmtime. Again, we have the issue that gmtime and localtime are the same, so you should remember when you want to use localtime, use the localtime2 function. Hopefully, this will take the problems away from my code I want to present next month and allow me to get it tested completely without it crashing. Until next time, as always; stay safe, healthy, positive and creative!

issue203/micro-ci_micro-la.1712038148.txt.gz · Dernière modification : 2024/04/02 08:09 de d52fr