Après les autres tests, c'est à élargir à moi de manière réussie la passerelle MQTT tellement que cela peut soutenir des appareils avec ESP-Now. Cela permet l'engagement de Boards très bon marché à base d'ESP8266. La portée est limitée alors, cependant, au domaine du réseau WLAN local. Il y a encore une autre restriction. ESPNow travaille seulement avec le canal WLAN 1. C'est pourquoi, c'est à régler nécessairement à Router pour le réseau local (par exemple, le box de Fritz) fixe sur le canal 1.
Puisque je jusqu'à présent ESP-Now le lien seulement de l'appareil à la passerelle à travaillent apportait, ESP-Now l'appareil peut livrer seulement des données des détecteurs à la passerelle cependant aucun ordre de la passerelle ne reçoit. Donc, je tenterai de résoudre ce problème et dans ce Blog au poste.
Le code contient aussi encore certaines améliorations et Fixe pour une faute à l'entrepôt de la liste d'appareils, celui-ci enfonçait alors si plus qu'un appareil était enregistré.
/* La passerelle MQTT forme une interface entre LoRa Geräten ou appareils ESP Nowe * et Cayenne MQTT Dashboards. Cela court sur ESP32 avec LoRa et display OLED * La configuration se produit du navigateur */ #include <SPI.h> #include <LoRa.h> #include "SSD1306.h" #include<Arduino.h> #include <CayenneMQTTESP32.h> #include <CayenneLPP.h> #include <WiFi.h> #include <Serveur de Web.h> #include <time.h> #include "FS.h" #include "SPIFFS.h" #include <esp_now.h> //Serveur NTP à la synchronisation de temps #define NTP_SERVER "de.pool.ntp.org" #define GMT_OFFSET_SEC 3600 #define DAYLIGHT_OFFSET_SEC 0 //Pins pour LoRa Chip #define S.S. 18 #define RST 14 #define DI0 26 //Fréquence pour LoRa Chip #define RUBAN 433175000 //Pin pour Display-Reset #define DISPLRESET 16 // #define MAXCHANNELS 256 //chiffre maximum des canaux administrés #define MAXDEVICE 32 //le nombre maximum des appareils administrés MAXCHANNELS/MAXDEVICE = 8 donne le nombre maximum de canaux par appareil #define MAXKANAL 8 //nombre maximum à des canaux par appareil //Le format Flash le système de fichier si ne se passent pas encore #define FORMAT_SPIFFS_IF_FAILED true #define APPWD "123456789" #define APCHANNEL 0 #define DEBUG 0 const Chaîne gwversion = "1.0"; //Pierres de construction pour le serveur de Web const PROGMEM char HTML_HEADER[] = "<!DOCTYPE HTML>" "<html>" "<head>" "<meta le nom = \"viewport \" content = \"width = device-width, initial scale = 1.0, maximum-scale = 1.0, user-scalable=0> \">" "<meta http-equiv = \"content-type \" content = \"le texte / html; charset=UTF-8 \">" "<title>MQTT Gateway</title>" "<style>" "body {background-color : #d2f3eb; font-family : Arial, Helvetica, Sans-Serif; Color : #000000;font-size:12pt;}" "th {background-color : #b6c0db; color : #050ed2;font-weight:lighter;font-size:10pt;}" "table, th, td {border : 1px px solid black;}" ".titel {font-size:18pt;font-weight:bold;text-align:center;}" "</style>"; const PROGMEM char HTML_HEADER_END[] = "</head>" "<body><div donne un look ='margin-left:30px; '>"; const PROGMEM char HTML_SCRIPT[] = "<script language = \"javascript \">" "function reload () {" "document.location = \"http://%s \";}" "</script>"; const PROGMEM char HTML_END_RELOAD[] = "</div><script language = \"javascript \">setTimeout (reload, 10000) ;</script></body>" "</html>"; const PROGMEM char HTML_END[] = "</body></html>"; const PROGMEM char HTML_TAB_GERAETE[] = "<table donne un look = \"width:100 les % \"><tr><th donne un look = \"width:20 les % \">ID</th><th donne un look = \"width:10 les % \">Nr.</th>" "<th donne un look = \"width:20 les % \">Kanäle</th><th donne un look = \"width:20 les % \">Name</th>" "<th donne un look = \"width:20 les % \">Letzte Daten</th><th donne un look = \"width:10 les % \">Aktion</th></tr>"; const PROGMEM char HTML_TAB_END[] = "</table>"; const PROGMEM char HTML_NEWDEVICE[] = "<div donne un look = \"margin-top:20px; \">%s le nom : <input type = \"le texte \"" le nom = \"devname \" maxlength = \"donne un look = \"width:200px \à 20 \" value = \"\" > <button le nom = \"enregistre \" value = \"les % s \">Registrieren</button></div>"; const PROGMEM char HTML_TAB_ZEILE[] = "<tr><td>%s</td><td>%i</td><td>%i jusqu'à %i</td><td>%s</td><td>%s</td><td><button le nom = \"delete \" value = \"les % i \">Löschen</button></td></tr>"; const PROGMEM char HTML_CONFIG[] = "<form method = \"la poste \"><h1>Zugangsdaten</h1><table>" "<tr><td>WLAN SSID</td><td><input type = \"le texte \" le nom = \"ssid \" value = \"les % s \" size=50 maxlen=30/></td></tr>" "<tr><td>WLAN Passwort</td><td><input type = \"le texte \" le nom = \"pwd \" value = \"les % s \" size=50 maxlen=30/></td></tr>" "<tr><td>Cayenne Benutzername</td><td><input type = \"le texte \" le nom = \"mquser \" value = \"les % s \" size=50 maxlen=40/></td></tr>" "<tr><td>Cayenne Passwort</td><td><input type = \"le texte \" le nom = \"mqpwd \" value = \"les % s \" size=50 maxlen=50/></td></tr>" "<tr><td>Cayenne le client Id</td><td><input type = \"le texte \" le nom = \"mqid \" value = \"les % s \" size=50 maxlen=40/></td></tr>" "<tr><td> </td><td><button le nom = \"save \" value=>Speichern</button></td></tr>" "</table></form></body></html>"; //Structures de données //Nouvelles la mémoire tampon struct MSG_BUF { uint8_t type; uint8_t à neuf; uint8_t données[10]; }; //Définition d'appareils struct DEVICE { uint8_t activement = 0; uint8_t sers = 0; //0=LoRa, 1=ESP-Now uint8_t id[6] = {0,0,0,0}; Chaîne nom = ""; Chaîne lisait = ""; }; //Variables globaux //Des données d'accès celui-ci peuvent être entrées sur le serveur de Web Chaîne wlanssid = "Lechner LAN"; Chaîne wlanpwd = "Guadalquivir2711"; Chaîne mqttuser = ""; Chaîne mqttpwd = ""; Chaîne mqttid = ""; //Serveur de Web l'instance Serveur de Web serveur(80); //Display OLED SSD1306 display(0x3c, 4, 15); //Mémoire tampon à l'interentrepôt des nouvelles par canal MSG_BUF messages[MAXCHANNELS]; //Liste des appareils définis DEVICE devices[MAXDEVICE]; //Etat MQTT int mqtt_con = 0; //Id d'un appareil non enregistré uint8_t inconnu[6]; //Flag toujours alors vrai quand un nouvel appareil était découvert boolean un nouvel appareil = false; //Type du nouvel appareil 0=LöRa 1 =ESPNow uint8_t neuesGeraetTyp = 0; //Compteur et Aktivitaets l'état pour le display uint32_t loraCnt = 0; //Nombre de LoRa reçue des nouvelles Chaîne charge de Lora = ""; //Date et temps de la dernière LoRa reçue la nouvelle uint32_t nowCnt = 0; //Nombre des nouvelles ESP Now reçues Chaîne nowLast = ""; //Date et temps de la dernière LoRa reçue la nouvelle uint32_t cayCnt = 0; //Nombre des nouvelles MQTT envoyées Chaîne cayLast = ""; //Date et temps de la dernière nouvelle MQTT envoyée //La fonction livre la date et le temps d'heure dans le format Yyyy le mm dd hh:mm:ss comme la chaîne Chaîne getLocalTime() { char sttime[20] = ""; struct tm timeinfo; if (WiFi.état() == WL_CONNECTED) { if(!getLocalTime(&timeinfo)){ Serial.println("Failed to obtain time"); return sttime; } strftime(sttime, sizeof(sttime), "%Y-%m-%d %H:%M:%S", &timeinfo); } return sttime; } //La fonction livre 6 octets de Geräte-Id dans le format xx:xx:xx:xx:xx:xx comme la chaîne Chaîne getId(uint8_t id[6]) { Chaîne stid; char tmp[4]; sprintf(tmp,"x",id[0]); stid=tmp; for (uint8_t j = 1; j<6; j++) { sprintf(tmp,":% 02x",id[j]); stid = stid += tmp ; } retour stid; } // la fonction fournit une partie d'un tampon de données au format xx, xx, xx .... sous forme de chaîne String getData(uint8_t buf[], uint8_t commencer, uint8_t fin) { String stdata; char tmp[4]; sprintf(tmp,"% 02x",buf[commencer]); stdata=tmp; pour (uint8_t j = commencer+1; j<fin; j++) { sprintf(tmp,",% 02x",buf[j]); stdata = stdata += tmp ; } retour stdata; } // prépare le tampon de messages // définit tous les messages comme terminés nul initMessageBuffer() { pour (int je = 0;je<MAXCHANNELS;je++) { messages[je].nouveau = 0; } } // Fonction pour enregistrer la configuration nul écrire la configuration(const char *fn) { Fichier f = SPIFFS.ouvert(fn, FILE_WRITE); si (!f) { Série.println(F("ERREUR: SPIFFS ne peut pas enregistrer la configuration")); retour; } pour (uint8_t je = 0; je<MAXDEVICE; je++) { f.imprimer(appareils[je].actif);f.imprimer('\ n'); si (appareils[je].actif) { f.imprimer(appareils[je].service);f.imprimer('\ n'); f.imprimer(getId(appareils[je].id));f.imprimer('\ n'); f.imprimer(appareils[je].nom);f.imprimer('\ n'); f.imprimer(appareils[je].dernier);f.imprimer('\ n'); } d'autre { f.printf("0 \ n00: 00: 00: 00: 00: 00 \ n- \ n- \ n"); } } } // Fonction de stockage des données d'accès nul accès en écriture(const char *fn) { Fichier f = SPIFFS.ouvert(fn, FILE_WRITE); si (!f) { Série.println(F("ERREUR: SPIFFS ne peut pas enregistrer les données de connexion")); retour; } f.imprimer("WLANSSID =");f.imprimer(wlanssid);f.imprimer('\ n'); f.imprimer("WLANPWD =");f.imprimer(wlanpwd);f.imprimer('\ n'); f.imprimer("MQTTUSER =");f.imprimer(mqttuser);f.imprimer('\ n'); f.imprimer("MQTTPWD =");f.imprimer(mqttpwd);f.imprimer('\ n'); f.imprimer("MQTTID =");f.imprimer(mqttid);f.imprimer('\ n'); } // Fonction de lecture de la configuration nul lecture de la configuration(const char *fn) { uint8_t je = 0; String tmp; char hex[3]; si (!SPIFFS.existe(fn)) { // n'existe pas encore alors créez écrire la configuration(fn); retour; } Fichier f = SPIFFS.ouvert(fn, "r"); si (!f) { Série.println(F("ERREUR :: SPIFFS ne peut pas ouvrir la configuration")); retour; } #ifdef DEBUG Série.println("Lire la liste des appareils"); #endif tout (f.disponible() && (je<MAXDEVICE)) { Série.printf("Lire le périphérique% i",je); tmp = f.readStringUntil('\ n'); appareils[je].actif = (tmp == "1"); tmp = f.readStringUntil('\ n'); appareils[je].service = tmp.toInt(); tmp = f.readStringUntil('\ n'); pour (uint8_t j=0; j<6; j++){ hex[0]=tmp[j*3]; hex[1]=tmp[j*3+1]; hex[2]=0; appareils[je].id[j]= (octet) strtol(hex,ZERO,16); } tmp = f.readStringUntil('\ n'); appareils[je].nom = tmp; tmp = f.readStringUntil('\ n'); appareils[je].dernier = tmp; #ifdef DEBUG Série.imprimer("Appareil"+getId(appareils[je].id)+ "Nom" + appareils[je].nom); Série.printf("Service% i actif% i \ r \ n",appareils[je].service,appareils[je].actif); #endif je++; } } // Fonction de lecture des données d'accès nul accès en lecture(const char *fn) { uint8_t je = 0; String clé; String val; char hex[3]; si (!SPIFFS.existe(fn)) { // n'existe pas encore alors créez accès en écriture(fn); retour; } Fichier f = SPIFFS.ouvert(fn, "r"); si (!f) { Série.println(F("ERREUR :: SPIFFS ne peut pas ouvrir les données d'accès")); retour; } tout (f.disponible() && (je<MAXDEVICE)) { clé = f.readStringUntil('='); val = f.readStringUntil('\ n'); si (clé == "WLANSSID") wlanssid = val; si (clé == "WLANPWD") wlanpwd = val; si (clé == "MQTTUSER") mqttuser = val; si (clé == "MQTTPWD") mqttpwd = val; si (clé == "MQTTID") mqttid = val; } } // Fonction d'enregistrement d'un nouvel appareil nul deviceRegister() { uint8_t je = 0; // recherche entrée gratuite tout ((je<MAXDEVICE) && appareils[je].actif) je++; // s'il n'y a pas de nouvelle entrée on ne fait rien si (je < MAXDEVICE) { // sinon enregistrer l'appareil Nom = nom entré // ou inconnu si aucun n'a été entré si (serveur.hasArg("devname")) { appareils[je].nom = serveur.mauvais("devname"); } d'autre { appareils[je].nom = "inconnu"; } pour (uint8_t j = 0; j<6; j++) appareils[je].id[j]=inconnu[j]; appareils[je].actif = 1; appareils[je].service= nouveau type de périphérique; appareils[je].dernier = ""; écrire la configuration("/konfiguration.csv"); nouveau dispositif = faux; } } // La page de configuration est affichée par le serveur web nul handleConfig(){ char htmlbuf[1024]; booléen redémarrer = faux; int index; // a-t-on appuyé sur le bouton mémoire? si (serveur.hasArg("enregistrer")) { // Données de la requête POST wlanssid = serveur.mauvais("ssid"); // si le SSID contient un espace, nous obtenons un "+" // cela doit être reconverti en un espace pour l'enregistrement wlanssid.remplacer("+"," "); wlanpwd = serveur.mauvais("pwd"); mqttuser = serveur.mauvais("mquser"); mqttpwd = serveur.mauvais("mqpwd"); mqttid = serveur.mauvais("mqid"); Série.println("Nouvelle configuration:"); Série.imprimer("SSID:");Série.println(wlanssid); Série.imprimer("Mot de passe:");Série.println(wlanpwd); Série.imprimer("Utilisateur:");Série.println(mqttuser); Série.imprimer("Mot de passe:");Série.println(mqttpwd); Série.imprimer("ID:");Série.println(mqttid); // Enregistrez la nouvelle configuration dans SPIFFS accès en écriture("/zugang.txt"); // on se souvient que la connexion WiFi doit être redémarrée // mais d'abord le serveur web doit livrer la page HTML redémarrer = vrai; } // Sortie de la page de configuration // nous créons des pointeurs vers la mémoire interne des chaînes d'accès // pour l'utiliser pour sprintf et pour démarrer la connexion WiFi et Cayenne char* txtSSID = const_cast<char*>(wlanssid.c_str()); char* txtPassword = const_cast<char*>(wlanpwd.c_str()); char* txtUser = const_cast<char*>(mqttuser.c_str()); char* txtPwd = const_cast<char*>(mqttpwd.c_str()); char* txtId = const_cast<char*>(mqttid.c_str()); // Envoyer la page HTML actuelle au navigateur serveur.setContentLength(CONTENT_LENGTH_UNKNOWN); // en-tête serveur.envoyer(200, "text / html",HTML_HEADER); serveur.sendContent(HTML_HEADER_END); // Le formulaire avec les champs de saisie est rempli avec les valeurs actuelles sprintf(htmlbuf,HTML_CONFIG,txtSSID,txtPassword,txtUser,txtPwd,txtId); // et envoyé au navigateur serveur.sendContent(htmlbuf); serveur.sendContent(HTML_END); si (redémarrer) { // Si l'indicateur de redémarrage a été défini, la connexion WiFi doit être déconnectée et nouvelle // être construit mqtt_con = 0; Série.println("Redémarrer"); uint8_t délai = 0; Série.println("Déconnecter"); WiFi.déconnecter(); tout ((WiFi.statut() == WL_CONNECTED) && (délai < 10)) { retard(1000); délai++; } Série.println("Reconnecter"); WiFi.commencer(txtSSID,txtPassword); tout ((WiFi.statut() != WL_CONNECTED) && (délai < 10)) { retard(1000); délai++; } Série.imprimer("Adresse IP:"); Série.println(WiFi.localIP()); si (WiFi.statut() == WL_CONNECTED) { // si le redémarrage a réussi, la connexion à Cayenne doit également être rétablie. si ((mqttuser != "")&&(mqttpwd != "") && (mqttid != "")) { Série.println("Connect Cayenne"); Cayenne.commencer(txtUser, txtPwd, txtId); mqtt_con = 1; } // synchronise l'horloge avec le serveur de temps configTime(GMT_OFFSET_SEC, DAYLIGHT_OFFSET_SEC, NTP_SERVER); // Heure actuelle de sortie Série.println(getLocalTime()); } } } // La page de réinitialisation a été interrogée par le serveur Web nul handleReset() { //nous reculons les données d'accès wlanssid= ""; wlanpwd = ""; mqttuser = ""; mqttpwd=""; mqttid=""; //et indiquent les données de configuration //seulement si sur le côté de configuration le badge //A des entrepôts est cliqué, deviennent les données d'accès //aussi dans SPIFFS effacé. handleConfig(); } //Le côté avec la liste d'appareils était interrogé par le serveur de Web void handleWLANRequest(){ char htmlbuf[512]; char tmp1[20]; char tmp2[20]; char tmp3[20]; int index; //est-ce que l'efface le bouton était cliqué ? if (serveur.hasArg("delete")) { index = serveur.méchamment("delete").toInt(); #ifdef DEGUG Serial.printf("Lösche device %i =",index); Serial.println(devices[index].nom); #endif devices[index].activement=0; schreibeKonfiguration("/konfiguration.csv"); } //est-ce que le fait d'enregistrer le bouton était cliqué ? if (serveur.hasArg("enregistrer")) { geraetRegistrieren(); Serial.println("La configuration est sauvegardée"); schreibeKonfiguration("/konfiguration.csv"); } //Envoient l'HTML actuel au côté au navigateur serveur.setContentLength(CONTENT_LENGTH_UNKNOWN); //Header serveur.envoie(200, "texte / html",HTML_HEADER); //Adresse IP pour reload script WiFi.localIP().toString().toCharArray(tmp1,20); sprintf(htmlbuf,HTML_SCRIPT,tmp1); serveur.sendContent(htmlbuf); serveur.sendContent(HTML_HEADER_END); //Formulaire Début serveur.sendContent("<div class = \"le titre \">MQTT - Gateway</div><form method = \"la poste \">"); //Tableau des appareils actifs serveur.sendContent(HTML_TAB_GERAETE); for (uint8_t i = 0; i<MAXDEVICE; i++) { if (devices[i].activement == 1) { getId(devices[i].id).toCharArray(tmp1,20); devices[i].nom.toCharArray(tmp2,20); devices[i].lisait.toCharArray(tmp3,20); sprintf(htmlbuf,HTML_TAB_ZEILE,tmp1,i,i*8,i*8+7,tmp2,tmp3,i); serveur.sendContent(htmlbuf); } } serveur.sendContent(HTML_TAB_END); //Au cas où un nouvel appareil soit trouvé ses ID ainsi qu'un champ de demande deviennent pour le nom //et un bouton pour enregistrer le nouvel appareil indiqué if (un nouvel appareil) { getId(inconnu).toCharArray(tmp1,20); sprintf(htmlbuf,HTML_NEWDEVICE,tmp1,tmp1); serveur.sendContent(htmlbuf); } serveur.sendContent(HTML_END_RELOAD); } //Service Funktions du Web du serveur pour Root la liste void handleRoot() { if (WiFi.état() != WL_CONNECTED) { //si nous n'avons aucun lien dans Routernetz //si le côté de configuration est indiqué si bien que les données d'accès puissent être entrées handleConfig(); } else { handleWLANRequest(); } } //Fonction à la recherche d'un appareil dans la liste d'appareils //La restitution l'index de l'appareil ou-1 si ce n'était pas trouvé int findDevice(uint8_t dev[6]) { uint8_t j; uint8_t i = 0; boolean found = false; jeu { j = 0; if (devices[i].activement == 0) { i++; } else { while ((j < 6) && (dev[j] == devices[i].id[j])) {j++;} found = (j == 6); if (!found) i++; } } while ((i<MAXDEVICE) && (!found)); if (found) {return i;} else {return -1;} } //Fonction à l'annonce de l'état au display OLED void indique() { display.clear(); display.drawString(0,0,"La passerelle MQTT"+gwversion); display.drawString(0,10,getLocalTime()); display.drawString(0,20,WiFi.localIP().toString()); display.drawString(0,34,"MQTT :"); display.drawString(60,34,Chaîne(cayCnt)); display.drawString(0,44,"LoRa :"); display.drawString(60,44,Chaîne(loraCnt)); display.drawString(0,54,"NOW :"); display.drawString(60,54,Chaîne(nowCnt)); display.display(); } //Les données reçues sauvegardent dans la mémoire tampon d'informations //La valeur de restitution n'enregistre pas le numéro d'appareils ou-1 au cas où uint8_t processData(uint8_t buf[], int buflen) { int devnr; int index; uint8_t devid[6]; uint8_t canal; uint8_t type; uint8_t len; uint8_t i; boolean sortie; index = 0; while ((index < 6) && (index < buffle)) { devid[index] = buf[index]; index++; } #ifdef DEBUG Série.imprimer("ID d'appareil =");Série.println(getId(devid)); #endif // vérifier si l'appareil est enregistré devnr = findDevice(devid); si (devnr >= 0) { #ifdef DEBUG Série.println(getLocalTime()); Série.imprimer("Numéro d'appareil =");Série.println(devnr); #endif // si oui, nous définissons l'horodatage du dernier message et // lire les données appareils[devnr].dernier = getLocalTime(); //writeconfiguration("/konfiguration.csv "); // maintenant lire les données tout (index < buffle) { canal = buf[index++]+devnr*CANAL MAX; si (index == buffle) casser; taper = buf[index++]; sortie = faux; interrupteur(taper) { cas LPP_DIGITAL_INPUT : len = LPP_DIGITAL_INPUT_SIZE - 2; casser; cas LPP_DIGITAL_OUTPUT : len = LPP_DIGITAL_OUTPUT_SIZE - 2; sortie = vrai; casser; cas LPP_ANALOG_INPUT : len = LPP_ANALOG_INPUT_SIZE - 2; casser; cas LPP_ANALOG_OUTPUT : len = LPP_ANALOG_OUTPUT_SIZE - 2; sortie = vrai; casser; cas LPP_LUMINOSITY : len = LPP_LUMINOSITY_SIZE - 2; casser; cas LPP_PRESENCE : len = LPP_PRESENCE_SIZE - 2; casser; cas LPP_TEMPERATURE : len = LPP_TEMPERATURE_SIZE - 2; casser; cas LPP_RELATIVE_HUMIDITY : len = LPP_RELATIVE_HUMIDITY_SIZE - 2; casser; cas LPP_ACCELEROMETER : len = LPP_ACCELEROMETER_SIZE - 2; casser; cas LPP_BAROMETRIC_PRESSURE : len = LPP_BAROMETRIC_PRESSURE_SIZE - 2; casser; cas LPP_GYROMETER : len = LPP_GYROMETER_SIZE - 2; casser; cas LPP_GPS : len = LPP_GPS_SIZE - 2; casser; défaut: len = 0; } // si le canal n'est pas un actionneur, on remet à 1 dans la mémoire tampon des messages // pour que les données soient envoyées au serveur MQTT à la prochaine opportunité si (!sortie) messages[canal].nouveau =1; messages[canal].taper = taper; je = 0; tout ((je<len) && (index < buffle)) { si (!sortie) messages[canal].les données[je] = buf[index]; je++; index++; } #ifdef DEBUG Série.printf("Canal% i tapez% i data:",canal,taper);Série.println(getData(messages[canal].les données,0,len)); #endif } retour devnr; } d'autre { pour (uint8_t je = 0; je<6; je++) inconnu[je] = devid[je]; nouveau dispositif = vrai; retour -1; } } uint8_t formulaire de réponse(uint8_t buf[], uint8_t devnr) { // nous vérifions si nous avons des données de sortie pour le dispositif LoRa actuel int index = 6; // les six premiers octets sont l'ID de l'appareil int devbase = devnr*CANAL MAX; #ifdef DEBUG Série.printf("Activateurs pour le périphérique% i canal% i vers% i \ r \ n",devnr,devbase,devbase+8); #endif pour (int je = devbase; je<devbase+8; je++) { // selon le type de données numériques ou analogiques interrupteur (messages[je].taper) { cas LPP_DIGITAL_OUTPUT : buf[index++]= je-devbase; buf[index++]=messages[je].taper; buf[index++]=messages[je].les données[0]; #ifdef DEBUG Série.println("Sortie numérique"); #endif casser; cas LPP_ANALOG_OUTPUT : buf[index++]= je-devbase; buf[index++]=messages[je].taper; buf[index++]=messages[je].les données[0]; buf[index++]=messages[je].les données[1]; #ifdef DEBUG Série.println("Sortie analogique"); #endif casser; } } retour index; } // Traite un message d'un client LoRa nul readLoRa() { uint8_t buf[256]; int ix; int devnr; uint8_t len; uint8_t octet; // récupérer les données si disponibles int packetSize = LoRa.parsePacket(); // avons-nous reçu des données? si (packetSize > 0) { #ifdef DEBUG Série.printf("% i octets reçus de LoRa \ r \ n",packetSize); #endif tout ((ix < packetSize) && (ix < 256)) { octet= LoRa.lire(); // Serial.printf ("% 2x", octet); buf[ix++] = octet; } // Serial.println (); #ifdef DEBUG Série.println(getData(buf,0,packetSize)); #endif devnr = processData(buf, packetSize); si (devnr >=0) { // mise à jour du statut loraCnt++; loraLast = getLocalTime(); } d'autre { nouveau type de périphérique = 0; // Appareil LoRa } // Envoi de la réponse de la deuxième partie au périphérique LoRa // délai (500); // L'ID de périphérique est déjà dans les six premiers octets du tampon len = 6; // si nous avons un appareil enregistré, nous envoyons également des données si (devnr >= 0) len = formulaire de réponse(buf, devnr); #ifdef DEBUG Série.printf("Envoyer au périphérique% i% i octets \ r \ n",devnr,len); Série.println(getData(buf,0,len)); #endif LoRa.beginPacket(); LoRa.écrire(buf,len); int statut de l'huile = LoRa.endPacket(); #ifdef DEBUG Série.imprimer("Statut d'envoi ="); Série.println(statut de l'huile); #endif } } // rappel pour ESP Now nul readESPNow(const uint8_t *mac_addr, const uint8_t *r_data, int data_len) { uint8_t les données[70]; uint8_t devnr; uint8_t len; #ifdef DEBUG Série.printf("% i octets reçus de ESP-Now \ r \ n",data_len); #endif memcpy(&les données, r_data, taille de(les données)); devnr = processData(les données,data_len); si (devnr >=0) { // mise à jour du statut nowCnt++; maintenantDernier = getLocalTime(); } d'autre { nouveau type de périphérique = 1; // Appareil ESP Now } retard(100); // Envoi de la réponse de la deuxième partie à l'appareil ESP-Now // L'ID de périphérique est déjà dans les six premiers octets du tampon len = 6; // si nous avons un appareil enregistré, nous envoyons également des données si (devnr >= 0) len = formulaire de réponse(les données, devnr); #ifdef DEBUG Série.printf("Envoyer au périphérique% i% i octets \ r \ n",devnr,len); Série.println(getData(les données,0,len)); #endif esp_now_send(les données, les données, len); #ifdef DEBUG Série.println("Fin"); #endif } nul configuration() { // initialise la mémoire de l'appareil pour (uint8_t je =0; je<MAXDEVICE; je++) appareils[je].actif = 0; // Initialiser l'affichage OLED pinMode(DISPLRESET,SORTIE); digitalWrite(DISPLRESET, FAIBLE); retard(50); digitalWrite(DISPLRESET, ÉLEVÉ); affichage.init(); affichage.flipScreenVertically(); affichage.setFont(ArialMT_Plain_10); affichage.setTextAlignment(TEXT_ALIGN_LEFT); // Démarrer l'interface série Série.commencer(115200); tout (!Série); Série.println("Démarrer"); // Système de fichiers Flash si (SPIFFS.commencer(FORMAT_SPIFFS_IF_FAILED)) Série.println(F("SPIFFS chargé")); // Lire la configuration et accéder aux données lecture de la configuration("/konfiguration.csv"); accès en lecture("/zugang.txt"); initMessageBuffer(); // Initialiser SPI et LoRa SPI.commencer(5,19,27,18); LoRa.setPins(SS,RST,DI0); Série.println("LoRa TRX"); si (!LoRa.commencer(BANDE)) { Série.println("Le démarrage de LoRa a échoué!"); tout (1); } LoRa.enableCrc(); Série.println("LoRa Initial OK!"); retard(2000); // Sortie des données d'accès en lecture pour vérification Série.imprimer("SSID:");Série.println(wlanssid); Série.imprimer("Mot de passe:");Série.println(wlanpwd); Série.imprimer("Utilisateur:");Série.println(mqttuser); Série.imprimer("Mot de passe:");Série.println(mqttpwd); Série.imprimer("ID:");Série.println(mqttid); // Se connecter au serveur WLAN et MQTT Série.println("Connect WLAN"); // on utilise l'ESP32 comme point d'accès mais aussi comme client dans le réseau du routeur WiFi.la mode(WIFI_AP_STA); // nous avons besoin de pointeurs vers la mémoire des caractères dans les chaînes char* txtSSID = const_cast<char*>(wlanssid.c_str()); char* txtPassword = const_cast<char*>(wlanpwd.c_str()); char* txtUser = const_cast<char*>(mqttuser.c_str()); char* txtPwd = const_cast<char*>(mqttpwd.c_str()); char* txtId = const_cast<char*>(mqttid.c_str()); // Quelle que soit la connexion au réseau de routeurs, nous démarrons AccessPoint // qui permet la configuration via un navigateur si nous l'avons // se connecter au point d'accès WiFi.softAP("MQTTGateway",APPWD,APCHANNEL,0); //Le lien dans Routernetz est produit WiFi.begin(txtSSID, txtPassword); uint8_t timeout = 0; while ((WiFi.état() != WL_CONNECTED) && (timeout<10)) { timeout++; delay(1000); } //nous attendons au maximum pendant 10 secondes jusqu'au lien se trouve if (WiFi.état() == WL_CONNECTED) { //Si le lien avait du succès dans Routernetz, nous lançons MQTT à Cayenne //et synchronisent l'heure interne avec le serveur de Time Serial.print("IP address :"); Serial.println(WiFi.localIP()); if ((mqttid != "") && (mqttuser != "") && (mqttpwd != "")) { Serial.println("State MQTT"); Cayenne.begin(txtUser, txtPwd, txtId); Serial.println("Cayenne le lien de manière produite"); mqtt_con = 1; } //L'heure avec le serveur de temps synchronisent configTime(GMT_OFFSET_SEC, DAYLIGHT_OFFSET_SEC, NTP_SERVER); //Distribuent du temps d'heure actuel Serial.println(getLocalTime()); } //Le Web des serveurs initialisent serveur.on("/", handleRoot); serveur.on("/conf",handleConfig); serveur.on("/reset",handleReset); serveur.begin(); if (esp_now_init() == ESP_OK) Serial.println("ESP-Now initialise!"); esp_now_register_recv_cb(readESPNow); Serial.println("*********************************************"); } void loop() { indique(); if (WiFi.état() == WL_CONNECTED) { //Examinent LoRa l'interface sur des données readLoRa(); //avec Cayenne MQTT des serveurs communiquent if (mqtt_con == 1) Cayenne.loop(1); } //Le Web des serveurs servent serveur.handleClient(); delay(100); } //Des données de la mémoire tampon d'informations envoient au serveur MQTT CAYENNE_OUT_DEFAULT() { boolean sortie = false; boolean sentData = false; float val; #ifdef DEBUG Serial.println(getLocalTime()); Serial.println("Cayenne envoie"); #endif for (int i = 0; i<MAXCHANNELS; i++) { //les nouvelles seulement nouvelles envoient if (messages[i].à neuf == 1) { #ifdef DEBUG Serial.printf("Sende MQTT Kanal %i Typ %i\n",i,messages[i].type); #endif //selon le type Données envoient switch (messages[i].type) { case LPP_DIGITAL_INPUT : Cayenne.digitalSensorWrite(i,messages[i].données[0]); break; case LPP_DIGITAL_OUTPUT : sortie = true; break; case LPP_ANALOG_INPUT : val = (messages[i].données[0]*256 + messages[i].données[1]);Cayenne.virtualWrite(i,val/100,"analog_sensor",UNIT_UNDEFINED); break; break; case LPP_ANALOG_OUTPUT : sortie = true; break; case LPP_LUMINOSITY : Cayenne.luxWrite(i,messages[i].données[0]*256 + messages[i].données[1]); break; case LPP_PRESENCE : Cayenne.digitalSensorWrite(i,messages[i].données[0]); break; case LPP_TEMPERATURE : val = (messages[i].données[0]*256 + messages[i].données[1]); Cayenne.celsiusWrite(i,val/10); break; case LPP_RELATIVE_HUMIDITY : val=messages[i].données[0];Cayenne.virtualWrite(i,val/2,TYPE_RELATIVE_HUMIDITY,UNIT_PERCENT); break; case LPP_ACCELEROMETER : val = (messages[i].données[0]*256 + messages[i].données[1]);Cayenne.virtualWrite(i,val/1000,"gx","g"); break; case LPP_BAROMETRIC_PRESSURE : val = (messages[i].données[0]*256 + messages[i].données[1]);Cayenne.hectoPascalWrite(i,val/10); break; //case LPP_GYROMETER : len = LPP_GYROMETER_SIZE - 2; break; //case LPP_GPS : len = LPP_GPS_SIZE - 2; break; } if (!sortie) { messages[i].à neuf = 0; sentData = true; } } } if (sentData) { //Actualisent l'état cayCnt++; cayLast = getLocalTime(); } } CAYENNE_IN_DEFAULT() { uint8_t * pData; int val; int ch = request.canal; #ifdef DEBUG Serial.println("Cayenne recive"); Serial.printf("Des données MQTT pour le canal %i = %s\n",ch,getValue.asString()); #endif switch (messages[ch].type) { case LPP_DIGITAL_OUTPUT : messages[ch].données[0] = getValue.asInt(); messages[ch].à neuf = 1; break; case LPP_ANALOG_OUTPUT : val = round(getValue.asDouble()*100); messages[ch].données[0] = val / 256; messages[ch].données[1] = val % 256; messages[ch].à neuf = 1; break; } CAYENNE_LOG("Channel %u, value %s", request.canal, getValue.asString()); //Process le message here. If there is à l'assortiment error au message error using getValue.setError (), e.g getValue.setError ("Error du message"); }
Maintenant, le display indique aussi un numéro de version. Des informations étendues à cette passerelle, vous trouvez dans les autres parties de cette série.
2 commentaires
Roland
Ich habe den Fehler scheinbar gefunden. Ich habe das exakt gleiche Board von Heltec 2×.
Beim Ersten Board funktioniert das WLAN einfach nicht. Beim zweiten geht alles Problemlos.
Ich habe auf der Platine nichts gelötet (Pins) und habe so auch keinen Kurzschluss auf der Platine mit der Antenne verursacht. Schaut so aus als hätte die Platine einen Defekt. Ich habe jetzt den Heltec ESP32LORA als Client für LORA verwendet das funktioniert.
Optisch habe ich jetzt nichts gefunden was die WLAN Antenne stören könnte.
Roland
Jetzt spiele ich mich mit den Projekten von 1 bis 7
Wie in der Beschreibung erwähnt startet aber der Access-Point „MQTTGateway“ nicht.Das Hochladen und Kompilieren funktioniert bei allen Projekten.
Ich schaffe es aber nicht die WLAN Einstellungen zu ändern. Im Seriellen Monitor sieht man
LoRa TRX
LoRa Initial OK!
SSID: Lechner LAN
Passwort: Guadalquivir2711
User:
Passwort:
ID:
WLAN verbinden
ESP-Now initialisiert!
Was mache ich da falsch?