Articles - Logiciel & scripts

Suivi consommation électrique compteur EDF Linky (Partie 2)

  |   3529  |   Poster commentaire  |  Logiciel & scripts
Après la mise en place du Raspi les problèmes surviennent rapidement. LE gros souci : il ne devient plus accessible via SSH sur son adresse IP au bout d'une heure ou le lendemain, un délai aléatoire. Hum bizarre car il répond au ping. Ce qui signifie que le Raspi n'a pas décroché du Wi-Fi. Par contre impossible d'initier une connexion SSH. Il se trouve qu'un jour je suis arrivé à temps pour comprendre :



Le processus SSH n'a plus de mémoire pour se forker (générer un autre processus à partir de lui-même) et n'arrive donc pas à gérer les arrivants sur le port 22. Ici je suis arrivé presque à temps, dans la capture d'écran c'est cette fois le processus bash qui n'arrive pas à lancer les commandes. La RAM est saturée. Le message est limpide. Impossible de lancer une commande pour savoir ce qu'il se passe. Un reboot violent via alimentation/reset est malheureusement nécessaire dans ces cas là afin de reprendre la main. Au reboot j'ai vite compris :



Un script PHP se lance toutes les minutes pour relever la consommation instantanée, ce qui est normal, mais le script ne se termine jamais. Les processus PHP finissent ainsi par s'empiler (00h57, 00h58, 00h59...) et saturer la mémoire au bout d'un moment.

Alors pourquoi le script ne se termine pas ? En fait il y a une petite faille dans le script PHP.



En ligne 7 on essaie d'ouvrir le device /dev/ttyS0.
En ligne 8 on vérifie que le device a pu être ouvert (création réussie d'un FileHandle), le cas d'erreur est ici bien géré. En cas de problème, si le périphérique est indisponible ou inexistant on termine l'exécution avec le message "<device> not found".
Le problème se situe à la ligne 9, une boucle lit ce qui arrive sur le port série, caractère par caractère, tant que le fanion de fin de trame (chr 2 - STX) n'arrive pas. Ceci afin de démarrer la vraie lecture uniquement à partir de la trame suivante qui elle sera complète. On ignore la trame "courante". Sauf que si rien n'arrive sur le port série, ce caractère n'est jamais trouvé et le script PHP se retrouve à attendre bêtement à l'infini un STX qui n'arrive jamais.

La solution de contournement consiste à placer un timeout sur la commande afin de limiter son temps d'exécution. Cela tombe bien puisqu'une commande existe sur linux pour cela : timeout.



Il n'y a qu'a demander à killer le process (signal n°9 = SIGKILL) au bout de 15 secondes. 15 secondes étant suffisantes pour que le Raspi ait le temps de lire une trame complète et de jouer sa requête INSERT sqlite. On peut éventuellement mettre 20, 30 voire 40 secondes. De ce fait, au pire dans ce cas, les données ne rentrent pas dans la base sqlite mais le système n'est pas pollué/contaminé.

Mais pourquoi cela arrive ? Et bien en effet à de multiples reprises j'ai pu constater l’absence de données arrivant sur le port série de manière aléatoire :



On a rien du tout, j'ai stoppé avec CTRL-C.

C'est quoi ce binz ? Au début je pensais à une connectique foireuse entre le Linky et le module PiTInfo de Charles. Mais au multimètre (je n'ai pas d'oscilloscope portable) ça fluctue bien sur la broche RXD du GPIO. Le problème n'est donc pas matériel, le signal arrive bien au Raspi. Mais alors qu'est-ce que c'est que ce bordel ? J'ai cherché sur le web. J'ai trouvé qu'il fallait se méfier de la vitesse du VPU et du CPU car elle avait une influence sur la bonne tenue de route du port UART intégré. En effet j'avais émis l'hypothèse qu'au bout d'un moment les fréquences devaient varier selon la charge du CPU et que donc, le port déraillait à cause de cela.

Par conséquent j'ai joué un peu avec le gouverneur selon les modes (powersave, performance, ondemand) via une commande jouée au boot via /etc/rc.local et donner une fréquence fixe au CPU. Bilan : idem. Rien sur port série 9 fois sur 10 au démarrage ou alors ça marche 1 heure et puis plus rien. En fait vous aurez beau descendre le VPU à 250Mhz ou utiliser n'importe quel rituel de sorcellerie, c'est exactement pareil. J'ai trouvé la réponse ici. La faute en est au Raspi lui-même. En résumé : le SOC Broadcom embarque deux ports/modules UART implémentés matériellement de manière différentes (pages 10 & 175), l'un intitulé "mini-uart" (fonctionne à base d'un logiciel qui émule) et l'autre nommé "PL011" (circuit matériel réel).



Le premier est une grosse daube :

Citation :
The second serial port you will see referred to as the “mini uart” and lives at /dev/ttyS0. It also calculates it’s bit timing’s from the CPU cores frequency and if the CPU is under heavy load it can corrupt the serial communications. Not good.


Citation :

Relevant differences between PL011 and mini UART
The mini UART has smaller FIFOs. Combined with the lack of flow control, this makes it more prone to losing characters at higher baudrates. It is also generally less capable than the PL011, mainly due to its baud rate link to the VPU clock speed.
The particular deficiencies of the mini UART compared to the PL011 are :
No break detection
No framing errors detection
No parity bit
No receive timeout interrupt
No DCD, DSR, DTR or RI signals


Dans le cas du Raspi Zero Wireless, j'avais désactivé la console et activé le module "mini-uart". C'est lui qui par défaut est relié aux broches du GPIO. Il est ainsi disponible sur /dev/ttyS0, c'est celui que j'ai utilisé au début. Le PL011 est lui utilisé par la puce Bluetooth par défaut, "disponible" sur /dev/ttyAMA0. Si on veut utiliser le PL011 plus costaud sur les broches du GPIO il faut les échanger (re-router) avec les directives overlay pi3-disable-bt & pi3-miniuart-bt. Une fois cela fait, il faut utiliser /dev/ttyAMA0 dans les scripts.



Et voilà fini le port série qui freeze quand ça lui chante et ne retourne plus de données. Ne pas hésiter aussi à placer une réinitialisation à chaque boot dans /etc/rc.local :

Code BASH :
stty -F /dev/ttyAMA0 1200 sane evenp parenb cs7 -crtscts