Convert Arduino code into ESP Easy Mega plugin for ESP8266 / ESP32

How to convert arduino code into esp easy mega plugin for ESP8266
Share on facebook
Share on twitter
Share on linkedin
Share on pinterest
Share on email
Share on whatsapp

ESP Easy Mega already has an impressive list of plugins for the most common sensors and actuators. If you have not found your happiness in the existing plugins or if you have an already functional Arduino code, we will see how to turn it into a plugin.

 

We will adapt the Arduino code of an AMG8833 thermal camera to transform it into an ESP Easy Mega plugin. The plugin will take one measurement per second and calculate the average temperature (64 measurements), the minimum temperature and the maximum temperature recorded by the thermal camera.

It is no longer possible to develop plugins for ESP Easy R120 (stable version). Indeed, the source code is too old and generates many errors during compilation.

Install Visual Studio Code and the PlatformIO plugin

It is possible to develop a plugin using the Arduino IDE. However, since the source code for the ESP Easy Mega firmware is developed with PlatformIO, it will be much easier to go for the same solution. PlatformIO is available as a plugin for many code editors (Atom, CLion, CodeBlocks, Eclipse, Emacs, NetBeans, Qt Creator, Sublime Text, Vim, Visual Studio, VSCode). The functionalities are identical whatever the publisher. I opted for Microsoft’s Visual Studio Code, a fast, free, cross-platform editor. You choose !

If you do not yet know PlatformIO, I advise you to start by reading this tutorial.

Arduino code used for the thermal imager AMG8833

The AMG88xx (AMG8833 / AMG8831) from Panasonic is a Grid-EYE matrix infrared sensor for simultaneously boardping 64 temperatures (8×8 pixels). It detects heat (infrared radiation) from the human body or any other object.

Please note, this sensor does not offer sufficient accuracy (± 2.5 °C) for medical use. It should not be used for medical purposes such as detecting COVID-19. For example, it can be used to detect presence, fault diagnosis by thermal analysis.

Technical specifications of AMG8833

  • Breakout AMG8831 / AMG8833 mesure de température IR matricielle 64 pixelsSquare matrix temperature measurement consisting of 64 points (8×8 pixels)
  • Operating voltage: 3.3V or 5V
  • Temperature range: -20°C to +80°C (or 0°C to +80°C when high performance mode is activated)
  • Temperature accuracy: ± 2.5°C or ± 4.5 F (typical)
  • Human detection distance: 7m maximum
  • Temperature difference equivalent to noise is 0.05 ° C at 1 Hz
  • Measuring angle: 60 °
  • Current consumption: 4.5mA (normal mode), 0.2mA (sleep mode), 0.8mA (sleep mode)
  • I2C interface
  • Frame rate: 1 or 10 frames per second
  • Time to activate communication after configuration: 50ms then 15ms
  • Panasonic technical manuals

There are 4 versions of the sensor. The differences are located in the supply voltage (3V3 or 5V) and the gain factor (low or high). In the general public, we mainly find the AMG8833 / AMG8831 version. The second reference indicated on the breakout (daughter board) is the reference of the old generation. This has no impact on the operation. Panasonic does not clearly indicate the changes from one generation to the next.

More technical information here

Source code

For the Arduino code, I simplified the example installed with the Adafruit library. This code retrieves a matrix of temperatures each second and calculates the minimum, maximum and average temperature of the 64 points. Nothing very complicated but it is enough for the example.

#include <Wire.h>
#include <Adafruit_AMG88xx.h>  
#define DISPLAY_MATRIX true   // Affiche la matrice de temperature | display the temperature matrix

Adafruit_AMG88xx amg;

float pixels[AMG88xx_PIXEL_ARRAY_SIZE];

void setup() {
  Serial.begin(115200);
  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 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();

  if ( DISPLAY_MATRIX ) {
    Serial.print("[");
    for (int i = 1; i <= AMG88xx_PIXEL_ARRAY_SIZE; i++) {
      Serial.print(pixels[i - 1]);
      Serial.print(", ");
      if ( i % 8 == 0 ) Serial.println();
    }
    Serial.println("]");
    Serial.println();
    
    delay(10000);
  } else {
    delay(1000); // Attend 1 seconde - wait a second
  }
}

Equipment used

For this tutorial, we will simply need an ESP8266 module. Any NodeMCU will do.

More development boards

Circuit

As communication with the AMG8833 takes place via the I2C bus, the circuit is rudimentary.

AMG8833ESP8266
SDAD2
SCLD1
GNDGND
3V3V3

Circuit I2C AMG8833 sur ESP8266

The steps to follow to develop a plugin for ESP Easy Mega

Have a working Arduino code. You don’t have to, but it’s easier to convert already working Arduino code than having to debug it in an ESP Easy plugin. One problem at a time!

1 Adapt the Arduino code to an ESP Easy plugin

2 Declare the plugin

3 Compile, upload and test!

Convert Arduino code to ESP Easy plugin

A template named _Pxxx_PluginTemplate.ino is available at the root of the src (source) folder.

This is a general model, here is a minimal version

Allows to include the plugin during compilation (we will see how to do this below)

#ifdef USES_P129

A series of define to define the constants

#define PLUGIN_129
#define PLUGIN_ID_129 129
#define PLUGIN_NAME_129 "Nom du plugin"
#define PLUGIN_VALUENAME1_129 "Label of the first value returned by the plugin"
Everything is explained in detail below in the article.
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

Here’s what to do now to convert your Arduino code easily:

1Just after the #ifdef USES_PXXX, declare the libraries at the start of the code

2After declaring the constants DEFINE, declare the temporary variables and initialize the objects. Here for example, we will need to create an object to communicate with the AMG88xx sensor and an array of 64 floats to store the temperatures.

Adafruit_AMG88xx amg;
float pixels [AMG88xx_PIXEL_ARRAY_SIZE];

3 Finally insert the contents of the loop loop in the PLUGIN_ONCE_A_SECOND case so that the temperature is updated every second.

4There are a few small adjustments to be made in the code:

  • Replace Serial.print() by addLog(LOG_LEVEL_INFO, message_to_send)
  • Publish each value in the UserVar. The position in the table must correspond to the declaration of the labels which gives
  • UserVar [event->BaseVarIndex + 0] = mini; for the minimum temperature.
  • UserVar [event->BaseVarIndex + 1] = max; for the maximum temperature.
  • UserVar [event->BaseVarIndex + 2] = average; for the mean value
  • Remove the delay(1000). The timeout is now managed by ESP Easy

Initial Arduino code

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);

ESP Easy code

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);

Declare the new plugin to the compiler

Now that the plugin code is ready, we have to declare it so that it is integrated during compilation. Everything goes in the define_plugin_sets.h file located at the root of the src folder.

This file is used to configure the plugins to embed according to the compiled version (stable / dev / test). No need to search too much, place your plugin directly in the stable version by creating a new key

#define USES_P129

There is nothing more to do! Save the file

Déclarer le plugin utilisateur pour l'embarquer dans ESP Easy

Compile and upload the ESP Easy Mega firmware with the plugin

Everything is ready, you just have to upload the firmware as usual with PlatformIO

From the PIO menu ➀, click on the environment that interests you ➁ to display the PIO functions.

Click on Build to compile or on Upload to compile and upload ➂

Compiler ou téléverser ESP Easy Mega depuis PIO

Or from Terminal, run the following command, replacing with the desired version

platformio run --target upload --environment 

Check that the plugin has been embedded

As usual, log into the ESP Easy Mega administration interface and add a new device.

In the selection list you should find your plugin

Nouveau plugin utilisateur dans la liste de sélection

And the user interface of our plugin!

Interface du plugin utilisateur

Detailed description of methods

If everything is clear, here are a little more detailed explanations of how the plugin works

ESP Easy plugin header: include and #define

In the header of the plugin, we can define the libraries to possibly include

#include <SPI.h> 

Then all modules must be identified by a series of keys. It is important to correctly assign the chosen ID to all the keys for the plugin to work.

#define PLUGIN_129Plugin ID
#define PLUGIN_ID_129 129Set the plugin ID
#define PLUGIN_NAME_129 “Indoor Air Quality – MQ135”The caption that will be displayed in the choice list
#define PLUGIN_VALUENAME1_129 “Temp. mini”Plugin output variable. Label displayed in quotes
#define PLUGIN_VALUENAME2_129 “Temp. maxi”The second digital output of the plugin
#define PLUGIN_VALUENAME3_129 “Average”and so on

Plugin_XXX function

The plugin is encapsulated in a function. This function takes several parameters that just need to be tested. The ESP Easy engine regularly launches the plugins associated with the configured Devices.

boolean Plugin_129(byte function, struct EventStruct *event, String& string) 
{
   // Plugin code
}

By convention, we name the plugin by Plugin_ID_DU_PLUGIN

Several methods are mandatory. Each method is called by a switch / case at regular intervals. A method possibly returns a value

PLUGIN_DEVICE_ADD method

The first method PLUGIN_DEVICE_ADD allows to define the parameters which are common to all the 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;
      }

The main parameters are

  • Type the type of equipment connected. You can choose from
    • DEVICE_TYPE_SINGLE (1) connected to a digital input (datapin)
    • DEVICE_TYPE_I2C (2) the device communicates with the ESP8266 / ESP32 via the I2C bus
    • DEVICE_TYPE_ANALOG (3) we use the A / D converter of the ESP8266 (Pin ALL, for example A0)
    • DEVICE_TYPE_DUAL (4) device connected using 2 digital inputs
    • DEVICE_TYPE_DUMMY (99) logical device without physical connection (Dummy device). Read this article to learn more
  • VType corresponds to the type returned by the plugin following the Domoticz format. All types are listed in the file controlleremu.py
    • SENSOR_TYPE_SINGLE (1) one output
    • SENSOR_TYPE_TEMP_HUM (2) 2 temperature & humidity type outputs (DHT11 or DHT22)
    • SENSOR_TYPE_TEMP_BARO (3) 2 temperature & atmospheric pressure type outputs (BMP180)
    • SENSOR_TYPE_TEMP_HUM_BARO (4) 3 outputs, temperature, humidity, atmospheric pressure (BME280)
    • SENSOR_TYPE_DUAL (5) generic, 2 outputs
    • SENSOR_TYPE_TRIPLE (6) generic, 3 outputs
    • SENSOR_TYPE_SWITCH (10) 2 states, switch
    • SENSOR_TYPE_DIMMER (11) 1 dimmer output
    • SENSOR_TYPE_LONG (20) 1 output
  • ValueCount number of output variable. This counter must correspond to the number of key PLUGIN_VALUENAME1_xxx

PLUGIN_GET_DEVICENAME

This method returns the name of the Device.

PLUGIN_GET_DEVICEVALUENAMES

This method is called when opening the module configuration page. It allows to add a new line for each output variable of the plugin.

Use the imposed formalism without forgetting to increment the index of the array TaskDeviceValueNames[X] and of the 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));

Here is for example what we get.

PLUGIN_GET_DEVICEVALUENAMES déclaration des libellés pour chaque variable

PLUGIN_INIT

This method is called when the plugin is initialized. For example, we can reload parameters.

The method must end with success = true;

PLUGIN_READ, PLUGIN_ONCE_A_SECOND, PLUGIN_TEN_PER_SECOND:

This method makes it possible to read the value of the sensors and more generally to perform all the processing that is usually carried out in the loop() of an Arduino program.
Depending on the frequency of treatment desired, there are 3 methods:

  • PLUGIN_READ the plugin is executed according to the time indicated on the Device configuration page only once.
  • PLUGIN_ONCE_A_SECOND this task will be executed once per second with all other tasks calling this function.
  • PLUGIN_TEN_PER_SECOND same but 10 times per second.

When ESP starts up, the tasks are therefore added to lists. They will run at the chosen frequency. It is therefore necessary to choose the frequency of execution well and not to create a code that is too heavy so that the ESP has time to process all the tasks.

The method must end with success = true;

There you have it, you know the basics to start developing your own plugins. Complicated in appearance, it is actually quite simple.

Click to rate this post!
[Total: 1 Average: 5]

Are you having a problem with this topic?

Maybe someone has already found the solution, visit the forum before asking your question
Ask your question

Share on facebook
Share on twitter
Share on linkedin
Share on pinterest
Share on email
Share on whatsapp

Did you like this project ? Don't miss any more projects by subscribing to our weekly newsletter!

We will be happy to hear your thoughts

      Leave a Reply

      DIY Projects