Monitoring électricité avec la téléinfo + Node Red + MQTT

:warning:
Ce tuto n’est plus d’actualité ! Je vous conseille d’aller voir celui ci
Monitoring électricité avec la téléinfo + Node Red + influxDB





Hi !
Je vais vous expliquer un peu ce que j’ai fais pour monitorer ma consommation d’élec :slight_smile:

Note : Perso, je n’utilise plus cette méthode à cause des inconvénients (stocker en base HA, MQTT). A venir un autre tuto avec une méthode toujours à base de Nodered mais avec stockage direct dans influxdb et récup des infos de influxdb dans HA…

:warning:
Disclaimer :
Ne touchez pas si vous ne savez pas ce que vous faites !
Risque d’électrocution !
On parle quand même du compteur principal !
Si vous faites une mauvaise manip vous pouvez vous cramer la tête ou cramer le compteur (qu’Enedis s’empressera de vous facturer !)

Ne déplombez pas votre compteur ! Ca vous coutera cher !
Ne mettez pas le feu chez vous, c’est pas marrant !
Je ne saurai être tenu responsable pour quelque bobos ou dégâts !
:warning:

Le contexte :
J’ai un compteur linky en limite de propriété. Malheureusement me brancher sur la prise téléinfo de ce dernier n’était pas envisageable parce que hors de portée wifi et impossible de passer des câbles dans la gaine déjà en place (elle est sûrement écrasée entre le compteur et le sous sol de ma maison).
Je suis en contrat simple tarif (BASE).

La solution : Mettre un autre compteur dans le sous sol en tête de tableau élec ! J’ai donc acheté un compteur électrique d’occasion sur Ebay, un sagemcom s10c4. (Modèle utilisé par EDF pendant des années avant le linky). Branché l’arrivée de courant en provenance de mon disjoncteur principal sur ce compteur puis à la sortie de ce compteur mon tableau électrique. Du coup chaque Wh consommé par mon installation domestique passe dans ce compteur. J’utilise donc les bornes téléinfo de ce compteur :smiley:

La mise en place : 2 simples fils d’un paire d’un câble PTT298 entre le compteur et un boitier de téléinfo GCE electronics : Module TELEINFO USB et le boitier branché en USB sur mon NUC. Passage de ce boitier en passthrough à ma VM ou hassio est installé. et hop un nouveau port série est détecté :slight_smile:
J’ai décidé de faire la relève via nodered en m’inspirant très fortement de ce qui est fait par Charles sur Hallard.me. => PiTInfo : Téléinfo, Emoncms avec Node Red sur Raspberry PI, moins de 30 min, moins de 10€ – Charles's Blog

Voici le détail du flow pour récupérer, décoder et envoyer les infos de la téléinfo dans le cadre d’un tarif HP/HC : (code du flow dans le second post !)

Version pour le tarif BASE : (code dans le second post)

Dans les 2 cas :

  • Le premier noeud récupère les trames sur le port série
  • Le second limite le nombre de trames (sinon c’est trop !)
  • Le 3ème valide la trame (calcul de checksum)
  • Le 4ème mets tout ça en forme.
  • Les suivants ne récupèrent qu’une certaine partie de la trame pour au final envoyer cette info dans un topic MQTT.

De l’autre côté, hassio récupère les données via des sensors MQTT.

A vous de choisir en fonction de votre contrat, BASE ou HP/HC !


Puis un autre flow (code dans le second post) se charge de faire le calcul de puissance consommée par échantillons de 2 minutes :

En effet cette puissance réelle consommée basée sur l’index du compteur n’existe pas dans la téléinfo. Il faut la calculer. On fait simplement la différence entre l’index de l’instant T et de l’instant T-environ.2.minutes ce qui nous donne le nombre de Wh consommés pendant ces environ 2 minutes. Puis on divise ce nombre par le nombre de secondes écoulées entre les 2 relevés divisé par 3600 (1) (2).
Soit en gros (IndexT - IndexT-2min) / (Tps écoulé entre le relevé T et T-environ.2.minutes / 3600)
Le résultat en W est ensuite envoyé dans un topic MQTT là aussi récupéré via un sensor MQTT dans hassio.

Au final dans hassio (j’ai encore un peu de travail, c’est pas définitif) :
image
(1) On est en Wh (Watts heures), donc n secondes divisées par 3600 pour avoir ça en heures !
(2) Important de ne pas assumer que les trames sont pile poil distantes de 2 minutes. Quelques secondes de plus ou de moins faussent beaucoup le résultat !

Petite foot note : J’ai quand même eu un downside avec le contrat HP/HC. En effet, pour déclencher les heures pleines/heures creuses Enedis à longtemps utilisé un truc appelé PULSADIS. Avec les linky Enedis à changé de techno pour du CPL 3. Malheureusement ils n’ont pas jugé nécessaire de synchroniser les signaux de ces 2 technos. Mon compteur Linky passe en HC à 1h20 et 12h20 alors que mon compteur sagemcom lui passe à 1h36 et 12h36. Oui, il y à 16 minutes de différence entre le signal PULSADIS et CPL… Du coup ma télérelève des indexs HP et HC et faussée.
Mais en faisant mes calculs, je me rends compte que ce contrat HP/HC n’est pas avantageux au final.
Evidemment ceci n’est valable que si vous ajoutez un second compteur. Si vous prenez le téléinfo sur votre compteur principal (Linky ou pas) vous n’aurez pas ce problème.
Je suis donc repassé en tarif simple.

1 « J'aime »

Suite certaines demandes voici le détail de comment récupérer les valeurs extraites de la Téléinfo dans Home Assistant via MQTT :

Dans le 1er flow qui récolte la trame et va la décoder, à la toute fin vous avez soit

  • pour les contrats HP/HC 4 indexs (HP+HC en Wh et kWh) + Puissance instantanée + Période tarifaire en cours (PTEC)
  • pour les contrats base 2 indexs (Wh et kWh) et la puissance instantanée.

Je vous donne l’exemple pour le tarif base :

Vous devez commencer par configurer un « config node » MQTT dans votre nodered :

  • Ajoutez un noeud MQTT out.

Si c’est la première fois que vous utilisez MQTT dans Nodered, sinon go direct à la « configuration des noeuds » :

  • Cliquez sur le petit crayon juste à droite de « Add new MQTT broker »
  • Renseignez l’IP de votre broker MQTT + le port et dans l’onglet security le login et le mot de passe pour s’y connecter.

Configuration des noeuds + sensors HA associés comme suit :

  • Le noeud MQTT pour l’index en Wh est configuré comme suit :
    image
    Donc pour récupérer cette valeur dans HA vous devez créer un sensor MQTT :
sensor:
- platform: mqtt
  name: index_edf_wh
  state_topic: "edf/index_wh"
  unit_of_measurement: "Wh"

  • Pour les kWh le noeud MQTT dans nodered :
    image
    Puis le sensor qui va bien dans HA :
- platform: mqtt
  name: index_edf_kwh
  state_topic: "edf/index_kwh"
  unit_of_measurement: "kWh"

  • Pour l’intensité:
    image
    Et le sensor dans HA :
- platform: mqtt
  name: iinst_edf
  state_topic: "edf/iinst"
  unit_of_measurement: "A"
  • Pour la puissance:
    image
    Et le sensor dans HA :
- platform: mqtt
  name: pinst_edf
  state_topic: "edf/pinst"
  unit_of_measurement: "W"

Ainsi vous pourrez créer des sensors Utility meters qui comptent votre consommation journalière, mensuelle, annuelle :

utility_meter:
#Compteur journalier
  edf_daily:
    source: sensor.index_edf_kwh
    cycle: daily
#Compteur mensuel
  edf_monthly:
    source: sensor.index_edf_kwh
    cycle: monthly
#Compteur annuel
  edf_yearly:
    source: sensor.index_edf_kwh
    cycle: yearly

Carte lovelace

entities:
  - label: Journalier
    type: section
  - entity: sensor.edf_daily
    name: Aujourd'hui
  - label: Mensuel
    type: section
  - entity: sensor.edf_monthly
    name: Mois en cours
  - label: Annuel
    type: section
  - entity: sensor.edf_yearly
    name: Année en cours
  - label: Temps réel
    type: section
  - entity: sensor.pinst_edf
    icon: 'mdi:flash'
    name: Puissance instantanée
  - entity: sensor.iinst_edf
    icon: 'mdi:flash-circle'
    name: Intensité instantanée
show_header_toggle: false
title: Compteurs consommation électrique
type: entities

Code à importer dans nodered pour avoir les flows tout faits

Flow de récup et validation des trames pour le mode HP/HC : :warning: Pensez à changer la conf des noeuds MQTT et serial !

[{"id":"86c82f25.87ce8","type":"debug","z":"31754ffc.c5547","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1310,"y":540,"wires":[]},{"id":"dc5193dd.31241","type":"function","z":"31754ffc.c5547","name":"Structure payload","func":"function isNumeric(n) { \n      return !isNaN(parseFloat(n)) && isFinite(n); \n}\n\n// Pour tous les labels \nfor (var label in msg.payload ) {\n    var value = msg.payload[label];\n    \n\t// Correction des valeurs type string en numérique \t\t\n\tif (label == \"OPTARIF\")\t{\n  \t\t// L'option tarifaire choisie (Groupe \"OPTARIF\") est codée sur 4 caractères alphanumériques \n  \t\t// J'ai pris un nombre arbitraire codé dans l'ordre ci-dessous \n  \t\t// je mets le 4eme char à 0, trop de possibilités \n      \tvalue = value.substring(0, 3);\n    \n       \tif      (value==\"BAS\") value=1;// BASE => Option Base. \n  \t\telse if (value==\"HC.\") value=2;// HC.. => Option Heures Creuses. \n  \t\telse if (value==\"EJP\") value=3;// EJP. => Option EJP. \n  \t\telse if (value==\"BBR\") value=4;// BBRx => Option Tempo\n  \t\telse value = 0;\n  \t\t\n  \t\tmsg.payload[label] = value;\n\t} else if (label==\"HHPHC\") {\n      // L'horaire heures pleines/heures creuses (Groupe \"HHPHC\") est codé par un caractère A à Y \n      // J'ai choisi de prendre son code ASCII\n      msg.payload[label] = value.charCodeAt();\n    } else if ( label == \"PTEC\") {\n      // La période tarifaire en cours (Groupe \"PTEC\"), est codée sur 4 caractères \n      // J'ai pris un nombre arbitraire codé dans l'ordre ci-dessous\n      if      (value==\"TH..\") value= 1; // Toutes les Heures. \n      else if (value==\"HC..\") value= \"Heures Creuses\"; // Heures Creuses. \n      else if (value==\"HP..\") value= \"Heures Pleines\"; // Heures Pleines. \n      else if (value==\"HN..\") value= 4; // Heures Normales. \n      else if (value==\"PM..\") value= 5; // Heures de Pointe Mobile. \n      else if (value==\"HCJB\") value= 6; // Heures Creuses Jours Bleus. \n      else if (value==\"HCJW\") value= 7; // Heures Creuses Jours Blancs (White). \n      else if (value==\"HCJR\") value= 8; // Heures Creuses Jours Rouges. \n      else if (value==\"HPJB\") value= 9; // Heures Pleines Jours Bleus. \n      else if (value==\"HPJW\") value= 10;// Heures Pleines Jours Blancs (White). \n      else if (value==\"HPJR\") value= 11;// Heures Pleines Jours Rouges. \n      else value = 0;\n      \n      msg.payload[label] = value;\n    } else if ( label == \"IINST\") {\n        delete msg.payload.IINST;\n        msg.payload.IINST = Number(value)\n    } else if ( label == \"IMAX\") {\n        delete msg.payload.IMAX;\n        msg.payload.IMAX1 = Number(value);\n    } else if ( isNumeric(value) && label != \"ADCO\" ) {\n        // Transformer les valeurs numériques\n        msg.payload[label] = Number(value);\n    }\n}\n\n// Sauvegarde dans le contexte global\ncontext.global.teleinfo = msg.payload;\n\nreturn msg;","outputs":1,"noerr":0,"x":670,"y":560,"wires":[["f979933e.c7032","81b457bd.720e28","ca2f3cb3.ced7c","2075f662.e977ca","79d460da.de8aa","6ddb61d.7de3da","a7352aec.7cc578"]]},{"id":"bb4e5cce.d4804","type":"mqtt out","z":"31754ffc.c5547","name":"edf/index_wh","topic":"edf/index_wh","qos":"","retain":"true","broker":"7512dcc2.be07d4","x":1330,"y":580,"wires":[]},{"id":"25183aa6.a19c36","type":"mqtt out","z":"31754ffc.c5547","name":"edf/index_kwh","topic":"edf/index_kwh","qos":"","retain":"true","broker":"7512dcc2.be07d4","x":1340,"y":680,"wires":[]},{"id":"936873da.10b6c","type":"mqtt out","z":"31754ffc.c5547","name":"edf/iinst","topic":"edf/iinst","qos":"","retain":"true","broker":"7512dcc2.be07d4","x":1320,"y":780,"wires":[]},{"id":"a36e7648.2f6928","type":"serial in","z":"31754ffc.c5547","name":"","serial":"3b2a542e.d3dabc","x":90,"y":560,"wires":[["310addc1.ff9122"]]},{"id":"f979933e.c7032","type":"function","z":"31754ffc.c5547","name":"INDEX TOTAL WH","func":"var INDEX = msg.payload.HCHC + msg.payload.HCHP\n\nmsg.payload = INDEX\nreturn msg;","outputs":1,"noerr":0,"x":930,"y":560,"wires":[["2ef2da60.8a7d76"]]},{"id":"25c2fa1d.b33cf6","type":"function","z":"31754ffc.c5547","name":"valide trame","func":"// La trame complète est reçue dans 'msg'\nvar teleinfo={};\n\n// Enlever les codes début et fin de trame et récupérer les lignes 1 à 1\nvar lines = msg.payload.toString().replace(\"\\u0002\\n\",\"\").replace(\"\\r\\u0003\",\"\");\nlines = lines.split(\"\\r\\n\");\n\n// Pour chaque ligne\nfor (var line in lines) {\n\tvar i;\n  \tvar checksum = 32;\n  \t\n  \t// Recupérer le label, la valeur et la checksum\n  \t// si la checksum est un espace on le remplace par un caractère non \n  \t// autorisé en checksum (ici 's') pour eviter pb de split\n  \t// donc espace espace devient espace s\n\tvar myline = lines[line].toString().replace(\"  \",\" s\").split(\" \");\n\t\n\t// on dépile nos 3 valeurs\n\tvar check = myline.pop();\n\tvar value = myline.pop();\n\tvar label = myline.pop();\n\t\n\t// On peu repositionner la checksum à espace si c'était le cas\n\tif (check == \"s\") check = \" \";\n\n\t// Calcul de la checksum sur ce qu'on a reçu, on balaye tous les caractères\t\t\n  \tfor (i = 0; i < label.length; i++) checksum += label.charCodeAt(i);\n  \tfor (i = 0; i < value.length; i++) checksum += value.charCodeAt(i);\n \tchecksum = ((checksum%256) & 63) + 32;\n \tchecksum = String.fromCharCode(checksum);\n\t\n\t// Checksum correcte ?\n \tif (checksum == check ) {\n\t\tteleinfo[label] = value;\n\t} else {\n\t\tconsole.log(\"'%s' '%s' '%s' => Bad Checksum '%s'\", label, value, check, checksum );\n\t}\n}\nreturn [ { payload: teleinfo } ];","outputs":1,"noerr":0,"x":470,"y":560,"wires":[["dc5193dd.31241","de235fb7.a9233"]]},{"id":"2ef2da60.8a7d76","type":"rbe","z":"31754ffc.c5547","name":"","func":"rbe","gap":"","start":"","inout":"out","property":"payload","x":1130,"y":560,"wires":[["86c82f25.87ce8","bb4e5cce.d4804"]]},{"id":"81b457bd.720e28","type":"function","z":"31754ffc.c5547","name":"INDEX TOTAL KWH","func":"var INDEX = msg.payload.HCHC + msg.payload.HCHP\n\nmsg.payload = INDEX / 1000\nreturn msg;","outputs":1,"noerr":0,"x":940,"y":620,"wires":[["15fdcbab.7ea5c4"]]},{"id":"15fdcbab.7ea5c4","type":"rbe","z":"31754ffc.c5547","name":"","func":"rbe","gap":"","start":"","inout":"out","property":"payload","x":1130,"y":620,"wires":[["6b463144.db1fc","25183aa6.a19c36"]]},{"id":"6b463144.db1fc","type":"debug","z":"31754ffc.c5547","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1310,"y":640,"wires":[]},{"id":"6ddb61d.7de3da","type":"function","z":"31754ffc.c5547","name":"IINST","func":"var IINST = msg.payload.IINST\n\nmsg.payload = IINST\nreturn msg;","outputs":1,"noerr":0,"x":890,"y":680,"wires":[["125a0354.b2905d"]]},{"id":"edc388bb.f12798","type":"debug","z":"31754ffc.c5547","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1310,"y":740,"wires":[]},{"id":"125a0354.b2905d","type":"rbe","z":"31754ffc.c5547","name":"","func":"rbe","gap":"","start":"","inout":"out","property":"payload","x":1130,"y":680,"wires":[["edc388bb.f12798","936873da.10b6c"]]},{"id":"310addc1.ff9122","type":"delay","z":"31754ffc.c5547","name":"","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"15","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"x":280,"y":560,"wires":[["25c2fa1d.b33cf6","a89a85b8.4b8098"]]},{"id":"ca2f3cb3.ced7c","type":"function","z":"31754ffc.c5547","name":"INDEX HC KWH","func":"var INDEX = msg.payload.HCHC\n\nmsg.payload = INDEX / 1000\nreturn msg;","outputs":1,"noerr":0,"x":920,"y":500,"wires":[["2002cc8b.516b44"]]},{"id":"2075f662.e977ca","type":"function","z":"31754ffc.c5547","name":"INDEX HP KWH","func":"var INDEX = msg.payload.HCHP\n\nmsg.payload = INDEX / 1000\nreturn msg;","outputs":1,"noerr":0,"x":920,"y":440,"wires":[["1cf856c6.bdfdb9","1d37c2c6.46802d"]]},{"id":"1d37c2c6.46802d","type":"debug","z":"31754ffc.c5547","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1310,"y":340,"wires":[]},{"id":"586cc235.f9756c","type":"mqtt out","z":"31754ffc.c5547","name":"edf/index_hp_kwh","topic":"edf/index_hp_kwh","qos":"","retain":"true","broker":"7512dcc2.be07d4","x":1350,"y":380,"wires":[]},{"id":"47a40206.b69c8c","type":"debug","z":"31754ffc.c5547","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1310,"y":440,"wires":[]},{"id":"d1cd6f9c.39734","type":"mqtt out","z":"31754ffc.c5547","name":"edf/index_hc_wh","topic":"edf/index_hc_kwh","qos":"","retain":"true","broker":"7512dcc2.be07d4","x":1350,"y":480,"wires":[]},{"id":"2002cc8b.516b44","type":"rbe","z":"31754ffc.c5547","name":"","func":"rbe","gap":"","start":"","inout":"out","property":"payload","x":1130,"y":500,"wires":[["d1cd6f9c.39734","47a40206.b69c8c"]]},{"id":"1cf856c6.bdfdb9","type":"rbe","z":"31754ffc.c5547","name":"","func":"rbe","gap":"","start":"","inout":"out","property":"payload","x":1130,"y":440,"wires":[["586cc235.f9756c","1d37c2c6.46802d"]]},{"id":"79d460da.de8aa","type":"debug","z":"31754ffc.c5547","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":670,"y":460,"wires":[]},{"id":"de235fb7.a9233","type":"debug","z":"31754ffc.c5547","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":470,"y":460,"wires":[]},{"id":"a89a85b8.4b8098","type":"debug","z":"31754ffc.c5547","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":290,"y":460,"wires":[]},{"id":"a7352aec.7cc578","type":"function","z":"31754ffc.c5547","name":"PTEC","func":"var PTEC = msg.payload.PTEC\n\nmsg.payload = PTEC\nreturn msg;","outputs":1,"noerr":0,"x":890,"y":740,"wires":[["78f8cd7e.408f24"]]},{"id":"523f3dd0.734f34","type":"mqtt out","z":"31754ffc.c5547","name":"edf/ptec","topic":"edf/ptec","qos":"","retain":"true","broker":"7512dcc2.be07d4","x":1320,"y":880,"wires":[]},{"id":"941b507d.8f041","type":"debug","z":"31754ffc.c5547","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1310,"y":840,"wires":[]},{"id":"78f8cd7e.408f24","type":"rbe","z":"31754ffc.c5547","name":"","func":"rbe","gap":"","start":"","inout":"out","property":"payload","x":1130,"y":740,"wires":[["941b507d.8f041","523f3dd0.734f34"]]},{"id":"7512dcc2.be07d4","type":"mqtt-broker","z":"","name":"mosquitto","broker":"192.168.1.3","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""},{"id":"3b2a542e.d3dabc","type":"serial-port","z":"","serialport":"/dev/ttyUSB0","serialbaud":"1200","databits":"7","parity":"even","stopbits":"1","waitfor":"","newline":"0x3","bin":"false","out":"char","addchar":"","responsetimeout":"10000"}]

Flow de récup et validation des trames pour le mode BASE : :warning: Pensez à changer la conf des noeuds MQTT et serial !

[{"id":"6928a039.118cf","type":"debug","z":"6834f0bf.c570c","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1310,"y":440,"wires":[]},{"id":"3014527a.81e22e","type":"function","z":"6834f0bf.c570c","name":"Structure payload","func":"function isNumeric(n) { \n      return !isNaN(parseFloat(n)) && isFinite(n); \n}\n\n// Pour tous les labels \nfor (var label in msg.payload ) {\n    var value = msg.payload[label];\n    \n\t// Correction des valeurs type string en numérique \t\t\n\tif (label == \"OPTARIF\")\t{\n  \t\t// L'option tarifaire choisie (Groupe \"OPTARIF\") est codée sur 4 caractères alphanumériques \n  \t\t// J'ai pris un nombre arbitraire codé dans l'ordre ci-dessous \n  \t\t// je mets le 4eme char à 0, trop de possibilités \n      \tvalue = value.substring(0, 3);\n    \n       \tif      (value==\"BAS\") value=1;// BASE => Option Base. \n  \t\telse if (value==\"HC.\") value=2;// HC.. => Option Heures Creuses. \n  \t\telse if (value==\"EJP\") value=3;// EJP. => Option EJP. \n  \t\telse if (value==\"BBR\") value=4;// BBRx => Option Tempo\n  \t\telse value = 0;\n  \t\t\n  \t\tmsg.payload[label] = value;\n\t} else if (label==\"HHPHC\") {\n      // L'horaire heures pleines/heures creuses (Groupe \"HHPHC\") est codé par un caractère A à Y \n      // J'ai choisi de prendre son code ASCII\n      msg.payload[label] = value.charCodeAt();\n    } else if ( label == \"PTEC\") {\n      // La période tarifaire en cours (Groupe \"PTEC\"), est codée sur 4 caractères \n      // J'ai pris un nombre arbitraire codé dans l'ordre ci-dessous\n      if      (value==\"TH..\") value= 1; // Toutes les Heures. \n      else if (value==\"HC..\") value= \"Heures Creuses\"; // Heures Creuses. \n      else if (value==\"HP..\") value= \"Heures Pleines\"; // Heures Pleines. \n      else if (value==\"HN..\") value= 4; // Heures Normales. \n      else if (value==\"PM..\") value= 5; // Heures de Pointe Mobile. \n      else if (value==\"HCJB\") value= 6; // Heures Creuses Jours Bleus. \n      else if (value==\"HCJW\") value= 7; // Heures Creuses Jours Blancs (White). \n      else if (value==\"HCJR\") value= 8; // Heures Creuses Jours Rouges. \n      else if (value==\"HPJB\") value= 9; // Heures Pleines Jours Bleus. \n      else if (value==\"HPJW\") value= 10;// Heures Pleines Jours Blancs (White). \n      else if (value==\"HPJR\") value= 11;// Heures Pleines Jours Rouges. \n      else value = 0;\n      \n      msg.payload[label] = value;\n    } else if ( label == \"IINST\") {\n        delete msg.payload.IINST;\n        msg.payload.IINST = Number(value)\n    } else if ( label == \"IMAX\") {\n        delete msg.payload.IMAX;\n        msg.payload.IMAX1 = Number(value);\n    } else if ( isNumeric(value) && label != \"ADCO\" ) {\n        // Transformer les valeurs numériques\n        msg.payload[label] = Number(value);\n    }\n}\n\n// Sauvegarde dans le contexte global\ncontext.global.teleinfo = msg.payload;\n\nreturn msg;","outputs":1,"noerr":0,"x":670,"y":560,"wires":[["f7b399b4.fe1048","beedb3e3.ddcb3","4b54c8ee.4a6428","ec2451b3.dcbb7"]]},{"id":"fbbe122e.9d309","type":"mqtt out","z":"6834f0bf.c570c","name":"edf/index_wh","topic":"edf/index_wh","qos":"","retain":"true","broker":"f06b0b28.42ba68","x":1330,"y":480,"wires":[]},{"id":"2a41b6e9.cb5c9a","type":"mqtt out","z":"6834f0bf.c570c","name":"edf/index_kwh","topic":"edf/index_kwh","qos":"","retain":"true","broker":"f06b0b28.42ba68","x":1340,"y":580,"wires":[]},{"id":"58383bac.be6804","type":"mqtt out","z":"6834f0bf.c570c","name":"edf/iinst","topic":"edf/iinst","qos":"","retain":"true","broker":"f06b0b28.42ba68","x":1320,"y":680,"wires":[]},{"id":"75f15514.01245c","type":"serial in","z":"6834f0bf.c570c","name":"","serial":"40ca77b1.eab5e8","x":90,"y":560,"wires":[["2c0ea20f.204abe"]]},{"id":"f7b399b4.fe1048","type":"function","z":"6834f0bf.c570c","name":"INDEX WH","func":"var INDEX = msg.payload.BASE\n\nmsg.payload = INDEX\nreturn msg;","outputs":1,"noerr":0,"x":910,"y":500,"wires":[["7a3bf371.a625ec"]]},{"id":"35183b6f.805564","type":"function","z":"6834f0bf.c570c","name":"valide trame","func":"// La trame complète est reçue dans 'msg'\nvar teleinfo={};\n\n// Enlever les codes début et fin de trame et récupérer les lignes 1 à 1\nvar lines = msg.payload.toString().replace(\"\\u0002\\n\",\"\").replace(\"\\r\\u0003\",\"\");\nlines = lines.split(\"\\r\\n\");\n\n// Pour chaque ligne\nfor (var line in lines) {\n\tvar i;\n  \tvar checksum = 32;\n  \t\n  \t// Recupérer le label, la valeur et la checksum\n  \t// si la checksum est un espace on le remplace par un caractère non \n  \t// autorisé en checksum (ici 's') pour eviter pb de split\n  \t// donc espace espace devient espace s\n\tvar myline = lines[line].toString().replace(\"  \",\" s\").split(\" \");\n\t\n\t// on dépile nos 3 valeurs\n\tvar check = myline.pop();\n\tvar value = myline.pop();\n\tvar label = myline.pop();\n\t\n\t// On peu repositionner la checksum à espace si c'était le cas\n\tif (check == \"s\") check = \" \";\n\n\t// Calcul de la checksum sur ce qu'on a reçu, on balaye tous les caractères\t\t\n  \tfor (i = 0; i < label.length; i++) checksum += label.charCodeAt(i);\n  \tfor (i = 0; i < value.length; i++) checksum += value.charCodeAt(i);\n \tchecksum = ((checksum%256) & 63) + 32;\n \tchecksum = String.fromCharCode(checksum);\n\t\n\t// Checksum correcte ?\n \tif (checksum == check ) {\n\t\tteleinfo[label] = value;\n\t} else {\n\t\tconsole.log(\"'%s' '%s' '%s' => Bad Checksum '%s'\", label, value, check, checksum );\n\t}\n}\nreturn [ { payload: teleinfo } ];","outputs":1,"noerr":0,"x":470,"y":560,"wires":[["3014527a.81e22e","c7c900a6.c32dc"]]},{"id":"7a3bf371.a625ec","type":"rbe","z":"6834f0bf.c570c","name":"","func":"rbe","gap":"","start":"","inout":"out","property":"payload","x":1130,"y":500,"wires":[["6928a039.118cf","fbbe122e.9d309"]]},{"id":"beedb3e3.ddcb3","type":"function","z":"6834f0bf.c570c","name":"INDEX KWH","func":"var INDEX = msg.payload.BASE\n\nmsg.payload = INDEX / 1000\nreturn msg;","outputs":1,"noerr":0,"x":910,"y":560,"wires":[["13648db0.51fa62"]]},{"id":"13648db0.51fa62","type":"rbe","z":"6834f0bf.c570c","name":"","func":"rbe","gap":"","start":"","inout":"out","property":"payload","x":1130,"y":560,"wires":[["26a4a917.34de86","2a41b6e9.cb5c9a"]]},{"id":"26a4a917.34de86","type":"debug","z":"6834f0bf.c570c","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1310,"y":540,"wires":[]},{"id":"ec2451b3.dcbb7","type":"function","z":"6834f0bf.c570c","name":"IINST","func":"var IINST = msg.payload.IINST\n\nmsg.payload = IINST\nreturn msg;","outputs":1,"noerr":0,"x":890,"y":620,"wires":[["a86647d.43bcab8"]]},{"id":"d8850e24.32a2e","type":"debug","z":"6834f0bf.c570c","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1310,"y":640,"wires":[]},{"id":"a86647d.43bcab8","type":"rbe","z":"6834f0bf.c570c","name":"","func":"rbe","gap":"","start":"","inout":"out","property":"payload","x":1130,"y":620,"wires":[["d8850e24.32a2e","58383bac.be6804"]]},{"id":"2c0ea20f.204abe","type":"delay","z":"6834f0bf.c570c","name":"","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"15","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"x":280,"y":560,"wires":[["35183b6f.805564","95b88432.b45b78"]]},{"id":"4b54c8ee.4a6428","type":"debug","z":"6834f0bf.c570c","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":670,"y":460,"wires":[]},{"id":"c7c900a6.c32dc","type":"debug","z":"6834f0bf.c570c","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":470,"y":460,"wires":[]},{"id":"95b88432.b45b78","type":"debug","z":"6834f0bf.c570c","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":290,"y":460,"wires":[]},{"id":"f06b0b28.42ba68","type":"mqtt-broker","z":"","name":"mosquitto","broker":"192.168.1.3","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""},{"id":"40ca77b1.eab5e8","type":"serial-port","z":"","serialport":"/dev/ttyUSB0","serialbaud":"1200","databits":"7","parity":"even","stopbits":"1","waitfor":"","newline":"0x3","bin":"false","out":"char","addchar":"","responsetimeout":"10000"}]

Code du flow du calcul de puissance instantanée :

[{"id":"5d80b82d.bdc808","type":"api-get-history","z":"31754ffc.c5547","name":"index edf -2mn","server":"7b44b840.df2a18","startdate":"","enddate":"","entityid":"sensor.index_edf_wh","entityidtype":"is","useRelativeTime":true,"relativeTime":"2m","flatten":true,"output_type":"array","output_location_type":"msg","output_location":"payload","x":380,"y":160,"wires":[["6a20a0c2.f9be1"]]},{"id":"5691f229.95948c","type":"api-current-state","z":"31754ffc.c5547","name":"index edf now","server":"7b44b840.df2a18","version":1,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","override_topic":true,"entity_id":"sensor.index_edf_wh","state_type":"num","state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","blockInputOverrides":false,"x":380,"y":260,"wires":[["5fc9af9.c7d3a5"]]},{"id":"6a20a0c2.f9be1","type":"function","z":"31754ffc.c5547","name":"","func":"msg2 = {};\nmsg2.payload = {};\ntopic = 'old';\nmsg2.payload.old_state = parseFloat(msg.payload[0].state);\nmsg2.payload.old_date = Date.parse(msg.payload[0].last_changed)/1000|0;\nmsg2.topic = topic;\nreturn msg2;","outputs":1,"noerr":0,"x":550,"y":160,"wires":[["7e6fce86.3e948","95675d11.94cf8"]]},{"id":"7e6fce86.3e948","type":"join","z":"31754ffc.c5547","name":"","mode":"custom","build":"object","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":false,"timeout":"","count":"2","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":690,"y":200,"wires":[["18c65f3.5663da1"]]},{"id":"18c65f3.5663da1","type":"function","z":"31754ffc.c5547","name":"","func":"old = msg.payload.old.old_state;\ncurrent = msg.payload.new.new_state;\ndiff_index = current - old;\ndiff_seconds = msg.payload.new.new_date - msg.payload.old.old_date;\ncoeff = diff_seconds / 3600\nconso = diff_index / coeff\nconso = Math.round(conso*100)/100\nmsg2 = {};\nmsg2.payload = {};\nmsg2.payload.conso = conso;\nreturn msg2;","outputs":1,"noerr":0,"x":870,"y":200,"wires":[["3c07458d.aecd7a"]]},{"id":"78162bff.2c2ee4","type":"inject","z":"31754ffc.c5547","name":"","topic":"","payload":"","payloadType":"date","repeat":"120","crontab":"","once":true,"onceDelay":"30","x":210,"y":220,"wires":[["5d80b82d.bdc808","5691f229.95948c"]]},{"id":"5fc9af9.c7d3a5","type":"function","z":"31754ffc.c5547","name":"","func":"msg3 = {};\nmsg3.payload = {};\ntopic = 'new';\nmsg3.payload.new_state = parseFloat(msg.payload);\nmsg3.payload.new_date = Date.parse(msg.data.last_changed)/1000|0;\nmsg3.topic = topic;\nreturn msg3;","outputs":1,"noerr":0,"x":550,"y":260,"wires":[["7e6fce86.3e948","f2d3db47.03d508"]]},{"id":"98252990.1417f8","type":"mqtt out","z":"31754ffc.c5547","name":"puissance instantanée","topic":"edf/pinst","qos":"","retain":"true","broker":"7512dcc2.be07d4","x":1380,"y":200,"wires":[]},{"id":"3c07458d.aecd7a","type":"function","z":"31754ffc.c5547","name":"transforme en nombre","func":"\nmsg.payload= parseFloat(msg.payload.conso);\n\nreturn msg;\n\n\n","outputs":1,"noerr":0,"x":1120,"y":200,"wires":[["98252990.1417f8"]]},{"id":"95675d11.94cf8","type":"debug","z":"31754ffc.c5547","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":685,"y":115,"wires":[]},{"id":"f2d3db47.03d508","type":"debug","z":"31754ffc.c5547","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":690,"y":280,"wires":[]},{"id":"7b44b840.df2a18","type":"server","z":"","name":"Home Assistant","legacy":false,"hassio":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open"},{"id":"7512dcc2.be07d4","type":"mqtt-broker","z":"","name":"mosquitto","broker":"192.168.1.3","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""}]
1 « J'aime »

Impressionnant !
Mais ça n’aurait pas été plus simple avec une pince et un Shelly EM ?

souhaitant un truc fiable je me voyais pas me servir d’une pince ampèremétrique a 15 boules :rofl:
Et le prix n’est pas l’argument le plus a prendre en compte. C’est bien évidemment la fiabilité de mesure hein !

S’agissant juste d’une évaluation de conso une pince est à mon gout suffisante. Pour une précision absolue c’est sur qu’un vieux compteur EDF est parfait ! Superbe idée :slight_smile:

Après ma solution de compteur supplémentaire n’est qu’une parade au compteur principal en dehors du logement. Sinon j’aurai pas eu a l’ajouter !
Mais au moins si mon linky prends feu ben ça sera loin dehors ! Lol

Je suis dans la même situation… J’ai deux solutions :

  • Remonter la teleinfo en utilisant le câble qui servait à commuter HP/HC (je ne sais pas si j’ai le droit) et ensuite utiliser un ESP/MQTT
  • Utiliser un ERL (ERL WiFi pour compteur Linky - eeSmart) mais je n’ai pas trouver d’infos pour l’exploiter sius HA

Le cable de commutation HP/HC s’il ne te sers plus tu le déplaces sur les bornes de téléinfo et tu utilise ça ! Aucun souci !
La solution ESP est jouable aussi (moi il est hors de portée wifi donc c’était pas possible !)

Bonjour à tous,
Je suis en charge du support du produit D2L, l’ERL WiFi.
A la demande de l’un des membres de ce forum, je viens vous parler de son utilisation possible avec HA.
Le D2L est un produit ouvert. Nous mettons à disposition un serveur gratuit sur lequel toujours gratuitement les données sont récupérable via une API. Nous ne développons nous même de Plugin mais nous apportons notre support (document, compte test) et offrons un D2L à tout développeur d’un plugin sur une plateforme non encore couverte (c’est le cas sauf erreur de notre part sur HA). Des plugin ont ainsi été développés par la communauté eedomus, jeedom, domotics, …
Il est aussi possible de développer un serveur local (le D2L envoie c’est données en JSON).
Un document existe pour les intégrateurs et nous allons prochainement publié un document simplifié pour les particuliers.
En résumé, si l’un de vous est volontaire pour développer un plugin sur la base de l’API et/ou d’un serveur local, nous serons heureux de lui faire bénéficier gracieusement de notre support.
Ne pouvant être présent sur l’ensemble des forums.
Merci d’avance d’envoyer vos demandes sur support@eesmart.fr

2 « J'aime »

Bonjour, merci pour tout ce travail,
J’essaie de l’intégrer à mon HA mais sans succès. (je débute). J’ai un teleinfo USBTIC en USB sur le même port série que l’exemple mais raccorder à un compteur Linky.
Sous node-red, j’ai des erreur dès le premier noeud :
Parfois : « TypeError: Cannot read property ‹ length › of undefined »
Parfois : le payload semble bon mais avec des caractères inconnus en début et fin :
Parfois : Le ADCO est ADO ou AD ADC
Parfois la payload contient tout en double (2 listes d’info enchainées)
Est-ce parce que c’est un Linky ?
Déjà testé sur Domoticz et fonctionnait nativement avec mon ancien compteur mais aussi après le passage en Linky…
Merci de votre aide

Problème en grande partie résolue, le port série doit être configuré en 9600 sur le Linky.
Je n’ai plus qu’une erreur de temps en temps lorsque la payload est :
payload: « … »
La puissance instantanée reste à 0, j’ai renommé les variables donc probablement la raison.
Merci pour le travail accompli et le partage.

Bonjour, je débute sur HA (jeedom auparavant), j’ai suivi le tuto mais c’est la 1ere fois que j’utilisais node-red. J’ai mis le chemin de mon teleinfo usb (/dev/serial/by-id/usb-Cartelectronic_Interface_USB_1_TIC_DA418ZL7-if00-port0) et j’ai configurer mon MQTT. mais sur mon Dashboard tout reste a 0.

Je vous montre mon flow sur node red :

Il faut vérifier si tu as bien des données qui sortent de ton 1er noeud (1er noeud de débug) dans un premier temps

j’ai ça dans le debug :

Donc déjà le chemin de ton USB/Serial est OK.

J’ai quand même l’impression que ton noeud « USB » n’est pas correctement configuré. Tu pourrais faire voir la config de ce noeud ?
En fait mon doute se trouve sur le découpage du payload qui arrive de l’USB.
Mon exemple est fait pour le boitier GCE Electronics et tu ne sembles pas utiliser celui ci. Donc cette config peut être différente, ainsi que la suite d’ailleurs.

Ensuite, désactiver tous les noeuds de débug et n’activer que celui qui est à la sortie de « limit 1msg/15s ».
Pense à faire voir aussi dans tes screens l’intégralité des infos.

Là on a pas tout…

Le lien vers ma carte : https://www.amazon.fr/gp/product/B01DLBVN3M/ref=ppx_yo_dt_b_search_asin_image?ie=UTF8&psc=1

et j’ai mis ces parametres car il y avait un commentaire plus bas :

image

Salut @SNoof, je viens de voir ton post! J’aimerais savoir, comment fais tu pour calculer en € l’ensemble de tes infos récoltées ?
Merci

Bonjour,

@eesmart ça en est où le D2L avec HA ?

Merci @SNoof pour ce post, ça fonctionne du premier coup avec le module GCE :slight_smile:

Utilisateurs de HA depuis quelques mois, ce fil m’a permis de découvrir un peu NodeRed.

Petit ajout pour avoir la consommation de la dernière heure et la consommation de la semaine :


#Compteur heure
  edf_hourly:
    source: sensor.index_edf_kwh
    cycle: hourly

#Compteur semaine
  edf_weekly:
    source: sensor.index_edf_kwh
    cycle: weekly

Bonjour,
débutant sur HA et donc encore plus sur nodered, ce topic est top.
Une question, j’ai importé les flow, mis les paramètres mosquitto.
Par contre, les sensor sont bien à créer dans le fichier sensor.yaml, on est d’accord …

Pareil, pourrais tu m’expliquer comment récupérer le tableau Historique Consommation et faire les belles courbes comme toi ?

Désolé si question « bête »