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édentes Révision précédente
Prochaine révision
Révision précédente
Prochaine révision Les deux révisions suivantes
mesh_et_mqtt [2020/03/25 17:44]
BILLARD
mesh_et_mqtt [2020/04/06 15:04]
BILLARD
Ligne 2: Ligne 2:
  
 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. 
 + 
 + 
 + 
 + 
 + 
 +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 113:
 {{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}}
mesh_et_mqtt.txt · Dernière modification: 2020/04/09 16:36 par BILLARD