Time et RTC

Warning

A la différence de la Pyboard, la classe RTC n'est pas implémentée sur la Pi pico (02/2021)

Ce que l'on va faire ici

Ici, nous allons voir comment utiliser le RTC de la carte Pi pico.

La classe RTC ne semble pas implémentée (Février 2021). Par contre, il est possible, via un "work around" que je propose ici, de synchroniser l'heure du pc de programmation et l'heure de la carte Pi pico qui restera à l'heure tant qu'elle ne sera pas mise hors tension (une alimentation par batterie sera nécessaire si l'USB doit être débranché) . C'est pas forcément l'idéal, mais j'ai pas trouvé mieux. Un datalogging horodaté sera alors possible.

L'autre option serait l'ajout d'un petit module RTC avec sa pile qui serait lu par le Pico pi.

Voir ici :

https://www.raspberrypi.org/forums/viewtopic.php?t=301502

Par contre, le module utime fournit la fonction time() qui renvoie le nombre de seconde depuis la mise sous tension par rapport à une date de référence qui a l'air d'être le 01/01/2021 pour le Pi Pico.

>>> import utime
>>> dir(utime)
['__class__', '__name__', 'gmtime', 'localtime', 'mktime', 'sleep', 'sleep_ms', 'sleep_us', 'ticks_add', 'ticks_cpu', 'ticks_diff', 'ticks_ms', 'ticks_us', 'time', 'time_ns']
>>> utime.time()
1609473198
>>> utime.localtime(utime.time())
(2021, 1, 1, 3, 54, 52, 4, 1)

D'autre part :

>>> utime.mktime((2021, 1, 1, 0, 0, 0, 0, 0))
1609459200

Tout à l'air de se passer comme si cette date était la date par défaut. Il faudrait donc simplement flasher avec le code une valeur appelée deltaCurrentTime

Dès qu'on met sous tension, on utime.time() qui vaut : 1609459200 En fait, ce qu'il faudrait, c'est un enregistrement simultané de heure courante pico et heure courante pc-1609459200(2021/01/01/ 00:00:00) +3600(décalage horaire) au moment de la programmation. On peut imaginer mettre ces 2 valeurs dans un fichier par exemple. Ou récupérer celle du pico juste avant de le programmer. Et on fait alors :

>>> utime.localtime(utime.time()+5678403-2704)
(2021, 3, 7, 17, 22, 34, 6, 66)

Si dans le script Python de programmation, on fait :

import pyboard
pyb=pyboard.Pyboard('/dev/ttyACM0', 115200) # definit un objet Pyboard correspondant à la carte
pyb.enter_raw_repl() # note : il faut stopper le port série au préalable à ce moment là... 
ret=pyb.exec("""import utime
print(utime.time())
""")

print(ret)

Ce qui donne :

b'1609463088\r\n'

Retrancher également -1609459200 à cette valeur :

delta_pico=int(ret)-1609459200

Ensuite, sortir du mode raw_repl :

pyb.exit_raw_repl() # sortie du mode repl_raw

ou y rester le temps de programmer la suite... à savoir récupérer le delta entre 1/1/2021 à 0:00 et le pc :

import time
delta_pc=int(time.time())-1609459200+3600 # 3600 = 1 heure de décalage
Out[4]: 5672769

Ensuite, il faut ajouter les 2 valeurs au code Micropython sous forme de variable

Et l'heure courante sera calculable à tout moment en faisant :

import utime
utime.localtime(utime.time()+delta_pc-delta_pico)

Il faut au moins une synchro entre les 2 au même moment ce qui peut aussi se faire manuellement en faisant simultanément dans un python pc et micropython repl :

import utime
utime.time()-1609459200

et sur le pc :

import time
int(time.time())-1609459200+3600 # 3600 = 1 heure de décalage

Une fois qu'on a la valeur pc et la pico, on fait sur le pico :

utime.localtime(utime.time()+delta_pc-delta_pico)

par exemple :

utime.localtime(utime.time()+5680247-4564) 

Il en résulte :

(2021, 3, 7, 18, 0, 26, 6, 66)

Tant que le pico ne sera pas éteint, çà sera bon. La manip est à recommencer si on éteint le pico. L'autre option c'est que çà soit fait automatiquement quand on programme (une option RTC à cocher quelque part dans IDE ? ) Et ou un petit script d'automatisation de la manip... qui donnera la valeur à utiliser pour RTC qui est en fait la différence des différences obtenues entre pico et pc.

Au final, il suffit de calculer au moins une fois la différence des 2 différences et on a une valeur pour avoir la RTC à partir de utime.time(). Un utilitaire pourrai très bien faire çà et une fois fait on ajouterai même manuellement la valeur dans le code pour la correction RTC.

ATTENTION

Bien que l'on parle de RTC (Horloge Temps Réel), celle-ci se réinitialise et repasse à une valeur par défaut (1er Janvier 2014 dans mon cas) dès que la carte est mise hors tension. Par contre, un reset ne réinitialise pas la RTC.

Note

RTC de la pyboard suppose une initialisation : je vous propose ici un petit script qui permet de le faire à partir du à partir duquel on programme la carte.

Une alternative possible est l'accès à un serveur ntp si la carte a un accès réseau. Une autre alternative est de récupérer l'heure à partir d'un module GPS utilisé avec la carte si on est dans ce cas.

============ Version Pyboard ==========

Ressources utiles

Classe RTC

Le module pyboard dispose d'une classe RTC qui donne accès à l'horloge temps réel de la carte. La doc est ici : http://docs.micropython.org/en/latest/pyboard/library/pyb.RTC.html

Module time

Micropython intègre également une version allégée du module time, module généraliste qui donne accès aux informations de temps du système. Voir la doc ici :

Exemple

Voici un petit script qui teste çà :

import pyb
import time


# sur la pyboard, on dispose de RTC qui permet mémorisation date une fois réglé et tant que alim. 

rtc=pyb.RTC() # création objet RTC

# utilisation des fonctions de l'objet RTC
print (rtc.datetime()) # (year, month, day, weekday, hours, minutes, seconds, subseconds)

#rtc.datetime((2017,9,22,4,18,39,4,0))
#print(rtc.datetime())

while True :
    #print (str(rtc.datetime()[4]),':',str(rtc.datetime()[5]),':',str(rtc.datetime()[6]))) # affiche hh:mm:ss 

    # pour affichage avec 0 devant nombre<10
    print ("%02d" % rtc.datetime()[4],':',"%02d" % rtc.datetime()[5],':',"%02d" % rtc.datetime()[6] ) # affiche hh:mm:ss 

    pyb.delay(1000)

### Option 2 : le module time fournit des fonctions "générales" concernant le temps mais ne permet pas de régler date/heure
print (time.localtime())

Mettre à jour automatiquement l'heure de la pyboard à partir du système

Trouvant assez peu pratique le fait de devoir fixer manuellement, j'ai eu envie de pouvoir mettre facilement la pyboard à l'heure du système sur lequel on travaille.

C'est ici qu'intervient le fameux script pyboard.py : ce script que l'on utilise pour envoyer un script depuis le système vers la carte, permet en fait à partir d'un code Python exécuté sur le système d'envoyer des instructions à l'interpréteur micropython. C'est tout simplement "énorme" cette possibilité...

Bref, du coup ici, j'ai écrit un code Python "classique" exécuté sur le système qui utilise le module datetime pour obtenir l'heure courante du système et l'utilise pour configurer la RTC de la carte avec la valeur obtenue... That's it !

Et Geany est ici notre ami car il permet de configurer 2 commande construction différentes : il suffit donc ici d'en définir une pour Python3 et une pour micropython. Ici, on utilisera la commande Python3 du coup.

ATTENTION : CE CODE EST UN CODE PYTHON CLASSIQUE, pas un code micropython

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# script pour initialiser la RTC de la pyboard - à exécuter en Python 3
# par X. HINAULT - 2017 - www.mon-fablab.fr 

import pyboard 


from datetime import datetime

print(datetime.now())

# construction de la chaine initialisation datetime à partir système
#(year, month, day, weekday, hours, minutes, seconds, subseconds) 
dt=(str(datetime.now().year)+','
+str(datetime.now().month)+','
+str(datetime.now().day)+','
+str(datetime.now().weekday())+','
+str(datetime.now().hour)+','
+str(datetime.now().minute)+','
+str(datetime.now().second)+','
+str(0)
)

print ('Date : ' + dt)
# voir aussi https://pypi.python.org/pypi/ntplib/

pyb = pyboard.Pyboard('/dev/ttyACM3') # port de connexion 

pyb.enter_raw_repl()

""" # test
pyb.exec('from upyduino import *') # exec_ pour python2
pyb.exec('pinMode(0,OUTPUT)')
pyb.exec('digitalWrite(0, HIGH)')
"""

pyb.exec('import pyb') # exec
pyb.exec('rtc=pyb.RTC()') # exec
pyb.exec('rtc.datetime(('+dt+'))') # exec -dt est un tuple



pyb.exit_raw_repl()

Note

Ce principe d'accès à l'interpréteur micropython à partir de Python système est en fait un mécanisme assez général qui sera intéressant à chaque fois que l'on aura besoin d'automatiser des tâches sur la carte micropython.