Skip to content
  • Blog
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Brand Logo

Community Forum

  1. Home
  2. Categories
  3. Téléinfo
  4. PiTInfo
  5. Récupération et publication MQTT des données de la téléinformation avec Raspberry Pi et Docker

Récupération et publication MQTT des données de la téléinformation avec Raspberry Pi et Docker

Scheduled Pinned Locked Moved PiTInfo
7 Posts 3 Posters 2.8k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • tmsT Offline
    tmsT Offline
    tms
    wrote on last edited by
    #1

    Hello,

    Ca fait un petit bout de temps que j'ai mis en place cette solution chez moi, et ça tourne parfaitement. Le mode historique comme standard est géré.

    Je pense que la solution a suffisamment fait ses preuves pour la partager avec vous !

    Toute la marche à suivre est disponible ici : https://github.com/tms0/teleinfo-publisher

    N'hésitez pas à tester et me dire ce que vous en pensez !

    Valentin

    1 Reply Last reply
    • CharlesC Offline
      CharlesC Offline
      Charles
      wrote on last edited by admin
      #2

      Alors ça, c'est top, merci à toi pour le partage 🙂

      Par ailleurs, sais que maintenant le firmware tasmota gère parfaitement la téléinfo est il envoi les données dans MQTT, ça c'est encore une autre très bonne nouvelle, toutes les cartes à base d'ESP8266 ou ESP32 peuvent être flashée avec. Il suffit d'ajouter un bon vieil opto ou prendre un pitinfo (Tindie ou Lectronz) aussi.

      1 Reply Last reply
      • tmsT Offline
        tmsT Offline
        tms
        wrote on last edited by
        #3

        Oui j'ai vu ça 🙂 j'ai laissé une petite note dans le README, mais c'est un domaine que j'ai très peu touché jusqu'ici !

        Pour l'instant, je suis pleinement satisfait du couple rpi zero / pitinfo, j'ai tout installé dans mon tableau électrique avec une petite alim rail din 5V et un support rail din pour le rpi aussi, c'est tout propre et ça tourne 24h24 sans problème.

        1 Reply Last reply
        • CharlesC Offline
          CharlesC Offline
          Charles
          wrote on last edited by
          #4

          Canon, en plus t'as un broker MQTT du coup 🙂

          Par ailleurs je ne sais pas si tou connais balena ca te permet de générer des images RPI avec balenaos (systeme protégé avec peu d'usure de la SD card).
          Comme tu maitrises docker ça peut avoir un sens d'avoir une image toute faite pour les users. Il choisi l'image, sa cible (rasp ou autre) et hop ca récup une image SD dans laquelle tout est pret y compris la config docker qui s'installe au 1er boot et se met à jour qd besoin toute seule
          C'est super souple et tu peux prendre la main à distance sur ton rasp. C'est gratuit jusque 10 devices c'est vraiment bien, Regarde si tu peux tu vas adorer 🙂

          1 Reply Last reply
          • tmsT Offline
            tmsT Offline
            tms
            wrote on last edited by
            #5

            Je fais tourner le broker sur un autre RPI, depuis lequel j'exploite les données avec la stack InfluxDB, tout dockerisé là aussi. C'est disponible sur un autre repo, mais il mériterait un README un peu plus fourni : https://github.com/tms0/energy-monitoring

            Je connaissais pas du tout balena, en plus je vois qu'ils ont une version open source en beta, je testerais ça à l'occasion, je commence à avoir une petite flotte de RPI mine de rien !

            N 1 Reply Last reply
            • tmsT tms

              Je fais tourner le broker sur un autre RPI, depuis lequel j'exploite les données avec la stack InfluxDB, tout dockerisé là aussi. C'est disponible sur un autre repo, mais il mériterait un README un peu plus fourni : https://github.com/tms0/energy-monitoring

              Je connaissais pas du tout balena, en plus je vois qu'ils ont une version open source en beta, je testerais ça à l'occasion, je commence à avoir une petite flotte de RPI mine de rien !

              N Offline
              N Offline
              Nalexdouze
              wrote on last edited by
              #6

              Bonjour @tms ,

              J'utilise ton flux Node-RED depuis quelques temps mais il me manquait des infos 😉
              J'ai donc modifié la fonction et ajouter une variable jeedom pour que le JSON soit interpréter par l'extension téléinfo de Jeedom

              Pour le contexte j'ai un dongle Micro Teleinfo V3.0 sur la BananaPi dans mon garage sur lequel tourne une instance Node-RED et plutôt que de partager le port USB à ma VM Jeedom j'ai préféré mettre un place un flux qui publie le TIC en MQTT.

              function computeChecksum(chars) {
                  // Calculer le checksum en additionnant les codes ASCII des caractères et en appliquant le masque
                  var sum = Array.from(chars).reduce((acc, curr) => acc + curr.charCodeAt(), 0);
                  return String.fromCharCode((sum & 0x3F) + 0x20); // Conversion en caractère ASCII
              }
              
              // Définir si le formatage pour Jeedom doit être appliqué
              var jeedom = true; // Passe à false si le formatage n'est pas nécessaire
              
              // Initialiser le payload
              var payload = {
                  timestamp: new Date().getTime() // Ajouter un horodatage au payload
              };
              
              // Supprimer les caractères de début/fin de trame
              var lines = msg.payload.toString().replace("\u0002\n", "").replace("\r\u0003", "");
              
              // Traiter chaque ligne séparément
              lines.split("\r\n").forEach(line => {
                  node.debug(`Ligne à décoder : ${line}`);
              
                  // Découper la ligne selon le format attendu : étiquette, horodatage, valeur, checksum
                  var groups = line.match(/^(.+?)\t(?:([\w\d]+)\t)?(.+)\t(.)$/i);
                  if (groups === null) {
                      node.warn(`Impossible de décoder la ligne '${line}'`);
                  } else {
                      var etiquette = groups[1].trim(); // Nom du champ
                      var valeur = groups[3].trim();   // Valeur associée
                      var checksum = groups[4].trim(); // Checksum reçu
              
                      // Calculer le checksum attendu
                      var computedChecksum = computeChecksum(line.slice(0, -1)); // Exclure le checksum reçu
                      if (computedChecksum !== checksum) {
                          node.warn(`Checksum invalide pour '${line}'. Attendu : '${computedChecksum}', reçu : '${checksum}'`);
                          return; // Ignorer cette ligne si le checksum est invalide
                      }
              
                      // Si l'étiquette est STGE, traiter la valeur comme un champ binaire
                      if (etiquette === 'STGE') {
                          let stgeValue = parseInt(valeur, 16).toString(2).padStart(32, '0'); // Compléter à 32 bits
              
                          // Décoder chaque groupe de bits avec les fonctions équivalentes
                          payload['STGE01'] = stgeValue[31] === '1' ? 'Ouvert' : 'Ferme';
                          payload['STGE02'] = switchMot02(parseInt(stgeValue.slice(28, 31), 2));
                          payload['STGE03'] = stgeValue[27] === '1' ? 'Ouvert' : 'Ferme';
                          payload['STGE04'] = switchMot04(parseInt(stgeValue[26], 2));
                          payload['STGE05'] = switchMot05(parseInt(stgeValue[25], 2));
                          payload['STGE06'] = switchMot06(parseInt(stgeValue[24], 2));
                          payload['STGE07'] = switchMot07(parseInt(stgeValue[23], 2));
                          payload['STGE08'] = switchMot08(parseInt(stgeValue[22], 2));
                          payload['STGE09'] = switchMot09(parseInt(stgeValue.slice(20, 22), 2));
                          payload['STGE10'] = switchMot10(parseInt(stgeValue.slice(18, 20), 2));
                          payload['STGE11'] = switchMot11(parseInt(stgeValue[17], 2));
                          payload['STGE12'] = switchMot12(parseInt(stgeValue[16], 2));
                          payload['STGE13'] = switchMot13(parseInt(stgeValue[15], 2));
                          payload['STGE14'] = switchMot14(parseInt(stgeValue.slice(13, 15), 2));
                          payload['STGE15'] = switchMot15(parseInt(stgeValue.slice(11, 13), 2));
                          payload['STGE16'] = switchMot16(parseInt(stgeValue[10], 2));
                          payload['STGE17'] = switchMot17(parseInt(stgeValue.slice(8, 10), 2));
                          payload['STGE18'] = switchMot18(parseInt(stgeValue.slice(6, 8), 2));
                          payload['STGE19'] = switchMot19(parseInt(stgeValue.slice(4, 6), 2));
                          payload['STGE20'] = switchMot20(parseInt(stgeValue.slice(2, 4), 2));
                      } else {
                          // Traitement normal pour les autres étiquettes
                          if (valeur.match(/^\d+$/)) {
                              valeur = parseInt(valeur);
                          }
                          payload[etiquette] = valeur;
                      }
                  }
              });
              
              // Fonctions de traduction (équivalents des switch_motXX en Python)
              function switchMot01(argument) {
                  const map = {
                      0: "Ferme",
                      1: "Ouvert",
                  };
                  return map[argument] || "Invalide";
              }
              
              function switchMot02(argument) {
                  const map = {
                      0: "Ferme",
                      1: "Ouvert sur surpuissance",
                      2: "Ouvert sur surtension",
                      3: "Ouvert sur delestage",
                      4: "Ouvert sur ordre CPL ou Euridis",
                      5: "Ouvert sur surchauffe avec I > Imax",
                      6: "Ouvert sur surchauffe avec I < Imax",
                  };
                  return map[argument] || "Invalide";
              }
              
              function switchMot03(argument) {
                  const map = {
                      0: "Ferme",
                      1: "Ouvert",
                  };
                  return map[argument] || "Invalide";
              }
              
              function switchMot04(argument) {
                  const map = {
                      0: "Toujours à 0",
                      1: "Anormal",
                  };
                  return map[argument] || "Invalide";
              }
              
              function switchMot05(argument) {
                  const map = {
                      0: "Pas de surtension",
                      1: "Surtension",
                  };
                  return map[argument] || "Invalide";
              }
              
              function switchMot06(argument) {
                  const map = {
                      0: "Pas de dépassement",
                      1: "Dépassement en cours",
                  };
                  return map[argument] || "Invalide";
              }
              
              function switchMot07(argument) {
                  const map = {
                      0: "Consommateur",
                      1: "Producteur",
                  };
                  return map[argument] || "Invalide";
              }
              
              function switchMot08(argument) {
                  const map = {
                      0: "Énergie active positive",
                      1: "Énergie active négative",
                  };
                  return map[argument] || "Invalide";
              }
              
              function switchMot09(argument) {
                  const map = {
                      0: "Énergie ventilée sur Index 1",
                      1: "Énergie ventilée sur Index 2",
                      2: "Énergie ventilée sur Index 3",
                      3: "Énergie ventilée sur Index 4",
                      4: "Énergie ventilée sur Index 5",
                      5: "Énergie ventilée sur Index 6",
                      6: "Énergie ventilée sur Index 7",
                      7: "Énergie ventilée sur Index 8",
                      8: "Énergie ventilée sur Index 9",
                      9: "Énergie ventilée sur Index 10",
                  };
                  return map[argument] || "Invalide";
              }
              
              function switchMot10(argument) {
                  const map = {
                      0: "Énergie ventilée sur Index 1",
                      1: "Énergie ventilée sur Index 2",
                      2: "Énergie ventilée sur Index 3",
                      3: "Énergie ventilée sur Index 4",
                  };
                  return map[argument] || "Invalide";
              }
              
              function switchMot11(argument) {
                  const map = {
                      0: "Horloge correcte",
                      1: "Horloge en mode dégradé",
                  };
                  return map[argument] || "Invalide";
              }
              
              function switchMot12(argument) {
                  const map = {
                      0: "Mode Historique",
                      1: "Mode Standard",
                  };
                  return map[argument] || "Invalide";
              }
              
              function switchMot13(argument) {
                  const map = {
                      0: "Non utilisé",
                      1: "Non utilisé",
                  };
                  return map[argument] || "Invalide";
              }
              
              function switchMot14(argument) {
                  const map = {
                      0: "Désactivée",
                      1: "Activée sans sécurité",
                      2: "Invalide",
                      3: "Activée avec sécurité",
                  };
                  return map[argument] || "Invalide";
              }
              
              function switchMot15(argument) {
                  const map = {
                      0: "New/Unlock",
                      1: "New/Lock",
                      2: "Registered",
                      3: "Invalide",
                  };
                  return map[argument] || "Invalide";
              }
              
              function switchMot16(argument) {
                  const map = {
                      0: "Compteur non synchronisé",
                      1: "Compteur synchronisé",
                  };
                  return map[argument] || "Invalide";
              }
              
              function switchMot17(argument) {
                  const map = {
                      0: "Pas d'annonce",
                      1: "Bleu",
                      2: "Blanc",
                      3: "Rouge",
                  };
                  return map[argument] || "Invalide";
              }
              
              function switchMot18(argument) {
                  const map = {
                      0: "Pas d'annonce",
                      1: "Bleu",
                      2: "Blanc",
                      3: "Rouge",
                  };
                  return map[argument] || "Invalide";
              }
              
              function switchMot19(argument) {
                  const map = {
                      0: "Pas de préavis en cours",
                      1: "Préavis PM1 en cours",
                      2: "Préavis PM2 en cours",
                      3: "Préavis PM3 en cours",
                  };
                  return map[argument] || "Invalide";
              }
              
              function switchMot20(argument) {
                  const map = {
                      0: "Pas de pointe mobile",
                      1: "PM1 en cours",
                      2: "PM2 en cours",
                      3: "PM3 en cours",
                  };
                  return map[argument] || "Invalide";
              }
              
              // Ajouter le formatage pour Jeedom si nécessaire
              if (jeedom) {
                  msg.payload = '{"TIC":' + JSON.stringify(payload) + '}';
                  msg.topic = 'teleinfo/TIC';
              } else {
                  msg.payload = payload;
              }
              
              return msg;
              
              

              C'est certainement perfectible en ajoutant par exemple un noeud réglages qui regrouperai les variables 😛

              Cordialement
              Alexis

              CharlesC 1 Reply Last reply
              • N Nalexdouze

                Bonjour @tms ,

                J'utilise ton flux Node-RED depuis quelques temps mais il me manquait des infos 😉
                J'ai donc modifié la fonction et ajouter une variable jeedom pour que le JSON soit interpréter par l'extension téléinfo de Jeedom

                Pour le contexte j'ai un dongle Micro Teleinfo V3.0 sur la BananaPi dans mon garage sur lequel tourne une instance Node-RED et plutôt que de partager le port USB à ma VM Jeedom j'ai préféré mettre un place un flux qui publie le TIC en MQTT.

                function computeChecksum(chars) {
                    // Calculer le checksum en additionnant les codes ASCII des caractères et en appliquant le masque
                    var sum = Array.from(chars).reduce((acc, curr) => acc + curr.charCodeAt(), 0);
                    return String.fromCharCode((sum & 0x3F) + 0x20); // Conversion en caractère ASCII
                }
                
                // Définir si le formatage pour Jeedom doit être appliqué
                var jeedom = true; // Passe à false si le formatage n'est pas nécessaire
                
                // Initialiser le payload
                var payload = {
                    timestamp: new Date().getTime() // Ajouter un horodatage au payload
                };
                
                // Supprimer les caractères de début/fin de trame
                var lines = msg.payload.toString().replace("\u0002\n", "").replace("\r\u0003", "");
                
                // Traiter chaque ligne séparément
                lines.split("\r\n").forEach(line => {
                    node.debug(`Ligne à décoder : ${line}`);
                
                    // Découper la ligne selon le format attendu : étiquette, horodatage, valeur, checksum
                    var groups = line.match(/^(.+?)\t(?:([\w\d]+)\t)?(.+)\t(.)$/i);
                    if (groups === null) {
                        node.warn(`Impossible de décoder la ligne '${line}'`);
                    } else {
                        var etiquette = groups[1].trim(); // Nom du champ
                        var valeur = groups[3].trim();   // Valeur associée
                        var checksum = groups[4].trim(); // Checksum reçu
                
                        // Calculer le checksum attendu
                        var computedChecksum = computeChecksum(line.slice(0, -1)); // Exclure le checksum reçu
                        if (computedChecksum !== checksum) {
                            node.warn(`Checksum invalide pour '${line}'. Attendu : '${computedChecksum}', reçu : '${checksum}'`);
                            return; // Ignorer cette ligne si le checksum est invalide
                        }
                
                        // Si l'étiquette est STGE, traiter la valeur comme un champ binaire
                        if (etiquette === 'STGE') {
                            let stgeValue = parseInt(valeur, 16).toString(2).padStart(32, '0'); // Compléter à 32 bits
                
                            // Décoder chaque groupe de bits avec les fonctions équivalentes
                            payload['STGE01'] = stgeValue[31] === '1' ? 'Ouvert' : 'Ferme';
                            payload['STGE02'] = switchMot02(parseInt(stgeValue.slice(28, 31), 2));
                            payload['STGE03'] = stgeValue[27] === '1' ? 'Ouvert' : 'Ferme';
                            payload['STGE04'] = switchMot04(parseInt(stgeValue[26], 2));
                            payload['STGE05'] = switchMot05(parseInt(stgeValue[25], 2));
                            payload['STGE06'] = switchMot06(parseInt(stgeValue[24], 2));
                            payload['STGE07'] = switchMot07(parseInt(stgeValue[23], 2));
                            payload['STGE08'] = switchMot08(parseInt(stgeValue[22], 2));
                            payload['STGE09'] = switchMot09(parseInt(stgeValue.slice(20, 22), 2));
                            payload['STGE10'] = switchMot10(parseInt(stgeValue.slice(18, 20), 2));
                            payload['STGE11'] = switchMot11(parseInt(stgeValue[17], 2));
                            payload['STGE12'] = switchMot12(parseInt(stgeValue[16], 2));
                            payload['STGE13'] = switchMot13(parseInt(stgeValue[15], 2));
                            payload['STGE14'] = switchMot14(parseInt(stgeValue.slice(13, 15), 2));
                            payload['STGE15'] = switchMot15(parseInt(stgeValue.slice(11, 13), 2));
                            payload['STGE16'] = switchMot16(parseInt(stgeValue[10], 2));
                            payload['STGE17'] = switchMot17(parseInt(stgeValue.slice(8, 10), 2));
                            payload['STGE18'] = switchMot18(parseInt(stgeValue.slice(6, 8), 2));
                            payload['STGE19'] = switchMot19(parseInt(stgeValue.slice(4, 6), 2));
                            payload['STGE20'] = switchMot20(parseInt(stgeValue.slice(2, 4), 2));
                        } else {
                            // Traitement normal pour les autres étiquettes
                            if (valeur.match(/^\d+$/)) {
                                valeur = parseInt(valeur);
                            }
                            payload[etiquette] = valeur;
                        }
                    }
                });
                
                // Fonctions de traduction (équivalents des switch_motXX en Python)
                function switchMot01(argument) {
                    const map = {
                        0: "Ferme",
                        1: "Ouvert",
                    };
                    return map[argument] || "Invalide";
                }
                
                function switchMot02(argument) {
                    const map = {
                        0: "Ferme",
                        1: "Ouvert sur surpuissance",
                        2: "Ouvert sur surtension",
                        3: "Ouvert sur delestage",
                        4: "Ouvert sur ordre CPL ou Euridis",
                        5: "Ouvert sur surchauffe avec I > Imax",
                        6: "Ouvert sur surchauffe avec I < Imax",
                    };
                    return map[argument] || "Invalide";
                }
                
                function switchMot03(argument) {
                    const map = {
                        0: "Ferme",
                        1: "Ouvert",
                    };
                    return map[argument] || "Invalide";
                }
                
                function switchMot04(argument) {
                    const map = {
                        0: "Toujours à 0",
                        1: "Anormal",
                    };
                    return map[argument] || "Invalide";
                }
                
                function switchMot05(argument) {
                    const map = {
                        0: "Pas de surtension",
                        1: "Surtension",
                    };
                    return map[argument] || "Invalide";
                }
                
                function switchMot06(argument) {
                    const map = {
                        0: "Pas de dépassement",
                        1: "Dépassement en cours",
                    };
                    return map[argument] || "Invalide";
                }
                
                function switchMot07(argument) {
                    const map = {
                        0: "Consommateur",
                        1: "Producteur",
                    };
                    return map[argument] || "Invalide";
                }
                
                function switchMot08(argument) {
                    const map = {
                        0: "Énergie active positive",
                        1: "Énergie active négative",
                    };
                    return map[argument] || "Invalide";
                }
                
                function switchMot09(argument) {
                    const map = {
                        0: "Énergie ventilée sur Index 1",
                        1: "Énergie ventilée sur Index 2",
                        2: "Énergie ventilée sur Index 3",
                        3: "Énergie ventilée sur Index 4",
                        4: "Énergie ventilée sur Index 5",
                        5: "Énergie ventilée sur Index 6",
                        6: "Énergie ventilée sur Index 7",
                        7: "Énergie ventilée sur Index 8",
                        8: "Énergie ventilée sur Index 9",
                        9: "Énergie ventilée sur Index 10",
                    };
                    return map[argument] || "Invalide";
                }
                
                function switchMot10(argument) {
                    const map = {
                        0: "Énergie ventilée sur Index 1",
                        1: "Énergie ventilée sur Index 2",
                        2: "Énergie ventilée sur Index 3",
                        3: "Énergie ventilée sur Index 4",
                    };
                    return map[argument] || "Invalide";
                }
                
                function switchMot11(argument) {
                    const map = {
                        0: "Horloge correcte",
                        1: "Horloge en mode dégradé",
                    };
                    return map[argument] || "Invalide";
                }
                
                function switchMot12(argument) {
                    const map = {
                        0: "Mode Historique",
                        1: "Mode Standard",
                    };
                    return map[argument] || "Invalide";
                }
                
                function switchMot13(argument) {
                    const map = {
                        0: "Non utilisé",
                        1: "Non utilisé",
                    };
                    return map[argument] || "Invalide";
                }
                
                function switchMot14(argument) {
                    const map = {
                        0: "Désactivée",
                        1: "Activée sans sécurité",
                        2: "Invalide",
                        3: "Activée avec sécurité",
                    };
                    return map[argument] || "Invalide";
                }
                
                function switchMot15(argument) {
                    const map = {
                        0: "New/Unlock",
                        1: "New/Lock",
                        2: "Registered",
                        3: "Invalide",
                    };
                    return map[argument] || "Invalide";
                }
                
                function switchMot16(argument) {
                    const map = {
                        0: "Compteur non synchronisé",
                        1: "Compteur synchronisé",
                    };
                    return map[argument] || "Invalide";
                }
                
                function switchMot17(argument) {
                    const map = {
                        0: "Pas d'annonce",
                        1: "Bleu",
                        2: "Blanc",
                        3: "Rouge",
                    };
                    return map[argument] || "Invalide";
                }
                
                function switchMot18(argument) {
                    const map = {
                        0: "Pas d'annonce",
                        1: "Bleu",
                        2: "Blanc",
                        3: "Rouge",
                    };
                    return map[argument] || "Invalide";
                }
                
                function switchMot19(argument) {
                    const map = {
                        0: "Pas de préavis en cours",
                        1: "Préavis PM1 en cours",
                        2: "Préavis PM2 en cours",
                        3: "Préavis PM3 en cours",
                    };
                    return map[argument] || "Invalide";
                }
                
                function switchMot20(argument) {
                    const map = {
                        0: "Pas de pointe mobile",
                        1: "PM1 en cours",
                        2: "PM2 en cours",
                        3: "PM3 en cours",
                    };
                    return map[argument] || "Invalide";
                }
                
                // Ajouter le formatage pour Jeedom si nécessaire
                if (jeedom) {
                    msg.payload = '{"TIC":' + JSON.stringify(payload) + '}';
                    msg.topic = 'teleinfo/TIC';
                } else {
                    msg.payload = payload;
                }
                
                return msg;
                
                

                C'est certainement perfectible en ajoutant par exemple un noeud réglages qui regrouperai les variables 😛

                Cordialement
                Alexis

                CharlesC Offline
                CharlesC Offline
                Charles
                wrote on last edited by
                #7

                @Nalexdouze Merci pour le partage, c'est effectivement la meilleure solution, en plus tu peux modifier ou dispatcher tes flux vers plusieurs solutions si besoin. J'aurais fait pareil 🙂

                1 Reply Last reply

                Hello! It looks like you're interested in this conversation, but you don't have an account yet.

                Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.

                With your input, this post could be even better 💗

                Register Login
                Reply
                • Reply as topic
                Log in to reply
                • Oldest to Newest
                • Newest to Oldest
                • Most Votes


                0

                Online

                5.8k

                Users

                565

                Topics

                5.3k

                Posts

                Top Topics

                Popular Tags

                teleinfo
                25 topics
                arduino
                19 topics
                remora
                16 topics
                esp8266
                10 topics
                arduipi
                10 topics
                raspberry
                8 topics
                wifinfo
                7 topics
                broadcast
                7 topics
                Copyright © 2022 Charles-Henri Hallard | Return to blog page | Powered by NodeBB
                • Login

                • Don't have an account? Register

                • Login or register to search.
                • First post
                  Last post
                0
                • Blog
                • Categories
                • Recent
                • Tags
                • Popular
                • Users
                • Groups