Outils pour utilisateurs

Outils du site


issue204:micro-ci_micro-la

More fun with dates and time Greetings fellow Beings. Yet again, I come to you from an undisclosed location somewhere in time and space. Yes, I am a fan of all things Doctor Who, Star Trek, Star Wars, and other things. Anyway, last month we looked at the subject of time change from “standard” time and “daylight saving” time and some of the issues that come with that on a Microcontroller. I promised that we would continue that subject. So here we go with a reminder of some of the issues. First, the ntptime module, used to get the network time, has a small problem when you make too many calls to it. The server simply tells you to go away after a while and you have to start all over again. I also gave you a short snippet to use the portable version of ntptime from Peter Hinch. I also talked about the fact that there are two functions that provide the current time (once it’s set) named gmtime and localtime, and the fact that they both give GMT time. There is no timezone information handled by either of these functions. So let’s talk about some of the possible remedies available to us.

Plus de plaisir avec les dates et l'heure

Salut mes amis. Une fois de plus, je viens à vous depuis un endroit tenu secret, quelque part dans le temps et l'espace. Oui, je suis un fan de Doctor Who, de Star Trek, de Star Wars et d'autres choses encore.

Quoi qu'il en soit, le mois dernier, nous avons abordé le sujet du changement d'heure entre l'heure « standard » et l'heure « d'été » et certains des problèmes qui en découlent sur un microcontrôleur. J'ai promis de poursuivre ce sujet. C'est donc parti pour un rappel de certains problèmes.

Tout d'abord, le module ntptime, utilisé pour obtenir l'heure du réseau, a un petit problème lorsque vous faites trop d'appels. Au bout d'un moment, le serveur vous dit simplement de quitter et vous devez tout recommencer. Je vous ai également donné un petit extrait pour utiliser la version portable de ntptime de Peter Hinch.

J'ai aussi parlé du fait qu'il y a deux fonctions qui fournissent l'heure actuelle (une fois qu'elle est définie) appelées gmtime et localtime, et du fait qu'elles donnent toutes les deux l'heure GMT. Aucune de ces fonctions ne gère les informations relatives au fuseau horaire.

Parlons donc des remèdes possibles qui s'offrent à nous.

In my search for an easy solution, I came across the fact that the MicroPython group has been working on creating a large library of modules that are useful for programmers writing MicroPython programs. Many of them attempt to mirror standard libraries in the Python world. One of these modules is the datetime module. MicroPython has suffered from the lack of this being in the builds. Well, now, the wait is over (at least for the most part). By using the micropython-lib datetime module in our programs, we can, with a few modifications, use “normal” python code in our MicroPython programs. Of course you have to have the datetime module “installed” on your device. There are few ways of doing this. One is my preferred way of getting the entire source code package and copying the necessary modules onto my device. By doing this, I can make sure that any of the dependencies are available and I can examine the code to see how that programmer (or group of programmers) got their code to work. Also if there are any errors being thrown, I can track it down much quicker than relying on a library where I can’t see the source code. You can find the package at https://github.com/micropython/micropython-lib/tree/master and download the entire zip file. Unzip the package into a folder (I use my Downloads folder and unzip it there, since it has the folder already there for me). Once there, you can find the file in the /python-stdlib/datetime/ folder (named datetime.py)

Dans ma recherche d'une solution facile, je suis tombé sur le fait que le groupe MicroPython a travaillé à la création d'une grande bibliothèque de modules utiles pour les programmeurs qui écrivent des programmes en MicroPython. Beaucoup d'entre eux tentent de refléter les bibliothèques standard du monde Python. L'un de ces modules est le module datetime. MicroPython souffrait de l'absence de ce module dans les builds. Maintenant, l'attente est terminée (du moins en grande partie).

En utilisant le module datetime de micropython-lib dans nos programmes, nous pouvons, avec quelques modifications, utiliser du code python « normal » dans nos programmes MicroPython.

Bien sûr, il faut que le module datetime soit « installé » sur votre appareil. Il y a plusieurs façons de le faire. La première, que je préfère, consiste à obtenir l'ensemble du code source et à copier les modules nécessaires sur mon appareil. Ce faisant, je peux m'assurer que toutes les dépendances sont disponibles et je peux examiner le code pour voir comment le programmeur (ou le groupe de programmeurs) a fait fonctionner son code. De plus, si des erreurs sont générées, je peux les trouver beaucoup plus rapidement qu'en me fiant à une bibliothèque dont je ne peux pas voir le code source. Vous pouvez trouver le paquet à l'adresse https://github.com/micropython/micropython-lib/tree/master et télécharger le fichier zip complet. Décompressez le paquet dans un dossier (j'utilise mon dossier Téléchargements et je le décompresse là, puisqu'il contient déjà mon dossier). Une fois dans ce dossier, vous trouverez le fichier dans le dossier /python-stdlib/datetime/ (nommé datetime.py).

Copy the datetime.py to your Microcontroller device and put it into the /lib folder or, if you don’t have it, either create the folder and place it there, or just drop it into your main folder on the device. (It’s better to put it into the /lib folder.) The other way, which is a bit easier but only provides you the compressed mpy file, is to use mip. Here is a link to using mip: https://www.tomshardware.com/how-to/raspberry-pi-pico-micropython-mip. Anyway, I haven’t had a chance to fully explore all the functions available, but for this month, we’ll use the datetime library to get the datetime.now function. You will call it like this : my_timezone = timezone(timedelta(hours=10)) current_time = datetime.datetime.now(my_timezone) Of course, you need to import the library before you can call it, but we’ll see that in this month’s first project. If you are a “regular” Python programmer, you will recognize the second line, which uses the datetime.datetime.now() method.

Copiez le fichier datetime.py sur votre microcontrôleur et placez-le dans le dossier /lib, ou, si vous ne l'avez pas, créez le dossier et placez-le dedans, ou placez-le simplement dans votre dossier principal sur le microcontrôleur. (Il est préférable de le placer dans le dossier /lib).

L'autre moyen, qui est un peu plus facile, mais qui ne vous fournit que le fichier mpy compressé, est d'utiliser mip. Voici un lien vers l'utilisation de mip : https://www.tomshardware.com/how-to/raspberry-pi-pico-micropython-mip.

Quoi qu'il en soit, je n'ai pas eu l'occasion d'explorer pleinement toutes les fonctions disponibles, mais pour ce mois-ci, nous utiliserons la bibliothèque datetime pour obtenir la fonction datetime.now. Vous l'appellerez comme ceci :

my_timezone = timezone(timedelta(hours=10))

current_time = datetime.datetime.now(my_timezone)

Bien entendu, vous devez importer la bibliothèque avant de pouvoir l'appeler, mais nous verrons cela dans le premier projet de ce mois.

Si vous êtes un programmeur Python « normal », vous reconnaîtrez la deuxième ligne, qui utilise la méthode datetime.datetime.now().

So, for this month’s main project, we’ll connect to the Internet (be sure you’re using a RPi Pico-W), use Peter Hinch’s portable NTPTime module, get the network time, set the Real Time clock on the Pico-W, and then start printing the time in the REPL once every 10 seconds. I’ve named the program ‘timetestFCM1.py’. Make sure that you have the datetime.py or datetime.mpy file either in your main device’s folder or in the lib folder. All of the other libraries needed are “standard” libraries, except for Peter’s portable NTPtime library. I’ve got that in the repository listed at the end of this article. The Code First, we’ll need a secret.py file. This will hold your SSID and your network password. I use this to make sure that if I ever share a project that uses networking, that my network information isn’t exposed in the code. (It’s in the repository, so all you need to do is to make sure you edit it once it’s on your device). It looks like this… # secret.py # ========================== SSID = {Your Network Name Here} PASSWORD = {Your Network Password Here} Really simple huh?

Ainsi, pour le projet principal de ce mois, nous allons nous connecter à Internet (assurez-vous que vous utilisez un RPi Pico-W), utiliser le module portable NTPTime de Peter Hinch, obtenir l'heure du réseau, régler l'horloge temps réel sur le Pico-W et ensuite commencer à imprimer l'heure dans le REPL une fois toutes les 10 secondes. J'ai nommé le programme « timetestFCM1.py ». Assurez-vous que vous avez le fichier datetime.py ou datetime.mpy dans le dossier de votre périphérique principal ou dans le dossier lib. Toutes les autres bibliothèques nécessaires sont des bibliothèques « standard », à l'exception de la bibliothèque portable NTPtime de Peter. Elle se trouve dans le dépôt listé à la fin de cet article.

Le code

Tout d'abord, nous avons besoin d'un fichier secret.py. Il contiendra votre SSID et votre mot de passe réseau. Je l'utilise pour m'assurer que si je partage un projet qui utilise le réseau, mes informations réseau ne sont pas exposées dans le code. (Il est dans le dépôt, donc tout ce que vous avez à faire est de vous assurer que vous l'éditez une fois qu'il est sur votre appareil). Cela ressemble à ceci :

# secret.py #

SSID = {Votre nom de réseau ici} PASSWORD = {votre mot de passe réseau ici}

Vraiment simple, hein ?

Moving on. Now we’ll need Peter’s portable NTPTime routine. That’s also in the repository saved as port_ntptime.py. Make sure that’s also on your device. Now (top right) we’ll start digging into the timetestFCM1.py project. First the imports. It will seem to be a REALLY big number of imports, but it’s not much. Next comes the connectNetwork function. This is a fairly straight forward function that I reuse often. First, I set up the onboard LED of the Pico (name it “led”), then make sure it’s off. Next I start to set up the network modes, send in the SSID and Password to the wlan object and loop until we get connected. Once we are connected to our local network, we turn the onboard LED on (next page, top right). Next we have the settime2 function. It’s very similar to the one defined in the NTPTime module, but this one will return a 0 if, for some reason, it can’t set the time correctly. We get the time and date tuple by sending the number of seconds since our EPOCH (from the network time server) to utime.gmtime and then set the software real time clock with that value. If everything worked correctly we return a True, otherwise return a False (next page, top left).

Passons à autre chose. Nous allons maintenant avoir besoin de la routine portable NTPTime de Peter. Elle se trouve également dans le dépôt, enregistrée sous le nom de port_ntptime.py. Assurez-vous qu'elle se trouve également sur votre appareil.

Maintenant (en haut à droite) nous allons commencer à plonger dans le projet timetestFCM1.py. Tout d'abord, les importations. Cela va vous sembler un nombre VRAIMENT important d'importations, mais ce n'est pas grand chose.

Ensuite vient la fonction connectNetwork. C'est une fonction assez simple que je réutilise souvent. Tout d'abord, je configure la LED embarquée du Pico (nommez-la « led »), puis je m'assure qu'elle est éteinte. Ensuite, je commence à configurer les modes réseau, j'envoie le SSID et le mot de passe à l'objet wlan et je boucle jusqu'à ce que nous soyons connectés. Une fois que nous sommes connectés à notre réseau local, nous allumons la LED embarquée (page suivante, en haut à droite).

Ensuite, nous avons la fonction settime2. Elle est très similaire à celle définie dans le module NTPTime, mais celle-ci renvoie un 0 si, pour une raison quelconque, elle ne peut pas régler l'heure correctement. Nous obtenons le tuple date et heure en envoyant le nombre de secondes écoulées depuis notre EPOCH (depuis le serveur de temps réseau) à utime.gmtime, puis nous réglons l'horloge logicielle en temps réel avec cette valeur. Si tout a fonctionné correctement, nous renvoyons un True, sinon nous renvoyons un False (page suivante, en haut à gauche).

Finally, we get to begin to play with the datetime module we went to “so much trouble” to get. First we need to set a value for our timezone, which in my case is -5 hours from GMT. Once we go through the time change again, this will be a -6 until the next time change. Then we take that and use it to seed the datetime.datetime.now() function, which returns a time string like this… 2024-04-07 02:49:10-05:00 We’ll get into formatting that next month. That’s it for all of our support functions. Now we have the main routine. This makes calls to the various functions that we’ve already discussed. FIrst, I define the two timezone offsets used here where I live. Cst is 6 hours behind GMT (starting in the Fall) and cdt is 5 hours behind (Starting in the Spring). I multiply the number of hours by 3600 (The number of seconds in an hour) and since we are behind GMT, I use a negative number.

Enfin, nous pouvons commencer à jouer avec le module datetime que nous nous sommes donné « tant de mal » à obtenir.

Tout d'abord, nous devons définir une valeur pour notre fuseau horaire, qui dans mon cas est de -5 heures par rapport à l'heure GMT. Une fois que nous aurons changé d'heure, ce sera -6 jusqu'au prochain changement d'heure. Ensuite, nous prenons cette valeur et nous l'utilisons pour ensemencer la fonction datetime.datetime.now(), qui renvoie une chaîne de temps comme celle-ci :

2024-04-07 02:49:10-05:00

Nous aborderons le formatage le mois prochain.

C'est tout pour nos fonctions de support. Nous avons maintenant la routine principale. Celle-ci appelle les différentes fonctions dont nous avons déjà parlé.

Tout d'abord, je définis les deux décalages de fuseau horaire utilisés ici, là où je vis. Cst est 6 heures derrière GMT (à partir de l'automne) et cdt est 5 heures derrière (à partir du printemps). Je multiplie le nombre d'heures par 3 600 (le nombre de secondes dans une heure) et, comme nous sommes en retard sur l'heure GMT, j'utilise un nombre négatif.

cst=-6*3600 cdt=-5*3600 Next I get the Epoch which is where my device bases the number of seconds from in order to “decode” the value sent from the NTPServer. The Pico uses January 1, 1970. Other devices use January 1, 2000. But that actual date is January 1, 1900. Knowing this can help if there are any errors. After that, I get the time that the device thinks the time is. EPOCH = time.gmtime(0)[0] print(f“{EPOCH=}”) rtc=machine.RTC() dti=rtc.datetime() print(f“{dti=}”) Now, I threw in a quick check to make sure this program was running on a Pico-W. If not, well, there is no need to continue on, since we can’t connect to a network. We simply call sys.exit() if it isn’t a Pico-W. # Check to see if the Pico has network which=GetWhichPico() if which == False: sys.exit()

cst=-6*3600 cdt=-5*3600

Ensuite, j'obtiens l'Epoch, c'est-à-dire l'instant sur lequel mon appareil base le nombre de secondes pour « décoder » la valeur envoyée par le serveur NTPS. Le Pico utilise le 1er janvier 1970. D'autres appareils utilisent le 1er janvier 2000. Mais la date réelle est le 1er janvier 1900. Le fait de savoir cela peut aider en cas d'erreur. Ensuite, j'obtiens l'heure que l'appareil pense être la bonne.

EPOCH = time.gmtime(0)[0] print(f« {EPOCH=} ») rtc=machine.RTC() dti=rtc.datetime() print(f« {dti=} »)

Maintenant, j'ai ajouté une vérification rapide pour m'assurer que ce programme fonctionnait sur un Pico-W. Si ce n'est pas le cas, il n'est pas nécessaire de continuer, puisque nous ne pouvons pas nous connecter à un réseau. Nous appelons simplement sys.exit() s'il ne s'agit pas d'un Pico-W.

# Check to see if the Pico has network which=GetWhichPico() if which == False:

  sys.exit()
  

Now we call the connectNetwork function. # Connect to the network connectNetwork() Now that we are connected, we can try to get the time (in seconds) from the NTP server. This is fairly simple. Once we are in the loop, we make a call to Peter’s portable ntptime function. It will either return the time value from the NTP server or a 0. If the value is greater than zero, we do a quick garbage collection (to get rid of any unneeded stuff), and call the settime2 function with the proper timezone offset. If the call to settime2 is successful, we set the loop variable to False, otherwise we sleep for 2 seconds (next page, top left). At this point, we can pretty much safely assume we got the Network time. Now all we need to do is print the time.gmtime and time.local time to the REPL, then print the return from showMyTime (bottom left). If you are old enough to remember “Y2K”, you’ll be either happy, or scared, to know that in 2038, there will be another one. Hopefully, we will be more ready for that issue than we were back in 1999. We’ll talk about that next month. The repository for this month is located at https://github.com/gregwa1953/MTMT204 . Until next time, as always; stay safe, healthy, positive and creative!

Nous appelons maintenant la fonction connectNetwork.

# Connect to the network connectNetwork()

Maintenant que nous sommes connectés, nous pouvons essayer d'obtenir l'heure (en secondes) du serveur NTP. C'est assez simple. Une fois que nous sommes dans la boucle, nous faisons un appel à la fonction portable ntptime de Peter. Il donnera, soit la valeur de l'heure du serveur NTP, soit un 0. Si la valeur est supérieure à zéro, nous procédons à un tri rapide des déchets (pour nous débarrasser de tout ce qui n'est pas nécessaire) et nous appelons la fonction settime2 avec le bon décalage de fuseau horaire. Si l'appel à settime2 est réussi, nous mettons la variable de boucle à False, sinon nous dormons pendant 2 secondes (page suivante, en haut à gauche).

À ce stade, nous pouvons supposer que nous avons obtenu l'heure du réseau. Maintenant, tout ce qu'il nous reste à faire est d'imprimer les temps time.gmtime et time.local sur le REPL, puis d'imprimer le retour de showMyTime (en bas à gauche).

Si vous êtes assez âgé pour vous souvenir du passage à l'an 2000, vous serez heureux ou effrayé d'apprendre qu'en 2038, il y aura un autre passage à l'an 2000. Espérons que nous serons mieux préparés qu'en 1999. Nous en reparlerons le mois prochain.

Le dépôt de ce mois-ci se trouve à l'adresse suivante : https://github.com/gregwa1953/MTMT204.

Jusqu'à la prochaine fois, comme toujours, restez en sécurité, en bonne santé, positifs et créatifs !

Encart p 43 en haut à droite, lignes noires Now we can define our internal functions. First the PI function GetWhichPico, which is useful if you have both types of the RPi Pico. Maintenant, nous pouvons définir nos fonctions internes. D'abord la fonction PI GetWhichPico, qui est utile si vous avez deux types de RPi Pico.

Encart p 45 en bas à gauche, lignes noires Finally, we can enter our forever loop, printing the device’s time every 10 seconds. Enfin, nous pouvons entrer dans notre boucle sans fin, avec impression de l'horodatage du dispositif toutes les 10 secondes.

That’s it. Here is the REPL output… C'est tout. Voici la sortie du REPL :

issue204/micro-ci_micro-la.txt · Dernière modification : 2024/05/01 11:41 de andre_domenech