ESP8266 - MQTT - NodeRed

Bonjour,
C’est un peu long à expliquer, mais voilà:

Le contexte:

Je viens d’avoir un véhicule d’entreprise électrique. Il sera chargé chez moi et je dois étalir des notes de frais.

Materiel:

  • Prise greenUp
    *Disjoncteur différentiel 20a hi avec contact auxiliaire pour alarme technique via knx et nodeRed
    *Sous compteur avec sortie SO
    *Contacteur NF avec contact auxiliaire pour alarme délestage via knx et nodeRed

ESP8266

Sur le sous-compteur, j’ai connecté un ESP8266 avec une résistance de poullUp de 10k sur l’entrée d2 pour pouvoir creer un fichier *.csv sur un ftp et faire ma note de frais. Voici le code de l’ESP:

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <ArduinoOTA.h>

const char* ssid = ***";
const char* password = "***";
const char* mqttServer = "***";
const int mqttPort = 1883;
const char* mqttUser = "***";
const char* mqttPassword = "***";

  String topic = "CPT_IRVE_Pub";                  // topic mqtt publié

const int buttonPin = D2;
int buttonState = LOW;
int lastButtonState = LOW;

WiFiClient espClient;
PubSubClient client(espClient);

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqttServer, mqttPort);

  // Initialiser OTA
  ArduinoOTA.setHostname("***");
  ArduinoOTA.setPassword("***");
  ArduinoOTA.begin();
}

void loop() {

  ArduinoOTA.handle();

  buttonState = digitalRead(buttonPin);

  if (buttonState != lastButtonState) {
    if (buttonState == HIGH) {
  Serial.println("IRVE:pullUp");
    }
    lastButtonState = buttonState;
    sendCountToMQTT();
  }

  client.loop();
}

void setup_wifi() {
  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  IPAddress staticIP(***);  // Adresse IP fixe
  IPAddress gateway(***);     // Adresse de la passerelle
  IPAddress subnet(***);    // Masque de sous-réseau

  WiFi.config(staticIP, gateway, subnet);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.print("WiFi connecte. IP address: ");
  Serial.println(WiFi.localIP());
}

void sendCountToMQTT() {
  if (!client.connected()) {
    reconnect();
  }
  String message = "IRVE:pullUp";
  char char_topic[topic.length() + 1];
  char char_message[message.length() + 1];
  topic.toCharArray(char_topic, topic.length() + 1);
  message.toCharArray(char_message, message.length() + 1);
  client.publish(char_topic, char_message);
}

void reconnect() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    if (client.connect("ESP8266Client", mqttUser, mqttPassword)) {
      Serial.println("connecte");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      delay(5000);
    }
  }
}

Quand je contrôle sur MQTT Exploreur, j’ai bien les impulsion. Elles semble synchro avec le compteur.

NodeRed

Je passe toute la partie test, délestage qui fonctionne et dont ce n’est pas le sujet.

[
    {
        "id": "9ab0c6fbc490d34e",
        "type": "group",
        "z": "e246ede82cd80a31",
        "style": {
            "stroke": "#999999",
            "stroke-opacity": "1",
            "fill": "none",
            "fill-opacity": "1",
            "label": true,
            "label-position": "nw",
            "color": "#a4a4a4"
        },
        "nodes": [
            "58b20e5a0987ea87",
            "f685b6b7c90da6a7",
            "a3ac54e4e2d26467",
            "1a34d8ecd1198fbd",
            "76834c3d7b724f23",
            "6633f6f50e2f8047",
            "a62f82ba9590bc30",
            "07640a3f9e8ec340",
            "a189a34effd3eb29",
            "2157746ce1d04193",
            "18feda6993c93be9",
            "8abad96514f58bf0",
            "6db1a8bbf35e57ea",
            "31ddf87e11357bb6",
            "6767102fb3c3dfc1"
        ],
        "x": 174,
        "y": 699,
        "w": 912,
        "h": 382
    },
    {
        "id": "58b20e5a0987ea87",
        "type": "comment",
        "z": "e246ede82cd80a31",
        "g": "9ab0c6fbc490d34e",
        "name": "Comptage consomation",
        "info": "",
        "x": 310,
        "y": 760,
        "wires": []
    },
    {
        "id": "f685b6b7c90da6a7",
        "type": "mqtt in",
        "z": "e246ede82cd80a31",
        "g": "9ab0c6fbc490d34e",
        "name": "Impulse CPT IRVE",
        "topic": "CPT_IRVE_Pub",
        "qos": "2",
        "datatype": "auto-detect",
        "broker": "e2a43bc677c6e24f",
        "nl": false,
        "rap": true,
        "rh": 0,
        "inputs": 0,
        "x": 290,
        "y": 820,
        "wires": [
            [
                "a3ac54e4e2d26467",
                "8abad96514f58bf0",
                "31ddf87e11357bb6"
            ]
        ]
    },
    {
        "id": "a3ac54e4e2d26467",
        "type": "function",
        "z": "e246ede82cd80a31",
        "g": "9ab0c6fbc490d34e",
        "name": "Convertion impulse en kwh",
        "func": "// Vérifier si le message reçu a un payload égal à \"IRVE:pullUp\"\nif (msg.payload === \"IRVE:pullUp\") {\n\n// Convertir les impulsions en kWh\nglobal.set(\"IRVE_kwh\", global.get(\"IRVE_kwh\") + 0.001); // Chaque impulsion représente 1 Wh\n\n// Arrondir la valeur à 0.01 kWh (deux décimales)\nglobal.set(\"IRVE_kwh\", parseFloat(global.get(\"IRVE_kwh\").toFixed(3)));\n}\n\n// Créer un nouveau message pour transmettre la valeur calculée\nmsg.payload = global.get(\"IRVE_kwh\");\n\nreturn msg;\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 700,
        "y": 820,
        "wires": [
            [
                "1a34d8ecd1198fbd"
            ]
        ]
    },
    {
        "id": "1a34d8ecd1198fbd",
        "type": "debug",
        "z": "e246ede82cd80a31",
        "g": "9ab0c6fbc490d34e",
        "name": "debug 250",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 970,
        "y": 820,
        "wires": []
    },
    {
        "id": "76834c3d7b724f23",
        "type": "inject",
        "z": "e246ede82cd80a31",
        "g": "9ab0c6fbc490d34e",
        "name": "",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 280,
        "y": 940,
        "wires": [
            [
                "6633f6f50e2f8047"
            ]
        ]
    },
    {
        "id": "6633f6f50e2f8047",
        "type": "change",
        "z": "e246ede82cd80a31",
        "g": "9ab0c6fbc490d34e",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "IRVE_kwh",
                "pt": "global",
                "to": "16.88",
                "tot": "num"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 480,
        "y": 940,
        "wires": [
            []
        ]
    },
    {
        "id": "a62f82ba9590bc30",
        "type": "inject",
        "z": "e246ede82cd80a31",
        "g": "9ab0c6fbc490d34e",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 280,
        "y": 1040,
        "wires": [
            [
                "07640a3f9e8ec340"
            ]
        ]
    },
    {
        "id": "07640a3f9e8ec340",
        "type": "change",
        "z": "e246ede82cd80a31",
        "g": "9ab0c6fbc490d34e",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "IRVE_kwh",
                "tot": "global"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 470,
        "y": 1040,
        "wires": [
            [
                "a189a34effd3eb29"
            ]
        ]
    },
    {
        "id": "a189a34effd3eb29",
        "type": "debug",
        "z": "e246ede82cd80a31",
        "g": "9ab0c6fbc490d34e",
        "name": "debug 252",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 970,
        "y": 1040,
        "wires": []
    },
    {
        "id": "2157746ce1d04193",
        "type": "comment",
        "z": "e246ede82cd80a31",
        "g": "9ab0c6fbc490d34e",
        "name": "Initialise par la valeur lu sur le cpt",
        "info": "",
        "x": 360,
        "y": 900,
        "wires": []
    },
    {
        "id": "18feda6993c93be9",
        "type": "comment",
        "z": "e246ede82cd80a31",
        "g": "9ab0c6fbc490d34e",
        "name": "Donne la conso actuel enregistrée",
        "info": "",
        "x": 360,
        "y": 1000,
        "wires": []
    },
    {
        "id": "8abad96514f58bf0",
        "type": "debug",
        "z": "e246ede82cd80a31",
        "g": "9ab0c6fbc490d34e",
        "name": "debug 254",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 490,
        "y": 800,
        "wires": []
    },
    {
        "id": "6db1a8bbf35e57ea",
        "type": "inject",
        "z": "e246ede82cd80a31",
        "g": "9ab0c6fbc490d34e",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 480,
        "y": 840,
        "wires": [
            [
                "a3ac54e4e2d26467"
            ]
        ]
    },
    {
        "id": "31ddf87e11357bb6",
        "type": "switch",
        "z": "e246ede82cd80a31",
        "g": "9ab0c6fbc490d34e",
        "name": "IRVE:pullUp?",
        "property": "payload",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "IRVE:pullUp",
                "vt": "str"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 520,
        "y": 740,
        "wires": [
            [
                "6767102fb3c3dfc1"
            ]
        ]
    },
    {
        "id": "6767102fb3c3dfc1",
        "type": "debug",
        "z": "e246ede82cd80a31",
        "g": "9ab0c6fbc490d34e",
        "name": "debug 255",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 750,
        "y": 740,
        "wires": []
    },
    {
        "id": "e2a43bc677c6e24f",
        "type": "***",
        "name": "",
        "broker": "***",
        "port": "1883",
        "clientid": "",
        "autoConnect": true,
        "usetls": false,
        "protocolVersion": "3",
        "keepalive": "60",
        "cleansession": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthPayload": "",
        "birthMsg": {},
        "closeTopic": "",
        "closeQos": "0",
        "closePayload": "",
        "closeMsg": {},
        "willTopic": "",
        "willQos": "0",
        "willPayload": "",
        "willMsg": {},
        "userProps": "",
        "sessionExpiry": ""
    }
]

Il semble que je compte 2 fois la même impulsion.

Donc je vois plusieurs causes:

  • Le pullUp ne fonctionne pas bien
  • Dans nr, le QOS2 bug
  • Ma fonction va trop vite

Voyez-vous une erreur de code ou autre, avez-vous d’autres pistes?

Merci pour votre aide, Nicolas

Pour controler le pullup, j’ai ajouté un compteur dont la valeur = celle du compteur physique. je la transmet via mqtt. pas de problème par là

Je précise que le compteur à une durée d’impulsion de 30ms

le problème viens du node mqtt car quand j’attend le topic pullup, il arrive 2 fois.

Je rappelle que j’ai ajouté le comptage dans l’ESP et qu’il arrive en un seul exemplaire alors que pullup arrive 2 fois coup sur coup.

Je préfère compter dans NodeRed car je métrise la valeur contrairement à l’ESP que peut boot et retourner à la valeur initial

Bonjour,
Je me répond à moi même. J’ai trouvé d’où viens mon problème.

Tout simplement du fait de l’avalanche de message sur le Topic MQTT.

Solution:

  • sur mon ESP, j’ai supprimé le topic pullup qui était envoyé tout les 0.001kwh. j’ai créé un nouveau topic qui lui envoie la valeur numérique calculé par l’ESP et ajusté suivant la valeur du compteur. Ce dernier est transmit tous les 0.01kwh. Cela réduit considérablement le trafic sur le brocker.
  • Sur nodeRed, je me contente de récuperer la valeur.

Plusieurs avantages:
Le brocker n’est pas surchargé inutilement
L’ESP fait tout le travail d’incrémentation
nodeRed n’est pas non plus srchargé et ne perd pas de pulup comme cela aurai pu se passer
nodeRed ne surcompte pas

Un extrait du code de mon ESP8266:

String topic = "CPT_IRVE_Pub";                      // topic mqtt publié

const int buttonPin = D2;
int buttonState = LOW;
int lastButtonState = LOW;

float kwh = 26.50;                                  // Valeur initiale pour kWh
float lastSentKwh = kwh;                            // Dernière valeur de kWh envoyée
const float kwhIncrement = 0.001;                   // Incrément de 0.001 kWh

const float sendFrequency = 0.01;                   // Fréquence d'envoi en kWh (toutes les 0.01 kWh)
const float kwhSendFrequency = 0.01;                // Fréquence d'envoi de la valeur de kWh (toutes les 0.1 kWh)

WiFiClient espClient;
PubSubClient client(espClient);

//_________________________________________________________________________________
void setup() {
  pinMode(buttonPin, INPUT_PULLUP);
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqttServer, mqttPort);

  // Initialiser OTA
  ArduinoOTA.setHostname("***");
  ArduinoOTA.setPassword("***");
  ArduinoOTA.begin();
}

//_________________________________________________________________________________
void loop() {
  ArduinoOTA.handle();                              // Gérer les mises à jour OTA

  buttonState = digitalRead(buttonPin);             // Lire l'état du bouton

  if (buttonState != lastButtonState) {
    if (buttonState == HIGH) {
      Serial.println("IRVE:pullUp");                // Afficher un message lorsque le bouton est relâché
      kwh += kwhIncrement;                          // Incrémenter kWh de 0.001 kWh lorsque le bouton est relâché

      if ((kwh - lastSentKwh) >= kwhSendFrequency) {
                                                    // Envoyer "IRVE:pullUp" et la valeur actuelle de kWh si la différence est supérieure ou égale à la fréquence spécifiée
        lastSentKwh = kwh;                          // Mettre à jour la dernière valeur de kWh envoyée
        sendCountToMQTT();                          // Appeler la fonction d'envoi MQTT
      }
    }
    lastButtonState = buttonState;                  // Mettre à jour le dernier état du bouton
  }

  client.loop();                                    // Gérer la connexion MQTT
}

le flow nodeRed:

[
    {
        "id": "9ab0c6fbc490d34e",
        "type": "group",
        "z": "e246ede82cd80a31",
        "style": {
            "stroke": "#999999",
            "stroke-opacity": "1",
            "fill": "none",
            "fill-opacity": "1",
            "label": true,
            "label-position": "nw",
            "color": "#a4a4a4"
        },
        "nodes": [
            "58b20e5a0987ea87",
            "f685b6b7c90da6a7",
            "1a34d8ecd1198fbd",
            "a62f82ba9590bc30",
            "07640a3f9e8ec340",
            "18feda6993c93be9",
            "8abad96514f58bf0",
            "a189a34effd3eb29",
            "c5b513db7b23a27e"
        ],
        "x": 174,
        "y": 659,
        "w": 672,
        "h": 262
    },
    {
        "id": "58b20e5a0987ea87",
        "type": "comment",
        "z": "e246ede82cd80a31",
        "g": "9ab0c6fbc490d34e",
        "name": "Comptage consomation",
        "info": "",
        "x": 310,
        "y": 700,
        "wires": []
    },
    {
        "id": "f685b6b7c90da6a7",
        "type": "mqtt in",
        "z": "e246ede82cd80a31",
        "g": "9ab0c6fbc490d34e",
        "name": "Impulse CPT IRVE",
        "topic": "CPT_IRVE_Pub",
        "qos": "2",
        "datatype": "utf8",
        "broker": "***",
        "nl": false,
        "rap": true,
        "rh": 0,
        "inputs": 0,
        "x": 310,
        "y": 760,
        "wires": [
            [
                "8abad96514f58bf0",
                "c5b513db7b23a27e"
            ]
        ]
    },
    {
        "id": "1a34d8ecd1198fbd",
        "type": "debug",
        "z": "e246ede82cd80a31",
        "g": "9ab0c6fbc490d34e",
        "name": "debug 250",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 730,
        "y": 760,
        "wires": []
    },
    {
        "id": "a62f82ba9590bc30",
        "type": "inject",
        "z": "e246ede82cd80a31",
        "g": "9ab0c6fbc490d34e",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 280,
        "y": 880,
        "wires": [
            [
                "07640a3f9e8ec340"
            ]
        ]
    },
    {
        "id": "07640a3f9e8ec340",
        "type": "change",
        "z": "e246ede82cd80a31",
        "g": "9ab0c6fbc490d34e",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "IRVE_kwh",
                "tot": "global"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 470,
        "y": 880,
        "wires": [
            [
                "a189a34effd3eb29"
            ]
        ]
    },
    {
        "id": "18feda6993c93be9",
        "type": "comment",
        "z": "e246ede82cd80a31",
        "g": "9ab0c6fbc490d34e",
        "name": "Donne la conso actuel enregistrée",
        "info": "",
        "x": 360,
        "y": 840,
        "wires": []
    },
    {
        "id": "8abad96514f58bf0",
        "type": "debug",
        "z": "e246ede82cd80a31",
        "g": "9ab0c6fbc490d34e",
        "name": "debug 254",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 510,
        "y": 720,
        "wires": []
    },
    {
        "id": "a189a34effd3eb29",
        "type": "debug",
        "z": "e246ede82cd80a31",
        "g": "9ab0c6fbc490d34e",
        "name": "debug 252",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 710,
        "y": 880,
        "wires": []
    },
    {
        "id": "c5b513db7b23a27e",
        "type": "function",
        "z": "e246ede82cd80a31",
        "g": "9ab0c6fbc490d34e",
        "name": "Valeur compteur",
        "func": "// Vérifier si le payload commence par \"IRVE:\"\nif (msg.payload.startsWith(\"IRVE:\")) {\n    // Extraire le nombre après \":\"\n    const payloadParts = msg.payload.split(\":\");\n    if (payloadParts.length === 2) {\n        const kwhValue = parseFloat(payloadParts[1]); // Convertir en float\n        if (!isNaN(kwhValue)) {\n            global.set(\"IRVE_kwh\", kwhValue); // Stocker dans la variable globale\n            msg.payload = kwhValue; // Mettre la valeur dans msg.payload\n        }\n    }\n}\n\nreturn msg;\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 530,
        "y": 760,
        "wires": [
            [
                "1a34d8ecd1198fbd"
            ]
        ]
    },
    {
        "id": "e2a43bc677c6e24f",
        "type": "***",
        "name": "",
        "broker": "***",
        "port": "1883",
        "clientid": "",
        "autoConnect": true,
        "usetls": false,
        "protocolVersion": "3",
        "keepalive": "60",
        "cleansession": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthPayload": "",
        "birthMsg": {},
        "closeTopic": "",
        "closeQos": "0",
        "closePayload": "",
        "closeMsg": {},
        "willTopic": "",
        "willQos": "0",
        "willPayload": "",
        "willMsg": {},
        "userProps": "",
        "sessionExpiry": ""
    }
]