Coding : Une partie sur la programmation quelques astuces et réflexions.

Thermostat intelligent (ESP32)

Les thermostats classiques permettent de programmer des plages horaires pendant lesquelles le chauffage est en route. Par exemple, on peut définir un démarrage à 6h pour que la pièce soit chaud à 7h. Malheureusement, en fonction de la température extérieure, parfois il fera chaud à 6h30, et parfois il fera chaud à 7h30.

Ce thermostat permet d'adapter l'heure de démarrage en fonction de la vitesse de chauffe. On définit ainsi des horaires de présence au lieux de définir des horaires de chauffe.

Courbe de chauffe chaudière.

Par exemple, si la vitesse de chauffe est de 2°C par heure et qu'il fait 18°C. Il suffira de chauffer à 6h30 pour qu'il fasse 19°C à 7h. J'appelle cette vitesse pente, elle est exprimée en °C / h et est mise à jour à chaque chauffe.

Matériel

Je n'ai pas fait grand chose de ce côté là. Vincent m'a prêté le matériel et a fait quelques soudures. Et pour l'instant, j'ai tout monté sur une platine de prototypage.

  • ESP32-PICO-KIT V4
  • Sonde de température TMP175 (I2C)
  • Un relais de type SRD-05VDC-SL-C
  • LEDs, boutons poussoirs, etc

La base : les entrées/sorties

Tout est programmée en C avec la toolchain IDF de l'ESP32. J'ai essayé les différents éléments tout seul : une première sonde de température analogique, puis la sonde I2C, puis le relay, etc. Je me suis aussi familiarisé avec le wifi sur ESP32 et le serveur web.

Fonctionnement du régulateur

La chaudière est pilotée en tout ou rien. Lorsque le relais est passant, la chaudière chauffe, sinon elle s'arrête.

Ce thermostat implémente une hystérésis. C'est-à-dire que pour atteindre une consigne à 19°C, il va chauffer jusqu'à dépasser un peu la température (19.3°C par exemple). A la descente, il va attendre de dépasser la consigne (18.7°C par exemple) pour chauffer.

Fonctionnement de la prédiction

La prédiction à deux entrées : le booléen qui indique la chauffe et la température. Grâce à ces deux données, elle actualise la pente (en °C/h).

La prédiction agit au début et à la fin de la chauffe. C'est-à-dire lorsque chauffe passe à vrai, puis lorsqu'il passe à faux. Elle enregistre alors 2 points X1 et X2. Si la différence de température entre ces deux points est d'au moins 1 degré, elle calcule la pente. La pente est la différence des températures entre X1 et X2 divisée par la durée entre X1 et X2.

Pendant un période d'absence, le logiciel calcule le temps qu'il faudra pour atteindre la consigne. Cette durée dépend de la température actuelle et de la pente. Lorsque la durée jusqu'à la période de présence est inférieure à ce temps de chauffe, la consigne du régulateur est mise à jour pour atteindre la température de présence.

L'Architecture

Modules du thermostat qui adapte le temps de chauffe.

Le module Régulateur (controller/hysteresis.h) implémente l'hystérésis. Il pend en entrée la température actuelle et renvoie le booléen chauffe. Il est paramétré par une consigne.

Le module Prédiction (controller/estimator.h) reçoit en entrée la température actuelle et le temps (jour de la semaine, heure et minute) et renvoie la pente.

Enfin le module Gestion (le main dans thermostat.c) reçoit la température actuelle et définie la consigne en fonction de la pente et des horaires de présence.

Tout ces modules reposent sur une couche d'abstraction donnant accès au matériel (température, relais, bouton poussoir) et au serveur web (définition des endpoints). Un module stock aussi la configuration et les horaires sous forme d'un jour (lundi-dimanche), heure et minute.

Interface web

Page web du thermostat connecté.

Tout est très léger et sans cosmétique. Un endpoint permet d'accéder aux statistiques sur 24h (température, pente et chauffe).

Deux boutons poussoirs permettent de passer en mode présence ou absence.

Améliorations

  • Ajouter un écran LCD. Il pourrait même permettre de remplacer l'interface web.
  • Économie d'énergie : mettre l'ESP32 en veille entre chaque mesure.

Raspberry Pi : une chaine hifi radio Internet

Mini projet d'une demi-journée (ou plutôt 2h) : permettre d'écouter des radios Internet depuis le Raspberry Pi sans écran. J'ai utilisé une souris comme IHM. Le principe est simple : le programme lance cvlc avec un flux, l'appui sur un bouton de la souris change le flux. Le nom de la radio est annoncé avant la lecture.

#!/bin/bash
next()
{
        /home/pi/RadioPi/mouse
        while killall vlc; do
                echo "kill";
        done
}
while true; do
        echo "Jazz radio" | espeak
        sudo -u pi cvlc http://radio/flux.mp3&
        next
        echo "BBC Radio 1" | espeak
        sudo -u pi cvlc http://radio/flux.asx&
        next
done

La fonctionnement n'est pas très propre car cvlc ne nous offre pas de possibilité de le fermer autrement que par un kill. Le programme mouse rend la main dès qu'un bouton de la souris est appuyé.

Le programme est appelé dans rc.local par :

sudo -u pi /home/pi/RadioPi/radios.sh&

On note le sudo -u pi qui permet de lancer le script par l'utilisateur pi, car VLC ne peut pas être exécuté par le root.

Code source de mouse :

Lire la suite de Raspberry Pi : une chaine hifi radio Internet

Mes conseils de programmation

Je vais essayer de décrire dans ce documents quelques principes de base que j'applique en programmant. Pour trouver l'essentiel, il m'a fallu prendre du recul sur mes habitudes.

Le nom doit permettre de comprendre ce que fais la fonction ou la variable

Pour les fonctions, l'habitude et de mettre un verbe d'action dans le nom. Pour les plus courants on trouve :
récupère (get) : elle renvoie quelque chose (il n'y a aucune raison que dans son code elle modifie une quelconque variable !! sinon, lui trouver un autre nom)
modifie/ajoute/supprime (set/add/del) : modifie une valeur/une liste ou un tableau
On peut l'étendre à n'importe quel verbe d'action : tri, analyse, nettoie...

Si la fonction est dans un package, il peut parfois être pratique (en C, par exemple), de donner le nom du package aux fonctions. Par exemple : donnéesInit, donnéesReset, donnéesAjout...

Important : si on modifie le contenue d'une fonction, il faut penser aussi à mettre à jours son nom si son but change, ou au moins sa documentation.

Pour les tableau, utiliser le terme "tab" dans le nom est souvent assez pratique.

Documenter ses fonctions (toutes)

Description de la fonction
Paramètres : liste des paramètres avec l'utilité. Indiqué s'il sont modifiés.
Retour : ce qui est retourné.

Sur les fonctions ou procédures complexes, on peut ajouter les champs suivants : Requis : ce qui doit être fait avant l'appel. Par exemple : appel à "init" requis.
Garantie : ce que l'on assure après (par exemple, "le tableau T est trié ou vide")

Dans le cas où le champ requis a été utilisé, il est peut-être intéressant de placer une assertion en début de fonction, pour assurer que cela a été fait.

Être capable de dessiner sa structure de données

Prendre une feuille de papier et dessiner ses tableaux, ses listes chainées... Ce conseil est sans doute le plus "scolaire" que je puisse donner, mais il vous propulse instantanément au rang de serial coder, surtout dans les langages comme le C où les pointeurs rendent le code peu lisibles.

Apprendre à dessiner une structure de donnée
Il n'y a plus qu'à faire la correspondance. En C, le tableau deviendra [], les pointeurs, dessinés par des flèches, deviendront des étoiles...

Classer ses fonctions par package (même en C, avec les .h)

Permet de leur donner une logique globale. Cela facilite aussi la factorisation du code. Être capable de classer ses fonctions traduit le fait que l'on comprend l'architecture de son programme. Dans le meilleur des cas, il faut décrire quel seront les packages avant même de commencer à coder. Il est intéressant aussi de décrire les interactions entres les différents packages.
Nb. Pour la programmation objet (Java, C++), c'est encore plus vrai.

Éviter les effets de bords (modification de variables)

Il faut éviter de modifier des variables du programme depuis une fonction (mais c'est parfois indispensable ou juste plus lisible). Dans ce cas, on doit comprendre ce qui est modifié juste en lisant la documentation de la fonction et son nom.
Exemple (trivial), en lisant la documentation de la fonction int get_numéro(), on ne s'attends pas à ce qu'elle modifie une variable. On s’attend juste à ce qu'elle renvoie le numéro.

Pour les procédures c'est moins vrai : "l'effet de bord" est leur seul moyen d’interagir avec l'extérieur. Cependant, si elles modifient plusieurs variables, il faut se demander si le développeur s'y attend, juste en lisant la doc.

Appeler ses fonctions avant de les écrire

Cela permet de s'assurer qu'elle est utile avant de l'appeler et d'évaluer quels seront les paramètres. Parfois, j'aime même effectuer les appels de toutes mes fonctions, et les écrire ensuite. Ça peut être inutile, si vous savez exactement quoi coder.

En conclusion, nous voyons que la programmation nécessite une certaine rigueur : savoir à tout instant POURQUOI j'écris cette ligne. Le code est à destinations de machines, mais il doit surtout être lisible par des humains, c'est pourquoi il est important de le rendre compréhensible.

Du code, et encore du code

Si vous n'avez pas encore jeté un œil à la section Réalisations sachez que j'ai ajouté pas mal de réalisation durant cette année.

  • plxPermalinks : Un plugin PluXml permettant de configurer vos url à volonté.
  • Monôme2Monôme : une messagerie instantanée très simple en java (résultat d'un projet) (GNU GPL)
  • amowebCartographie : un logiciel de cartographie de valeurs compatible Google Earth (GNU GPL)
  • amowebMathParser : un parser d'expressions mathématiques en java (LGPL)

C'est disponible sur cette page.

Bash : Remplacer les caractères d'échappement HTML en caractères UTF-8

Voici un petit script bash permettant de remplacer, dans tous les fichiers d'un répertoire, les séquences d'échappement HTML par le caractère qu'elle représentent (UTF-8).
J'ai pris la liste des caractères d'échappement de theukwebdesigncompany.com.

Avant de l'exécuter, comprenez comment il fonctionne et sauvegardez vos fichiers, ça vous évitera de perdes des documents.
convhtml-utf8.sh.zip