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
Prochaine révisionLes deux révisions suivantes
mesh_et_mqtt [2020/03/25 16:45] BILLARDmesh_et_mqtt [2020/06/07 11:25] – [Réseau MESH avec des ESP et MQtt] 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 :
 +
 +{{: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 :
Ligne 10: Ligne 16:
  
 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 =====+{{ ::mqtt_medh:flows.zip |}} 
 + 
 +{{::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. 
 + 
 +{{::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]]
Ligne 74: Ligne 127:
 {{tag>nodejs node-red développement mqtt iOT bj mesh}} {{tag>nodejs node-red développement mqtt iOT bj mesh}}
  
-===== Config du RaspberryPI  ===== 
  
-Doc ici pour la mise en place du hotspot WIFI [[http://www.octetmalin.net/linux/tutoriels/raspbian-installation-d-un-point-d-acces-wifi.php#configurer-des-adresses-ip-fixe-dhcpcd|Ici]]  
  
-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]]+===== 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 %uOffset = %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}} {{tag>nodejs node-red développement mqtt iOT bj}}
mesh_et_mqtt.txt · Dernière modification : 2020/10/29 13:58 de serge