ESP Easy Mega dispose déjà d’une liste impressionnante de plugins pour les capteurs et actionneurs les plus courants. Si vous n’avez pas trouvé votre bonheur dans les plugins existants ou si vous disposez d’un code Arduino déjà fonctionnel, nous allons voir comment faire pour le transformer en plugin.
Tutoriel actualisé le 15 mai 2020
Nous allons adapter le code Arduino d’une caméra thermique AMG8833 pour le transformer en plugin ESP Easy Mega. Le plugin fera une mesure par seconde et calculera la température moyenne (64 mesures), la température minimum et la température maximale relevée par la caméra thermique.
Installer Visual Studio Code et le plugin PlatformIO
Il est possible de développer un plugin à l’aide de l’IDE Arduino. Cependant, le code source du firmware ESP Easy Mega étant développé avec PlatformIO, ce sera beaucoup plus facile d’opter pour la même solution. PlatformIO est disponible sous la forme d’un plugin pour de nombreux éditeur de code (Atom, CLion, CodeBlocks, Eclipse, Emacs, NetBeans, Qt Creator, Sublime Text, Vim, Visual Studio, VSCode). Les fonctionnalités sont identiques quelque soit l’éditeur. J’ai opté pour Visual Studio Code de Microsoft, un éditeur rapide, gratuit et multi-plateforme. A vous de choisir !
Si vous ne connaissez pas encore PlatformIO, je vous conseille de commencer par lire ce tutoriel.
Code Arduino utilisé pour l’imageur thermique AMG8833
Spécifications techniques du AMG8833
Mesure de température à matrice carrée constituée de 64 points (8×8 pixels)
- Tension d’utilisation : 3.3V ou 5V
- Précision de la température : ± 2,5°C ou ±4,5°F (typique)
- Distance de détection humaine : 7m maximum
- Différence de température équivalente au bruit est de 0,05°C à 1 Hz
- Angle de mesure : 60°
- Consommation de courant : 4,5mA (mode normal), 0,2mA (mode sommeil), 0,8mA (mode veille)
- Interface I2C
- Fréquence d’images : de 1 ou 10 images par seconde
- Temps pour activer la communication après la configuration : 50ms puis 15ms
- Notices techniques Panasonic
Il existe 4 versions du capteur. Les différences étant situés au niveau de la tension d’alimentation (3V3 ou 5V) et le facteur de gain (faible ou élevé). Dans le grand public, on trouve surtout la version AMG8833/AMG8831. La seconde référence indiquée sur le breakout (carte fille) est la référence de l’ancienne génération. Cela n’a aucun impact sur le fonctionnement. Panasonic n’indique pas clairement les changements d’une génération à l’autre.
Code source
Pour le code Arduino, j’ai simplifié l’exemple installé avec la librairie Adafruit. Ce code récupère une matrice de températures chaque seconde et calcul le minimum, le maximum et la température moyenne des 64 points. Rien de bien compliqué mais c’est assez pour l’exemple.
#include <Wire.h>
#include <Adafruit_AMG88xx.h>
Adafruit_AMG88xx amg;
float pixels[AMG88xx_PIXEL_ARRAY_SIZE];
void setup() {
Serial.begin(9600);
Serial.println(F("AMG88xx pixels"));
bool status;
status = amg.begin();
if (!status) {
Serial.println("Could not find a valid AMG88xx sensor, check wiring!");
while (1);
}
Serial.println("-- Begin AMG88xx Test --");
Serial.println();
delay(100); // let sensor boot up - attend le démarrage de capteur
}
void loop() {
//read all the pixels - lit tous les pixels du capteur
amg.readPixels(pixels);
// Variables temporaires - Temp. var.
float sum = 0;
float mini = 80;
float maxi = 0;
float average = 0;
for(int i=1; i<=AMG88xx_PIXEL_ARRAY_SIZE; i++){
if ( pixels[i-1] < mini ) mini = pixels[i-1]; // trouve la température mini - find min temp.
if ( pixels[i-1] > maxi ) maxi = pixels[i-1]; // trouve la température maxi - find max. temp.
sum += pixels[i-1]; // additionne toutes les températures - add all temp.
}
average = sum/AMG88xx_PIXEL_ARRAY_SIZE; // calcul la température moyenne de la matrice - calculate matrix average
// Imprime les résultats - print results
Serial.print("Temp. mini: ");Serial.print(mini);
Serial.print(" Temp. maxi: ");Serial.print(maxi);
Serial.print(" Average: ");Serial.print(average);Serial.println();
delay(1000); // Attend 1 seconde - wait a second
}
Matériel utilisé
Pour ce tutoriel, nous aurons simplement besoin d’un module ESP8266. N’importe quel NodeMCU ferra l’affaire.
Circuit
La communication avec l’AMG8833 se faisant via le bus I2C, le circuit est rudimentaire.
AMG8833 | ESP8266 |
SDA | D2 |
SCL | D1 |
GND | GND |
3V | 3V3 |
Les étapes à suivre pour développer un plugin pour ESP Easy Mega
Disposer d’un code Arduino fonctionnel. Ce n’est pas une obligation, mais c’est plus facile de convertir du code Arduino déjà fonctionnel que de devoir le mettre au point dans un plugin ESP Easy. Un problème à la fois !
Adapter le code Arduino en plugin ESP Easy
Déclarer le plugin
Compiler, téléverser et tester !
Convertir le code Arduino en plugin ESP Easy
Un modèle (template) nommé _Pxxx_PluginTemplate.ino est disponible à la racine du dossier src (source). C’est un modèle général, voici une version minimale
Permet d’inclure le plugin lors de la compilation (nous verrons plus bas comment faire)
#ifdef USES_P129
#define PLUGIN_129
#define PLUGIN_ID_129 129
#define PLUGIN_NAME_129 "Nom du plugin"
#define PLUGIN_VALUENAME1_129 "Libellé de la première valeur retournée par le plugin"
boolean Plugin_129(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
switch (function)
{
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_129;
Device[deviceCount].Type = DEVICE_TYPE_I2C;
Device[deviceCount].VType = SENSOR_TYPE_TRIPLE; // Domoticz type, see controlleremu.py
Device[deviceCount].PullUpOption = false;
Device[deviceCount].InverseLogicOption = false;
Device[deviceCount].FormulaOption = true;
Device[deviceCount].DecimalsOnly = true;
Device[deviceCount].ValueCount = 3;
Device[deviceCount].SendDataOption = true;
Device[deviceCount].TimerOption = true;
Device[deviceCount].GlobalSyncOption = true;
break;
}
case PLUGIN_GET_DEVICENAME:
{
string = F(PLUGIN_NAME_129);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_129));
break;
}
case PLUGIN_WEBFORM_LOAD:
{
}
case PLUGIN_WEBFORM_SAVE:
{
success = true;
break;
}
case PLUGIN_INIT:
{
break;
}
case PLUGIN_ONCE_A_SECOND:
{
}
}
return success;
}
#endif
❶ Juste après le #ifdef USES_PXXX, déclarez les librairies au début du code,
❷ Après la déclaration des constantes (DEFINE), déclarez les variables temporaires et initialisez les objets. Ici par exemple, on aura besoin de créer un objet pour communiquer avec le capteur AMG88xx et d’un tableau de 64 floats pour stocker les températures.
Adafruit_AMG88xx amg;
float pixels[AMG88xx_PIXEL_ARRAY_SIZE];
❸ Insérer enfin le contenu de la boucle loop dans le cas (case) PLUGIN_ONCE_A_SECOND pour que la température soit actualisée chaque seconde.
❹ Il y a quelques petites adaptations à faire dans le code :
- Remplacer les Serial.print par addLog(LOG_LEVEL_INFO, message_a_envoyer)
- Publier chaque valeur dans le UserVar. La position dans le tableau doit correspondre à la déclaration des libellés ce qui donne
- UserVar[event->BaseVarIndex + 0] = mini; pour la température mini.
- UserVar[event->BaseVarIndex + 1] = maxi; pour la température maxi.
- UserVar[event->BaseVarIndex + 2] = average; pour la valeur moyenne
- Supprimer le delay(1000). Le délai d’attente est maintenant géré par ESP Easy
Code Arduino initial
amg.readPixels(pixels);
float sum = 0;
float mini = 80;
float maxi = 0;
float average = 0;
for(int i=1; i<=AMG88xx_PIXEL_ARRAY_SIZE; i++){
if ( pixels[i-1] < mini ) mini = pixels[i-1]; if ( pixels[i-1] > maxi ) maxi = pixels[i-1];
sum += pixels[i-1];
}
average = sum/AMG88xx_PIXEL_ARRAY_SIZE;
Serial.print("Temp. mini: ");Serial.print(mini);
Serial.print(" Temp. maxi: ");Serial.print(maxi);
Serial.print(" Average: ");Serial.print(average);Serial.println();
//delay a second
delay(1000);
Code ESP Easy
amg.readPixels(pixels);
float sum = 0;
float mini = 80;
float maxi = 0;
float average = 0;
for(int i=1; i<=AMG88xx_PIXEL_ARRAY_SIZE; i++){
if ( pixels[i-1] < mini ) mini = pixels[i-1]; if ( pixels[i-1] > maxi ) maxi = pixels[i-1];
sum += pixels[i-1];
}
average = sum/AMG88xx_PIXEL_ARRAY_SIZE;
String log = F("AMG88xx : Temp. mini: ");
log += mini;
UserVar[event->BaseVarIndex + 0] = mini;
addLog(LOG_LEVEL_INFO, log);
log = F("AMG88xx : Temp. maxi: ");
log += maxi;
UserVar[event->BaseVarIndex + 1] = maxi;
addLog(LOG_LEVEL_INFO, log);
log = F("AMG88xx : Temp. avg ");
log += average;
UserVar[event->BaseVarIndex + 2] = average;
addLog(LOG_LEVEL_INFO, log);
Déclarer le nouveau plugin au compilateur
Maintenant que le code du plugin est prêt, il nous reste à le déclarer pour qu’il soit intégré lors de la compilation. Tout ce passe dans le fichier define_plugin_sets.h situé à la racine du dossier src.
Ce fichier permet de configurer les plugins à embarquer en fonction de la version compilée (stable / dev / test). Inutile de trop chercher, placez directement votre plugin dans la version stable en créant une nouvelle clé
#define USES_P129
Il n’y a rien de plus à faire ! Enregistrez le fichier
Compiler et téléverser le firmware ESP Easy Mega avec le plugin
Tout est prêt, il ne reste plus qu’à téléverser le firmware comme d’habitude avec PlatformIO
Depuis le menu PIO ➀, cliquez sur l’environnement qui vous intéresse ➁ pour afficher les fonctions de PIO. Cliquez sur Build pour compiler ou sur Upload pour compiler et téléverser ➂
Ou depuis le Terminal, exécutez la commande suivante en remplaçant <version> par la version désirée
platformio run --target upload --environment <version>
Vérifier que le plugin a bien été embarqué
Comme d’habitude, connectez-vous à l’interface d’administration d’ESP Easy Mega puis ajoutez un nouveau device.
Dans la liste de sélection, vous devriez trouver votre plugin
Et l’interface utilisateur de notre plugin !
Description détaillées des méthodes
Si tout est claire, voici des explications un peu plus détaillées du fonctionnement du plugin
Entête du plugin ESP Easy : include et #define
Dans l’entête du plugin, nous peut définir les librairies à inclure éventuellement
#include <SPI.h>
Ensuite, tous les modules doivent être identifiés par une série de clés. Il est important de bien attribué l’ID choisi à toutes les clés pour que le plugin fonctionne.
#define PLUGIN_129 | Identifiant du plugin |
#define PLUGIN_ID_129 129 | L’ID du plugin |
#define PLUGIN_NAME_129 “Indoor Air Quality – MQ135” | Le libellé qui sera affiché dans la liste de choix |
#define PLUGIN_VALUENAME1_129 “Temp. mini“ | Variable de sortie du plugin. Libellé affiché entre guillemets |
#define PLUGIN_VALUENAME2_129 “Temp. maxi”
|
La seconde sortie numérique du plugin |
#define PLUGIN_VALUENAME3_129 “Average”
|
Et ainsi de suite |
Fonction Plugin_XXX
Le plugin est encapsulé dans une fonction. Cette fonction prend plusieurs paramètres qu’il suffit de tester. Le moteur d’ESP Easy lance à intervalle régulier les plugins associés aux Devices configurés.
boolean Plugin_129(byte function, struct EventStruct *event, String& string)
{
// contient le code du plugin
}
Par convention, on nomme le plugin par Plugin_ID_DU_PLUGIN
Plusieurs méthodes sont obligatoires. Chaque méthode est appelée par un switch / case à intervalle régulier. Une méthode renvoi éventuellement une valeur
Méthode PLUGIN_DEVICE_ADD
La première méthode (PLUGIN_DEVICE_ADD) permet de définir les paramètres qui sont communs à tous les Devices
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_129;
Device[deviceCount].Type = DEVICE_TYPE_I2C; // Device I2C, voir plus bas
Device[deviceCount].VType = SENSOR_TYPE_TRIPLE; // Voir plus bas
Device[deviceCount].PullUpOption = false;
Device[deviceCount].InverseLogicOption = false;
Device[deviceCount].FormulaOption = true; // Autorise la formule
Device[deviceCount].DecimalsOnly = true; // Valeur décimale
Device[deviceCount].ValueCount = 3;
Device[deviceCount].SendDataOption = true;
Device[deviceCount].TimerOption = true;
Device[deviceCount].GlobalSyncOption = true;
break;
}
Les principaux paramètres sont
- Type : le type de matériel connecté. On peut choisir parmi
- DEVICE_TYPE_SINGLE (1) : connecté sur une entrée numérique (datapin)
- DEVICE_TYPE_I2C (2) : l’appareil communique avec l’ESP8266 / ESP32 via le bus I2C
- DEVICE_TYPE_ANALOG 3 : on utilise le convertisseur A/N de l’ESP8266 (Pin TOUT, par exemple A0)
- DEVICE_TYPE_DUAL (4) : appareil connecté à l’aide de 2 entrée numériques
- DEVICE_TYPE_DUMMY (99) : appareil logique sans connexion physique (Dummy device). Lisez cet article pour en savoir plus
- VType. correspond au type de renvoyer par le plugin suivant le format Domoticz. Tous les types sont listés dans le fichier controlleremu.py
- SENSOR_TYPE_SINGLE (1) : un sortie
- SENSOR_TYPE_TEMP_HUM (2) : 2 sorties de type température & humidité (DHT11 ou DHT22)
- SENSOR_TYPE_TEMP_BARO (3) : 2 sorties de type température & pression atmosphérique (BMP180)
- SENSOR_TYPE_TEMP_HUM_BARO (4) : 3 sorties, température, humidité, pression atmosphérique (BME280)
- SENSOR_TYPE_DUAL (5) : générique, 2 sorties
- SENSOR_TYPE_TRIPLE (6) : générique, 3 sorties
- SENSOR_TYPE_SWITCH (10) : 2 états, interrupteur
- SENSOR_TYPE_DIMMER (11) : 1 sortie variateur
- SENSOR_TYPE_LONG (20) : 1 sortie
- ValueCount : nombre de variable de sortie. Ce compteur doit correspondre au nombre de clé PLUGIN_VALUENAME1_xxx
PLUGIN_GET_DEVICENAME
Cette méthode renvoi le nom du Device.
PLUGIN_GET_DEVICEVALUENAMES
Cette méthode est appelée à l’ouverture de la page de configuration du module. Elle permet d’ajouter une nouvelle ligne pour chaque variable de sortie du plugin. Utilisez le formalisme imposé sans oublier d’incrémenter l’indice du tableau TaskDeviceValueNames[X] et de la variable PLUGIN_VALUENAMEX_129
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_129));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_129));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[2], PSTR(PLUGIN_VALUENAME3_129));
Voici par exemple ce que l’on obtient.
PLUGIN_INIT
Cette méthode est appelée à l’initialisation du plugin. On pourra par exemple recharger des paramètres.
La méthode doit obligatoirement se terminer par success = true;
PLUGIN_READ, PLUGIN_ONCE_A_SECOND, PLUGIN_TEN_PER_SECOND:
Cette méthode permet de lire la valeur des capteurs et d’une manière plus générale de réaliser tous les traitements que l’on réalise habituellement dans la boucle loop() d’un programme Arduino. En fonction de la fréquence de traitement désiré, on dispose de 3 méthodes :
- PLUGIN_READ le plugin est exécuté suivant le délai indiqué sur la page de configuration du Device une seule fois.
- PLUGIN_ONCE_A_SECOND cette tâche sera exécutée une fois par seconde avec toutes les autres tâches appelant cette fonction.
- PLUGIN_TEN_PER_SECOND idem mais 10 fois par seconde.
Au démarrage de l’ESP, les tâches sont donc ajoutées dans des listes. Elle seront exécutez à la fréquence choisie. Il faut donc bien choisir la fréquence d’exécution et ne pas créer un code trop lourd pour que l’ESP ait le temps de traiter toutes les tâches.
La méthode doit obligatoirement se terminer par success = true;
Voilà, vous connaissez l’essentiel pour débuter le développement de vos propres plugins. D’apparence compliquée, c’est en fait assez simple.
- ESP Easy Mega. Installation facile avec PlatformIO sur ESP8266 (R120 obsolète)
- Hack . Prise connectée SONOFF S20 pour en faire un super smart plug avec ESP Easy R120
- ESP Easy R120 ou Mega. Flasher le firmware avec esptool.py sur ESP8266
- ESP Easy R120. Ecran d’affichage OLED SSD1306 déporté avec un script Lua
- ESP Easy R120. Utiliser les Rules pour créer la consigne d’un thermostat connecté (Jeedom, Domoticz, Node-RED…)
bonjour, je voudrais savoir svp pour créer un device, avec le code d’un autre : j’ai trouver le code pour intégrer un LIDAR (TFmini) mais je ne sais pas où l’intégrer, sur la D1 mini via PC? sur le portail en ligne de ESP easy?…
merci d’avance !
le code : https://www.letscontrolit.com/forum/viewtopic.php?f=5&t=3956&p=37172#p37172
Bonjour! Une question svp, quand on a codé le plugin, on doit mettre où le code? En effet j’aimerais créer le TFmini (LIDAR) grâce au code trouvé ici : https://www.letscontrolit.com/forum/viewtopic.php?f=5&t=3956&p=37172#p37172
mais je ne vous pas où coller ce code…Si qqn peut me donner une piste, merci !
Après, si j’ai compris le précédent tuto, je devrai compiler et exporter le binaire, on verra bien 😉
Bonsoir, pas de nouvelles sur la publication de la source, même à débogguer ? Merci.
Bonjour Minims. Oui, j’y travaille
Ok, Merci.
Sinon c est vraiment un gros travail ce site, j y passe des heures. Encore merci pour ce que tu fais.
Bonjour, je suis également intéressé par ce code. J’aimerais le tester et aussi l’adapter pour un MQ-7
J’attends impatiemment la suite de cet épisode pour inclure mon mq135 ! Et un bin compilé pour les flemmards 😉
je vais essayé en attendant de le réaliser de mon coté !
merci encore pour tout ces tutos !!!
Bonjour Sébastien. J’ai également la même demande sur la version anglaise du blog. Le plugin est développé mais je suis un peu déçu par les mesures. Je voulais prendre le temps de vérifier avant de publier. C’est peut être mon capteur qui est défectueux. Je vais le publier sur GitHub pour que vous puissiez essayer et me dire si vos mesures sont meilleures que les miennes. J’ai aussi regarder d’autres capteurs de CO2 sans calibration, mais le prix est plus élevé (30€).