Outils pour utilisateurs

Outils du site


mesh_et_mqtt

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentesRévision précédente
Prochaine révision
Révision précédente
mesh_et_mqtt [2020/03/21 08:38] BILLARDmesh_et_mqtt [2020/10/29 13:58] (Version actuelle) – ↷ Liens modifiés en raison d'un déplacement. serge
Ligne 1: Ligne 1:
-===== Réseau MESH avec des ESP et MQtt =====+====== Réseau MESH avec des ESP et MQtt ======
  
 L'objectif était de mettre en œuvre les informations contenues dans un article paru dans HACKABLE Magazine [[https://www.hackable.fr/?p=1142|27]] dans le contexte de l'internet des objets. L'objectif était de mettre en œuvre les informations contenues dans un article paru dans HACKABLE Magazine [[https://www.hackable.fr/?p=1142|27]] dans le contexte de l'internet des objets.
 +
 +La structure est la suivante :
 +
 +{{media_08:mesh_design_schema_principe.png?200|}}
 +
 +Choix du matériel.
  
 Pour ce faire j'ai opté pour l'utilisation de ce type de carte : Pour ce faire j'ai opté pour l'utilisation de ce type de carte :
 //ESP8266 ESP-01 Module de relais WiFi 2 canaux Module de relais 2 canaux pour contrôleur d'application de téléphone intelligent IOT// disponible en chine . //ESP8266 ESP-01 Module de relais WiFi 2 canaux Module de relais 2 canaux pour contrôleur d'application de téléphone intelligent IOT// disponible en chine .
-{{::esp2relaiscarte.jpg?200|}}+{{media_03:esp2relaiscarte.jpg?200|}}
  
 Le programmateur utilisé est celui-ci : Le programmateur utilisé est celui-ci :
  
 CH340 USB à ESP8266 série ESP-01 ESP-01S ESP01 ESP01S sans fil Wifi développement Module de carte pour Arduino programmeur adaptateur CH340 USB à ESP8266 série ESP-01 ESP-01S ESP01 ESP01S sans fil Wifi développement Module de carte pour Arduino programmeur adaptateur
 +
 +Une carte Raspberry-PI ancien modèle avec une carte WI-FI sur Port USB -- Système Raspbian BUSTER.
  
 ===== La carte ESP + Relais ===== ===== La carte ESP + Relais =====
Ligne 31: Ligne 39:
 Ce qui au niveau du code engendre ceci dans le setup() Ce qui au niveau du code engendre ceci dans le setup()
  
 +<code>
 void setup() { void setup() {
   delay(5000);   delay(5000);
   //INIT de la liaison série pour le controle des relais   //INIT de la liaison série pour le controle des relais
   Serial.begin(115200, SERIAL_8N1, SERIAL_TX_ONLY);   Serial.begin(115200, SERIAL_8N1, SERIAL_TX_ONLY);
 +</code>  
      
 et pour la commande des relais là ou vous souhaitez dans le code, ici la fermeture du relais 1 : et pour la commande des relais là ou vous souhaitez dans le code, ici la fermeture du relais 1 :
 +<code>
     Serial.write(0xA0);     Serial.write(0xA0);
     Serial.write(0x01);     Serial.write(0x01);
     Serial.write(0x01);     Serial.write(0x01);
     Serial.write(0xA2);     Serial.write(0xA2);
 +</code>
  
 ===== Le MESH ===== ===== Le MESH =====
  
-=== La librairie Painless mesh === +=== Le principe du  mesh === 
-Disponible ici : [[https://gitlab.com/gmag11/painlessMesh]]+ 
 +D'après wikipédia : [[https://fr.wikipedia.org/wiki/Topologie_mesh|Réseau MESH]] 
 + 
 +Le réseau maillé1 (ou maillage en réseau2) est une topologie de réseau (filaire et sans fil) où tous les hôtes sont connectés pair à pair sans hiérarchie centrale, formant ainsi une structure en forme de filet. 
 + 
 +=== Les librairies pour ESP8266 === 
 +Pour le MESH : [[https://gitlab.com/gmag11/painlessMesh|PainlessMesh]] 
 + 
 +La gestion de la communication MQTT : [[http://example.com|Lien externe|PubSubClient]] 
 + 
 +Le gestionnaire de taches [[https://github.com/arkhipenko/TaskScheduler|TaskScheduler]] 
  
-=== Premiers usages === 
  
 ===== Le MQtt ===== ===== Le MQtt =====
Ligne 55: Ligne 77:
 [[protocole_mqtt|Le protocole MQTT]] [[protocole_mqtt|Le protocole MQTT]]
  
-=== Installation des outils MOSQUITTO  ===+===== APPLICATION =====
  
-Ici les éléments d'installation de MOSQUITTO : +=== Configuration du RaspberryPI   ===
-[[https://ressources.labomedia.org/corinne_dadat#technologie1|Corinne Dadat]]+
  
-=== Application  ===+Sur la PI installation de  
 +  * Mosquitto [[corinne_dadat#technologie1|Corinne Dadat]]  
 +  * Node-REd [[node-red|Node-Red]]  
 +  * HostApd pour le wifi [[http://www.octetmalin.net/linux/tutoriels/raspbian-installation-d-un-point-d-acces-wifi.php#configurer-des-adresses-ip-fixe-dhcpcd|WIFI SPOT]] 
  
-J'ai fait le choix d'installer Mosquitto sur une Raspberry PI, qui embarquera aussi [[node-red|Node-Red]].+Notes :
  
 +Par défaut je n'ai rien modifié dans la configuration de mosquitto.
  
-===== La passerelle MQTT <--> MESH =====+Ajout du dashboard dans Node-Red.
  
 +Exemple de flow pour Node-Red  
  
-===== NODE-RED =====+{{ pliboo-02:flows.zip |}} 
 + 
 +{{media_07:le_diagramme_node-red_de_test.jpg?400|}}{{ :visu_diagramme_node-red_de_test.jpg?400|}} 
 + 
 +Le fichier json pour Node-Red. 
 + 
 +Un exemple de bouton poussoir Node-red avec changement de couleur et init à la mise sous-tension.  
 + 
 +Illustration de boutons dynamique. 
 + 
 +{{media_04:bouton_poussoir_node_red.png?direct&200|}} 
 + 
 +**Reste à gérer les interaction entre les boutons, dans le cas d'une carte disposant de trois boutons R1/R2/R1 et 2 et la création d'un subflow paramétrable. Aide bienvenue -- MERCI** 
 + 
 +<code> 
 +[{"id":"5e5c2e88.71aea","type":"ui_button","z":"d68fea03.31b0c8","name":"Bouton Poussoir","group":"65e2fa0d.4fb70c","order":0,"width":0,"height":0,"passthru":false,"label":"{{msg.state}}","tooltip":"","color":"","bgcolor":"{{msg.background}}","icon":"","payload":"true","payloadType":"bool","topic":"","x":450,"y":280,"wires":[["d450f8d3.7b7b1"]]},{"id":"7e81c5e9.f34c3c","type":"inject","z":"d68fea03.31b0c8","name":"","topic":"","payload":"reset","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":400,"y":220,"wires":[["d450f8d3.7b7b1"]]},{"id":"d450f8d3.7b7b1","type":"function","z":"d68fea03.31b0c8","name":"gestion BP","func":"\nvar state=context.get(\"state\") || \"OFF\";\n\nvar color '';\nif (msg.payload===\"reset\") {\n    state=\"OFF\"\n    color = 'red';\n    txt = \"OFF\"\n    msg.state=\"ON\";\n}\nelse{\n\nif ((msg.payload===true) && (state==\"OFF\")) {\n    state=!state;\n    context.set(\"state\",\"ON\") ;\n    msg.payload=\"RON#1\";\n    color = \"green\";\n    txt = \"ON\"\n    msg.state=\"OFF\";\n\n} \nelse {\n    msg.payload=\"ROFF#1\";\n    context.set(\"state\",\"OFF\") ;\n    color = 'red';\n    txt = \"OFF\"\n    msg.state=\"ON\";\n}\n}\n\n node.status({\n    \tfill : color,\n    \tshape : 'dot',\n    \ttext : txt\n });\nnode.send(msg);\nmsg.background=color;\n\n\n\nreturn msg;\n","outputs":1,"noerr":0,"x":690,"y":280,"wires":[["5e5c2e88.71aea"]]},{"id":"65e2fa0d.4fb70c","type":"ui_group","z":"","name":"Carte 1 V2","tab":"3939b51c.a31712","disp":true,"width":"6","collapse":true},{"id":"3939b51c.a31712","type":"ui_tab","z":"","name":"Home","icon":"dashboard","disabled":false,"hidden":false}] 
 +</code> 
 + 
 + 
 + 
 + 
 + 
 + 
 + 
 +La partie iptable n'est pas mise en oeuvre du fait d'un changement dans Buster [[https://www.debian.org/releases/jessie/mips64el/release-notes/ch-whats-new.fr.html#nftables.|iptables vers nftables]] 
 + 
 + 
 +===== Autres ressources =====
  
 Installation de node-red sur Raspbian [[https://nodered.org/docs/getting-started/raspberrypi|ici]] Installation de node-red sur Raspbian [[https://nodered.org/docs/getting-started/raspberrypi|ici]]
  
 {{tag>nodejs node-red développement mqtt iOT bj mesh}} {{tag>nodejs node-red développement mqtt iOT bj mesh}}
 +
 +
 +
 +===== La passerelle MQTT <--> MESH =====
 +
 +Réalisée avec un ESP8266. 
 +Doit se connecter au MESH et au Broker pour assurer la passerelle.
 +<code>
 +//*****************************************************************************************************
 +// FICHIER DE FONCTIONNEMENT POUR ESP8266 COMME PONT
 +//
 +//    MQTT BROKER <---> MESH
 +//           
 +//    François-Marie BILLARD
 +//
 +//    Test à faire 
 +//        envoyer un message depuis BROKER (via NODE- RED) vers le MESH OK le 2 avril 2020
 +//
 +//        envoyer un message depuis MESH vers BROKER : OK le 2 avril 2020
 +//
 +//*****************************************************************************************************
 +
 +#include <Arduino.h>
 +#include <painlessMesh.h>
 +#include <PubSubClient.h>
 +#include <WiFiClient.h>
 +
 +#define   MESH_PREFIX     "meshexoposition"
 +#define   MESH_PASSWORD   "passwordmesh"
 +#define   MESH_PORT       5555
 +
 +#define   STATION_SSID     "EXPOSITION"
 +#define   STATION_PASSWORD "1234567890"
 +
 +#define HOSTNAME "raspberrypi"
 +
 +// Prototypes
 +void receivedCallback( const uint32_t &from, const String &msg );
 +void mqttCallback(char* topic, byte* payload, unsigned int length);
 +
 +IPAddress getlocalIP();
 +
 +IPAddress myIP(0,0,0,0);
 +IPAddress mqttBroker(192, 168, 50, 15);
 +boolean ErreurBroker = true;
 +
 +
 +painlessMesh  mesh;
 +WiFiClient wifiClient;
 +PubSubClient mqttClient(mqttBroker, 1883, mqttCallback, wifiClient);
 +
 +void setup() {
 +  Serial.begin(115200);
 +
 +  mesh.setDebugMsgTypes( ERROR | STARTUP | CONNECTION );  // set before init() so that you can see startup messages
 +
 +  // Channel set to 6. Make sure to use the same channel for your mesh and for you other
 +  // network (STATION_SSID)
 +  mesh.init( MESH_PREFIX, MESH_PASSWORD, MESH_PORT, WIFI_AP_STA, 6 );
 +  mesh.onReceive(&receivedCallback);
 +
 +  mesh.stationManual(STATION_SSID, STATION_PASSWORD);
 +  mesh.setHostname(HOSTNAME);
 +
 +  // Bridge node, should (in most cases) be a root node. See [the wiki](https://gitlab.com/painlessMesh/painlessMesh/wikis/Possible-challenges-in-mesh-formation) for some background
 +  mesh.setRoot(true);
 +  // This node and all other nodes should ideally know the mesh contains a root, so call this on all nodes
 +  mesh.setContainsRoot(true);
 +}
 +
 +void loop() {
 +  mesh.update();
 +  mqttClient.loop();
 +
 +  
 +  
 +  if (myIP != getlocalIP()) {               //pas d'adresse IP correcte
 +    myIP = getlocalIP();                    //mise a jour de l'IP locale
 +    if (!mqttClient.connected() ) {         //pas de connexion au Broker 
 +       if (mqttClient.connect("wifiClient")) {  //tentative de connexion 
 +          // si connexion établie
 +          mqttClient.publish("painlessMesh/etatBridge","1");      // envoi une information de connexion via TOPIC
 +          mqttClient.subscribe("painlessMesh/to/#");              // abonnement au TOPIC
 +          ErreurBroker= false;
 +          }
 +          else {
 +            ErreurBroker= true;
 +          }
 +      }
 +    }
 +
 +  //ajout d'une gestion de la deconnexion.
 +
 +}
 +
 +
 +//Reception depuis le MESH renvoi vers le MQTT
 +void receivedCallback( const uint32_t &from, const String &msg ) {
 +  Serial.printf("bridge: Received from %u msg=%s\n", from, msg.c_str());
 +  String topic = "painlessMesh/from/" + String(from);
 +  mqttClient.publish(topic.c_str(), msg.c_str());
 +}
 +
 +
 +//************************************************************************************
 +
 +//  Cette fonction va renvoyer sur le MESH les messages en provenance du BRIDGE
 +
 +//************************************************************************************
 +
 +void mqttCallback(char* topic, uint8_t* payload, unsigned int length) {
 +  char* cleanPayload = (char*)malloc(length+1);
 +  payload[length] = '\0';
 +  memcpy(cleanPayload, payload, length+1);
 +  String msg = String(cleanPayload);
 +  free(cleanPayload);
 +
 +  String targetStr = String(topic).substring(16);
 +
 +  if(targetStr == "gateway")
 +  {
 +    if(msg == "getNodes")
 +    { // renvoi les informations sur les noeuds connectés si 
 +      // message est envoyé au TOPIC /painlessMesh/to/gateway avec message getNodes
 +      auto nodes = mesh.getNodeList(true);
 +      String str;
 +      for (auto &&id : nodes)
 +        str += String(id) + String(" ");
 +      mqttClient.publish("painlessMesh/from/gateway", str.c_str());
 +    }
 +  }
 +  else if(targetStr == "broadcast"
 +  {
 +    mesh.sendBroadcast(msg);
 +  }
 +  else
 +  {
 +    uint32_t target = strtoul(targetStr.c_str(), NULL, 10);
 +    if(mesh.isConnected(target))
 +    {
 +      mesh.sendSingle(target, msg);
 +    }
 +    else
 +    {
 +      mqttClient.publish("painlessMesh/etatBridge", "0");
 +    }
 +  }
 +}
 +
 +IPAddress getlocalIP() {
 +  return IPAddress(mesh.getStationIP());
 +}
 +</code>
 +
 +
 +===== Noeud du MESH  =====
 +
 +Réalisée avec un ESP8266 avec deux relais dans mon cas. 
 +Doit se connecter au MESH de manière automatique.
 +
 +L'objet de la librairie PainlessMesh pour l'initialisation du MESH dans le //setup()//. Puis de la mise à jour du MESH dans le //loop()//, via mesh.update.
 +
 +La fonction **receivedCallback** est appelé en cas de reception d'un message en provenance du MESH.
 +
 +L'utilisation de l'ordonnanceur de tâches pour la gestion des opérations d'envoi des messages et de mise à jour des relais dans le //setup()// et son appel dans le //loop()//   userScheduler.execute();
 +
 +
 + 
 + 
 +<code>
 +//************************************************************
 +// Exemple d'usage de la librairie PainlessMESH
 +// François-Marie BILLARD
 +//
 +//  Le 25 MArs 2020
 +//
 +// 1. Mesh sur le cana 6
 +// 2. La commande des relais doit être du type 
 +//    RON + chiffre : Allume en fonction des données ci-dessous sans extinction des autres
 +//    ROFF + chiffre : Eteint en fonction des données ci-dessous sans extinction des autres
 +//    RONA : Allume tous les relais chiffrés
 +//    ROFFA : Eteint tous les relais chiffrés
 +//
 +//  suivit d'un chiffre qui donne les relais actifs sous forme binaire
 +//      0 Tout éteint
 +//      1 Relais 1 allumé
 +//      2 Relais 2 allumé
 +//      3 Relais 1 et 2 allumés
 +//
 +//  FONCTIONNELLE le 6 AVRIL 2020
 +//
 +//************************************************************
 +#include "painlessMesh.h"
 +
 +#define   MESH_PREFIX     "meshexoposition"
 +#define   MESH_PASSWORD   "passwordmesh"
 +#define   MESH_PORT       5555
 +
 +#define   MAX_RELAIS   2
 +#define MAX_RELAIS_ON 3
 +
 +int etatRelais; // code l'état des 16 relais chaque bit un relais 0 repos, 1 actif
 +
 +
 +
 +String message; 
 +
 +Scheduler userScheduler; // Controluer 
 +painlessMesh  mesh;
 +
 +void maj_Relais() ; // Prototype pour le traitement des relais
 +
 +Task taskRelais( TASK_SECOND * 1 , TASK_FOREVER, &maj_Relais );
 +
 +void maj_Relais() {
 +   //traitement de l'état des relais du tableau etatRelais en fonction de la valeur ON
 +  //cette fonction dépend du type de carte
 +  for (int cpt=1;cpt<=MAX_RELAIS;cpt++) {
 +   
 +    if ((etatRelais & cpt) == cpt) { //Mise à un du relais
 +    switch (cpt) {
 +       case 1:          
 +          //Allumage relais 1
 +          Serial.write(0xA0);
 +          Serial.write(0x01);
 +          Serial.write(0x01);
 +          Serial.write(0xA2);
 +          delay(10);
 +        break;
 +      case 2:
 +          //Allumage relais 2
 +          Serial.write(0xA0);
 +          Serial.write(0x02);
 +          Serial.write(0x01);
 +          Serial.write(0xA3);
 +          delay(10);
 +      break;
 +    }
 +    
 +    } else { //Mise à zéro du relais
 +    switch (cpt) {
 +       case 1:
 +          //Extinction relais 1
 +          Serial.write(0xA0);
 +          Serial.write(0x01);
 +          Serial.write(0x00);
 +          Serial.write(0xA1);
 +          delay(10);
 +        break;
 +      case 2:
 +          //Extinction relais 2
 +          Serial.write(0xA0);
 +          Serial.write(0x02);
 +          Serial.write(0x00);
 +          Serial.write(0xA2);
 +          delay(10);
 +      break;
 +    }
 +    }
 +}
 +}
 +
 +
 +
 +
 +
 +// User stub
 +void sendMessage() ; // Prototype so PlatformIO doesn't complain
 +
 +
 +Task taskSendMessage( TASK_SECOND * 1 , TASK_FOREVER, &sendMessage );
 +
 +void sendMessage() {
 +  
 +  String msg = "Depuis le noeud  ";
 +  
 +  msg += mesh.getNodeId();
 +  msg += message;
 +  mesh.sendBroadcast( msg );
 +  taskSendMessage.setInterval( random( TASK_SECOND * 1, TASK_SECOND * 5 ));
 +  message="";
 +}
 +
 +// Needed for painless library
 +void receivedCallback( uint32_t from, String &msg ) {
 + //fonctionnel le 6 Avril 2020
 + boolean fin =false;
 + int cpt =0;
 + int valeur = -1;
 +
 + while (!fin){
 +  if (isDigit(msg[cpt])) {
 + 
 +    fin=true;
 +    String temp=msg.substring(cpt);
 +    valeur= temp.toInt();
 +    msg=msg.substring(0,cpt);
 +   }
 +  else {
 +    if (cpt>msg.length()) {
 +    fin =true;
 +    cpt=-1;
 +  }
 +  else {
 +        cpt++;
 +
 +  }
 + }
 +}
 + message = "recu : " + msg;
 + if (msg=="RONA") {
 +    //MAJ_Relais(MAX_RELAIS);
 +    etatRelais=MAX_RELAIS_ON;
 +    message= message + "Traite RONA";
 +  } else 
 +    if (msg=="ROFFA") {
 +        etatRelais=0;
 +        message= message + "Traite ROFFA";
 +    } else 
 +      if (msg=="RON") {
 +        etatRelais=(etatRelais | valeur );
 +        message= message + "Traite RONx";
 +      } else 
 +        if (msg=="ROFF") {
 +                    etatRelais=(etatRelais & (~valeur) );
 +                    message= message + "Traite ROFFx";
 +                    }
 +                    else if (msg=="TYPE") {
 +                    //sendMessage
 +                    message="Relais_2";
 +                    }
 +}
 +
 +void newConnectionCallback(uint32_t nodeId) {
 +    //Serial.printf("--> startHere: New Connection, nodeId = %u\n", nodeId);
 +}
 +
 +void changedConnectionCallback() {
 +  //Serial.printf("Changed connections\n");
 +}
 +
 +void nodeTimeAdjustedCallback(int32_t offset) {
 +    ////Serial.printf("Adjusted time %u. Offset = %d\n", mesh.getNodeTime(),offset);
 +}
 +
 +void setup() {
 +  //Serial.begin(115200);
 +   //INIT de la liaison série pour le controle des relais
 +  Serial.begin(115200, SERIAL_8N1, SERIAL_TX_ONLY);
 +  etatRelais = 0; //relais tous au repos
 +
 +
 +//mesh.setDebugMsgTypes( ERROR | MESH_STATUS | CONNECTION | SYNC | COMMUNICATION | GENERAL | MSG_TYPES | REMOTE ); // all types on
 +  mesh.setDebugMsgTypes( ERROR | STARTUP );  // set before init() so that you can see startup messages
 +
 +  mesh.init( MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT , WIFI_AP_STA, 6);
 +  //mesh.init( MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT );
 +  mesh.onReceive(&receivedCallback);
 +  mesh.onNewConnection(&newConnectionCallback);
 +  mesh.onChangedConnections(&changedConnectionCallback);
 +  mesh.onNodeTimeAdjusted(&nodeTimeAdjustedCallback);
 +
 +
 +  userScheduler.addTask( taskSendMessage );
 +  taskSendMessage.enable();
 +
 +  userScheduler.addTask( taskRelais );
 +  taskRelais.enable();
 +}
 +
 +void loop() {
 +   // tâche utilisateur et tâche mesh
 +  userScheduler.execute();
 +  mesh.update();
 +}
 +</code>
 +
 +{{tag>nodejs node-red développement mqtt iOT bj}}
mesh_et_mqtt.1584779901.txt.gz · Dernière modification : 2020/03/21 08:38 de BILLARD