Transformer du code Arduino en plugin ESP Easy Mega pour ESP8266 / ESP32 • Domotique et objets connectés à faire soi-même

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.

Il n’est plus possible de développer des plugins pour ESP Easy R120 (version stable). En effet, le code source est trop ancien et génère de nombreuses erreurs durant la compilation.

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

L’AMG88xx (AMG8833 / AMG8831) de Panasonic est un capteur infrarouges matriciel Grid-EYE permettant de cartographier simultanément 64 températures (8×8 pixels). Il détecte la chaleur (le rayonnement infrarouge) du corps humain ou tout autre objet.

Attention, ce capteur n’offre pas une précision suffisante (± 2,5°C) pour un usage médical. Il ne faut pas l’utiliser pour un usage médical tel que la détection du COVID-19. On pourra par exemple l’utiliser pour faire de la détection de présence, du diagnostic de panne par analyse thermique..

  • omhlunneatphaovys9uk-5620670Mesure 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.

Plus d’informations technique ici

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 
#include 

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 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.

Plus de cartes

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

x32rxjgfp39gmzc7ymjr-6919790

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)

Une série de define pour définir les constantes

#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"

Le coeur du plugin est constitué par une méthode switch / case.

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

Voici ce qu’il faut maintenant faire pour convertir votre code Arduino facilement :

❶ 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 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 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é

Il n’y a rien de plus à faire ! Enregistrez le fichier

yrfpccw5rkntjxwyffau-3701546

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

idk7cv2pcg7d5nktsduv-8532866

Ou depuis le Terminal, exécutez la commande suivante en remplaçant par la version désirée

platformio run --target upload --environment 

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

frtvc8q6pvtgbu1icvm5-1397121

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 

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.

Avez-vous aimé cet article ?