1

Librairie Universelle Pour la Téléinformation

Pourquoi ?

Travaillant sur différents projets utilisant la téléinformation dans des environnements assez variés (Arduino, Raspberry, Spark Core, ESP8266, …) j’en avais un peu marre de devoir faire des copier/coller de mon code original écrit il y a quelques années pour mon programme teleinfo. De plus chaque fois j’ai eu besoin de m’adapter aux environnements et faire des modifications. je me suis donc retrouvé avec trop de versions. Thibault m’en a remis une couche récemment avec sa propre version pour le programmateur à fils pilotes WIFI que nous utilisons 😉

Fonctions nécessaires

J’ai donc décidé de me lancer dans l’adaptation d’une libraire qui me servira partout et qui se doit d’être un tant soit peu “intelligente” et surtout fonctionnant avec tous les type de contrats EdF sans devoir faire des modifications sauvages d’étiquettes à la volée ou autres.

Cette librairie doit être optimisée et complètement dynamique c’est à dire qu’à aucun moment les valeurs des étiquettes reçues ne sont codées “en dur”. Au fur et à mesure que les données arrivent elles sont mémorisées et un espace mémoire qui leur est alloué dynamiquement. Ensuite les valeurs sont mises à jour au fur et à mesure de la réception. Ceci permet de rendre cette librairie directement compatible avec tous les types de contrats (Heures pleines/creuses, BBR, Tempo, ….)

Elle doit aussi fournir un système de callback afin de vous avertir quand il se passe un événement d’intéressant.

Développement

Format

La librairie est réalisé dans le format classique de librairies de type Arduino, elle fonctionnera donc directement depuis l’IDE de cet environnement pour les Arduino ainsi que pour le super nouveau chip Wifi très en vogue l’ESP8266 grâce à son inclusion dans l’IDE Arduino. Pour les autres cibles (Spark Core, Photon, Raspberry, …) il faudra peut être copier les fichiers ailleurs afin de les intégrer dans chaque environnement. Je reviendrais sur ce point quand j’aurai avancé sur le sujet (intégration dans remora par exemple)

Son code doit être simple est concis afin de pouvoir tourner sur des cible réduites en taille de code et en mémoire.

Mémorisation

Les données de téléinformation reçues sont vérifiées et ensuite stockées dans une liste chaînée. Je ne vais pas faire un cours la dessus, mais c’est un peu comme un tableau mais totalement dynamique. Je vous conseille d’aller voir ce cours dédié si vous êtes intéressés. En tous cas au niveau optimisation y’a pas mieux.

Le format d’une entrée de la liste pour cette librairie est le suivant :

  • Un pointeur sur l’objet suivant (ou NULL si c’est le dernier objet de la liste)
  • la valeur de la checksum de l’étiquette
  • des flags indiquant par exemple si cette étiquette est “nouvelle” (juste reçue et donc créée) ou vient d’être “mise à jour” dans la dernière trame reçue .
  • le nom de l’étiquette (via un pointeur dans l’objet)
  • la valeur de l’étiquette (via un pointeur dans l’objet)

Cette structure est déclarée dans le fichier include LibTeleinfo.h

Vous avez donc compris que la taille d’un élément dépendra de la longueur de l’étiquette ainsi que de sa valeur. Mais ne vous inquiétez pas, vous n’aurez pas à vous soucier de la gestion cette liste de manière générale, la librairie se charge de tout, ce qui vous intéresse c’est de pouvoir naviguer dans ses éléments.

Fonctions

La puissance de cette librairie provient de la possibilité de lui définir des callback, c’est à dire d’appeler vos propres fonctions à réception d’événements. J’ai défini les 4 événements suivants:

  • Réception d’un signal ADPS : dépassement de consommation de contrat
  • Réception d’une ligne d’étiquette : une étiquette+valeur+checksum ok vient d’être reçue (ex PAPP=250)
  • Trame modifiée :  une trame complète a été reçue (EOT) mais des données de cette trame ont été modifiées depuis la dernière trame reçue.
  • Trame identique : une trame complète a été reçue(EOT)  mais elle est identique à la dernière  trame reçue (généralement on ne fait rien).

Lors de l’appel de ces callback (qui sont les vôtres je le rappelle) par la librairie vous recevrez en paramètre les informations nécessaires, par exemple pour ADPS ce sera le numéro de la phase comme suit :

  • 0 : Phase unique (Monophasé)
  • 1 : Phase 1 si triphasé
  • 2 : Phase 2 si triphasé
  • 3 : Phase 2 si triphasé

Les déclarations des callback sont faites dans le fichier include LibTeleinfo.h

Utilisation

Connexions

Dans les explications suivantes, je vais utiliser un Arduino. Dans mon cas (ou si votre device ne possède qu’un seul port série) j’utilise une instance softserial afin de ne pas utiliser la vraie liaison série (TX/RX) que je garde pour le debug à 115200. D’où la connexion sur D3 (mais vous pouvez la changer). La téléinfo est donc reçue sur cette patte D3 qui recevra le signal RDX du schéma suivant :

Montage de base

RXD sur la patte D3 de l’arduino

Pour des informations détaillées et des explications complètes sur ce schéma vous pouvez vous référer à cet article dédié

Attention : La librairie softserial fonctionne parfaitement, mais est très gourmande en ressources d’interruption et elle perturbe très fortement les fonctions système telles que millis(), donc ne vous attendez pas à un fonctionnement normal de millis() mais plutôt à un fonctionnement retardé. J’avais mis un ticker toutes les secondes, et, parfois çà me mettait bien 1s, et d’autres, je devais attendre parfois jusqu’a 4s avant de voir mon ticker incrémenté !!!

Ce n’est pas super gênant, mais gardez le en mémoire si besoin, çà vous  évitera de vous prendre la tête quand çà ne fonctionnera pas comme vous le pensez.

Exemple

Pour utiliser la libraire dans votre programme c’est assez simple il faut inclure les fichiers de la libraire comme n’importe quelle autre libraire, l’instancier, l’initialiser et enfin l’appeler dans votre main loop.

Donc un programme minimal pourrait ressembler à cela :

On déclare les fichiers d’inclusion, on instancie la librairie, on configure softserial de nom Serial1 sur D3/RX (D4 TX ne sera pas utilisé). Dans l’init on initialise la librairie et enfin le main loop.

Le main loop regarde si un caractère est présent sur la liaison série préalablement déclarée et l’envoi à la libraire téléinfo pour son traitement. Je n’ai volontairement pas inclus l’objet série dans la librairie pour un portage plus facile. En effet, sur un Raspberry Pi tournant sous linux je suis pas certain qu’on puisse avoir un objet “Serial”. Donc pour se prémunir de tout problème, on passe juste les caractères reçus 1 à 1 à la librairie, et elle se débrouille toute seule. Ce n’est même pas obligé d’être synchrone.

Mais que fait alors ce programme ? et bien pour vous rien, il s’occupe juste de la gestion de réception/contrôle des données puis stocke et met à jour la liste chaînée. Voilà un squelette auquel tout programme utilisant cette librairie doit ressembler.

Affichage à réception d’étiquette

L’exemple précédent était juste une mise en bouche, on passe la vitesse supérieure, et nous allons utiliser une callback événementielle pour afficher les valeurs reçues. Cette callback est appelé à chaque réception une ligne d’étiquette valide (checksum OK), soit par exemple :

PAPP=00140 &

Pour réaliser cela, c’est très simple il faut commencer par créer une fonction qui va réaliser le traitement souhaité (ici juste l’affichage), cette fonction reçoit de la librairie un pointeur sur l’objet de la liste chaînée correspondant ainsi que des flags indiquant ce qu’il s’est passé :

Cette fonction affiche un pseudo compteur de seconde. Puis si la donnée reçue est nouvelle ou mise à jour grâce au flag fourni en paramètre . Et enfin elle affiche l’étiquette ainsi que sa valeur.

Bien entendu il faut dire à la librairie d’affecter notre callback à la fonction précédemment créée, ce qui rajoute à notre exemple précédent une ligne de code dans le setup()    tinfo.attachData(DataCallback);

Ce qui donne :

La sortie finale sur la serial nous donne :

Clignotement à réception de trame

L’exemple précédent montrait l’utilisation à réception des lignes d’étiquettes, ce n’est pas ce que je recommande, je préconise plus un traitement à réception d’une trame complète. Voici comment utiliser les callback adéquates. Dans cet exemple nous reprendrons juste les fonctions de l’exemple précédent sur lequel nous allons :

  • ajouter un clignotement court sur réception d’une trame identique à la précédente
  • ajouter un clignotement long pour une trame dont les données on été modifiées
  • afficher le signal ADPS si présent

on ajoute donc nos 3 callbacks :

Puis on les déclare dans le setup pour les “attacher”

Et enfin J’ai modifié le main avec un compteur de millis() pour le clignotement de la led

Et la sortie Serie nous donne maintenant :

Nous avons vu comment fonctionnent les callback, maintenant je vais vous montrer comment naviguer dans la liste chaînée afin de récupérer les données en réception de trame.

Envoi des données modifiés au format JSON

Pour ce faire, nous allons envoyer sur la serial les données au format JSON (oui oui, une lubie totalement arbitraire, fruit du hasard, et ce n’est absolument pas pour les faire digérer par node-red comme par exemple ici).

je ne vais pas détailler ce qui a déjà été vu mais me focaliser sur ce qui est nouveau :

  • Ajout d’un compteur de secondes avec le timer1 pour pallier au shift indroduit par sofwareserial sur millis();
  • A chaque trame modifiée, envoi sur la Serial en JSON uniquement les valeurs modifiées et non pas toute la trame
  • Transformer les données de type numérique en numérique JSON (enlever les 0 inutiles et les guillemets dans le format JSON pour indiquer à la cible que ce sont des valeurs numériques)
  • toute les minutes, envoi d’une trame complète (toutes les valeurs) avec en plus une donnée _UPTIME pour le fun.

Je préfixe les données “maison” par _ pour un traitement ultérieur afin de les différencier des véritables données reçues par la Téléinfo.

Les callback de l’exemple précédent on été modifiées pour appeler une fonction qui va se charger de la transformation en JSON des données de la liste chaînée (sauf sur ADPS ou on le fait en direct). Une variable globale fulldata  sera positionnée par le main loop toutes les 60 secondes pour indiquer que le prochain envoi sera de type “trame complète”.

Rien de bien sorcier donc, voyons maintenant la fonction sendJSON qui navigue dans la liste chaînée.  Comme nous recevons un pointeur sur notre liste chaînée, nous allons naviguer dans tous les éléments, et seuls ceux étant indiqués comme “modifiés” seront envoyés.

Si le paramètre d’entré all  vaut true , alors TOUS les élément seront envoyés.

Et enfin ce que donne la sortie série, que du JSON avec bien les _UPTIME toutes les 60s et la trame complète.

Conclusion

Voilà pour une présentation rapide de la librairie, je vous invite à aller voir sur le repo github dédié, j’ai posté pas mal d’exemples bien documentés donc vous devriez y trouver toutes les informations nécessaires.

J’ai même fait un exemple tournant sur Raspberry Pi avec un dongle Micro Teleinfo ou une carte ArduiPi.

Ensuite ?

Ensuite, et bien c’est assez simple, je travaille actuellement sur un module téléinfo Wifi à base d’ESP8266, tout le hard est validé sur breadboard et j’ai bien avancé au niveau code. Il reste pas mal de boulot, genre Bootstrap, AJAX/JQuery. D’ailleurs si une personne est motivée et maîtrise parfaitement ces technologies, je suis preneur car je suis un peu charrette en ce moment.

Je vais lancer la 1ere série de PCB pour avoir çà d’ici la fin de l’été (et de mes vacances), mais comme vous êtes arrivé en fin d’article pour vous récompenser de votre lecture assidue, voici comment se présente l’interface vue depuis le navigateur Internet de cette carte nommé Wifinfo.

Wifinfo Information Systeme

Wifinfo Information Systeme

Wifinfo Données de Téléinformation

Wifinfo Données de Téléinformation

Je vais publier les schémas de cette carte très rapidement 😉

Réferences

  • le repo github contenant la librairie ainsi que les exemples
  • la spécification ERDF concernant la téléinformation
  • tous les articles connexes de mon blog
  • J’ai créé une catégorie dédiée à cette librairie sur la communauté téléinfo pour toute question relative à son support ou son utilisation.
Charles

Charles

Comments on this topic in community Forums.