Après plusieurs tentatives malheureuses de construire une passerelle de LoRa universelle avec ESP32, la passerelle suivante a été mise en place, ce qui permet de connecter des périphériques IoT basés sur LoRa à Cayenne Dashboard via MQTT. Dans un niveau avancé, la passerelle doit également gérer les périphériques IoT basés sur le protocole ESP-Now.
Pour la passerelle, nous n'avons besoin que d'un seul ESP32 avec LoRa et OLED Display aucun autre composant n'est nécessaire. L'alimentation électrique peut être alimentée avec n'importe quel bloc d'alimentation USB.
Description de la fonction:
La passerelle peut gérer 32 appareils, chacun pouvant gérer jusqu'à 8 canaux. La transmission des données est asynchrone. Lorsque la passerelle reçoit un paquet de données LoRa, les six premiers octets sont interprétés comme étant l'ID de périphérique (c'est-à-dire l'adresse MAC). La passerelle regarde ensuite dans une liste de périphériques si cet appareil est déjà enregistré. Si ce n'est pas le cas, l'ID de périphérique est stocké et affiché à l'aide de l'interface Web.
Si le périphérique est déjà enregistré, les données sont lues et stockées par canal dans une mémoire tampon de messages. Le numéro de canal est déterminé à partir du numéro de périphérique (index de la liste des périphériques) * 8 + Numéro de canal des données reçues. Par conséquent, le dispositif 0 a les canaux 0 à 7, le périphérique 1 les canaux 8 à 15 u.s.w.
Un enregistrement commence par un octet suivi d'un numéro de canal suivi d'un octet de type, puis de 1 à 6 octets de données par type. Une fois que toutes les données ont été enregistrées dans la mémoire tampon de messages et que toutes les données ont été recréées, le paquet de réponses est compilé sur le périphérique Lora. Il recommence avec les six octets ID de périphérique. Ensuite, dans la mémoire tampon de messages, les canaux de cet appareil vérifient si un paquet de données de départ de Cayenne est présent sur le dispositif qui est marqué par nouveau. Si un paquet de données est détecté, il est ajouté au paquet de réponses et reprendra le numéro relatif de canal 0 à 7. La dernière étape est le transfert du paquet de réponses vers le périphérique LoRa.
La fonction Cayenne.loop (1) hérite de la communication avec le serveur IoT. Dans la fonction de rappel CAYENNE_OUT_DEFAULT (), tous les canaux sont recherchés dans la mémoire tampon de messages et le type contient un paquet de données d'entrée pour Cayenne. Ces paquets sont maintenant convertis en fonction du type et sont envoyés au serveur IoT. Une fois le transfert réussi, l'indicateur Nouveau est réinitialisé.
Une seconde fonction de rappel CAYENNE_IN_DEFAULT () est appelée chaque fois que Cayenne a reçu des données pour un canal d'action. Les données provenant du serveur IoT sont converties en fonction du type et stockées dans la mémoire tampon de messages. Elles sont recaractérisées de manière à ce qu'elles soient envoyées au périphérique lors de la prochaine communication LoRa avec le paquet de réponses.
Affichage:
L'affichage affiche à côté du nom la date et l'heure en cours. Il est disponible sous l'adresse IP.
La ligne MQTT: indique le nombre de transferts réussis vers IoT Server, LoRa, les transmissions réussies avec les périphériques LoRa et NOW indique le nombre de transmissions réussies dans les périphériques ESP-Now. Cette dernière est toujours 0, car cette fonction n'est pas encore implémentée.
Périphériques-Liste et enregistrement:
La liste de périphériques est stockée sous la forme d'un fichier CSV dans le système de fichiers Flash (SPIFFS), ce qui signifie qu'elle est conservée en l'absence de bloc d'alimentation. Cette liste peut être attendue à partir du serveur Web intégré à la passerelle. Vous pouvez supprimer des périphériques et enregistrer de nouveaux périphériques.
paquets de données:
Pour le type, les codes correspondant aux systèmes Smart Objects IPSO sont déduits, mais 3200 sont déduits.
Type | IPSO | Type Nr. | octets | Résolution |
Entrée numérique | 3200 | 0 | 1 | 1 |
Sortie numérique | 3201 | 1 | 1 | 1 |
Entrée analogique | 3202 | 2 | 2 | 0.01 avec signe |
Sortie analogique | 3203 | 3 | 2 | 0.01 avec signe |
Détecteur d'éclairage | 3301 | 101 | 2 | 1 Lux |
Senseur de présence | 3302 | 102 | 1 | 1 |
Capteur de température | 3303 | 103 | 2 | 0.1 ° C signé |
Détecteur humide | 3304 | 104 | 1 | 0.5% |
Détecteur d'accélération | 3313 | 113 | 6 | 0.001G avec signe par essieu X, Y et Z |
Capteur de pression | 3315 | 115 | 2 | 0.1 hPa |
Gyromètre | 3334 | 134 | 6 | 0.01% /s signé par essieu X, Y et Z |
Emplacement GPS | 3336 | 136 | 9 | Latitude 0.0001 ° signé Longitude 0.0001 ° signé Hauteur 0.01m signé |
Sketch:
L'enregistrement de la passerelle auprès de Cayenne est décrit de la même manière que dans la partie 1 de ce blog. Les données d'accès doivent ensuite être entrées dans le Sketch (signe jaune) ainsi que les données d'accès à la connexion WiFi locale. Le tableau de bord de Cayenne n'affiche pas les widgets car aucun périphérique n'a encore été connecté à la passerelle.
Board for Arduino IDE = TTGO LoRa32-OLED V1
/ * La passerelle MQTT constitue une interface entre les périphériques LoRa. Unités ESP Nowe * et Cayenne MQTT Tableaux de bord. Il fonctionne sur ESP32 avec LoRa et OLED Display * La configuration est effectuée par le navigateur */ #include <SPI.h> #include <LoRa.h> #include "SSD1306.h" #include<Arduino.h> #include <CayenneMQTTESP32.h> #include <CayenneLPP.h> #include <WiFi.h> #include <serveurs Web.h> #include <heure.h> #include "FS.h" #include "SPIFFS.h" // Les données de ce paramètre sont obtenues du tableau de bord Cayenne #define MQTT_USER "" #define MQTT_PASSWORD "" #define MQTT_CLIENTID "" // Données d'accès à la connexion WiFi locale #define WIFI_SSID "" #define MOT DE PASSE WIFI_PASSWORD "" // serveur NTP pour la synchronisation de l'heure #define SERVEUR NTP_SERVER "de.pool.ntp.org" #define GMT_OFFSET_SEC 3600 #define DAYLIGHT_OFFSET_SEC 0 // Pins pour la puce LoRa #define SS 18 #define RST 14 #define DI0 26 // Fréquence de la puce LoRa #define BANDE 433175000 // #define MAXCHANNELS 256 // Nombre maximal de canaux gérés #define MAXDEVICE 32 // Le nombre maximal de dispositifs gérés MAXCHANNELS/MAXDEVICE = 8 indique le nombre maximal de canaux par dispositif // Format du système de fichiers Flash si ce n'est déjà fait #define FORMAT_SPIFFS_IF_FAILED vrai #define DÉBOGAGE 1 // Paragraphes pour le serveur Web const char EN-TÊTE HTML_HEADER[] = " <!DOCTYPE HTML > " "<html>" "<head>" "< meta name = \" viewport \" content = \" width = device-width, initial-scale = 1.0, max-scale = 1.0, user-scalable= 0 > \" > " "< meta http-equiv = \ "content-type \" content = \ "text/html; charset = UTF-8 \" > " "<title>Passerelle MQTT</title>" "< script language = \ "javascript \" >" "function reload () {" "document.location= \" http:// %s \" ;}" "</script>" "<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 solid black ;}" ". Titre {font-size:18pt; font-weight:bold; text-align:center;}" "</style>" "</head>" "<body><div style='margin-left:30px;'>"; const char HTML_END[] = "</div>< script language = \ "javascript \" > setTimeout (reload, 10000) ;</script></body>" "</html>"; const char HTML_TAB_GERAETE[] = "< table style = \ "width: 100% \" ><tr>< th style = \ "width: 20% \" > ID</th>< th style = \ "width: 10% \" > N °</th>" "< th style = \ "width: 20% \" > canaux</th>< th style = \ "width: 20% \" > Name</th>" "< th style = \ "width: 20% \" > Dernières données</th>< th style = \ "width: 10% \" > Action</th></tr>"; const char HTML_TAB_END[] = "</table>"; const char HTML_NEWDEVICE[] = "< div style= \" Marc :20px; \" > %s nom: < input type = \ "text \" style = \ "width: 200px \" name = \ "devname \" maxlength= \" 10 \ "value = \ "enregistrent \" value = \" %s \" %s \" > Enregistrer</button></div>"; const char LIGNE HTML_TAB_LIGNE[] = "<tr><td>%s</td><td>%i</td><td>%i à %i</td><td>%s</td><td>%s</td><td>< button name = \ "delete \" value = \" %i \" ></button></button></td></tr>"; // structures de données // Messages Buffer struct MSG_BUF { uint8_t type; uint8_t neuf; uint8_t Données[10]; }; // Définition du périphérique struct UNITÉ { uint8_t actif; uint8_t de service; // 0 = LoRa, 1 = ESP-Now uint8_t id[6]; Chaîne Nom de; Chaîne Charge; }; // Variable globale // Instance du serveur Web serveurs Web serveur(80); // OLED Display SSD1306 display(0x3c, 4, 15); // Buffer pour la mise en cache des messages par canal MSG_BUF messages[MAXCHANNELS]; // Liste des unités définies UNITÉ devices[MAXDEVICE]; // ID d'un périphérique non enregistré uint8_t Inconnu[6]; // L'indicateur est toujours vrai quand un nouvel appareil a été découvert boolean new-Geraet = false; // Type de nouvel appareil 0 = LöRa 1 = ESPNow uint8_t newtcaetType = 0; // Compteurs et actifs Statut de l'affichage uint32_t loraCnt = 0; // Nombre de messages LoRa reçus Chaîne loraLast = ""; // Date et heure de la dernière connexion LoRa reçue uint32_t nowCnt = 0; // Nombre de messages ESP Now reçus Chaîne flocon = ""; // Date et heure de la dernière connexion LoRa reçue uint32_t cayCnt = 0; // Nombre de messages MQTT envoyés Chaîne cayLast = ""; // Date et heure du dernier message MQTT envoyé // La fonction renvoie la date et l'heure au format aaaa-mm-jj hh:mm:ss en tant que chaîne Chaîne getLocalTime() { char heure[20] = ""; struct tn timeinfo; if(!getLocalTime(&timeinfo)){ série.println("Failed to obtain time"); return heure; } strftime(heure, sizeof(heure), "%Y-%m-%d %H:%M:%S", &timeinfo); return heure; } // La fonction renvoie un ID de périphérique de 6 octets au format xx:xx:xx:xx:xx:xx en tant que chaîne. Chaîne getId(uint8_t id[6]) { Chaîne stid; char tmp[4]; sprintf(tmp,"%02x",id[0]); stid=tmp; pour (uint8_t j = 1; j<6; j++) { sprintf(tmp,": %02x",id[j]); stid = stid += tmp ; } return stid; } // prépare le buffer de message // exécute tous les messages sur void initMessageBuffer() { pour (int i = 0;i<MAXCHANNELS;i++) messages[i].neuf = 0; } // Fonction de stockage de la configuration void configuration en écriture(const char *fn) { File f = SPIFFS.open(fn, FILE_WRITE); if (!f) { série.println(F("ERREUR: SPIFFS ne peut pas sauvegarder la configuration")); return; } pour (uint8_t i = 0; i<MAXDEVICE; i++) { f.print(devices[i].actif);f.print(","); f.print(devices[i].de service);f.print(","); f.print(getId(devices[i].id));f.print(","); f.print(devices[i].Nom de);f.print(","); f.println(devices[i].Charge); } } // Fonction d'enregistrement d'un nouvel appareil void geraetRegister() { uint8_t i = 0; // la recherche d'entrée libre while ((i<MAXDEVICE) && devices[i].actif) i++; // il n'y a pas de nouvelle entrée, nous ne faisons rien. if (i < MAXDEVICE) { // un nom unique = nom entré = nom entré // ou inconnu si aucune entrée n'a été entrée if (serveur.hasArg("devname")) { devices[i].Nom de = serveur.arg("devname"); } else { devices[i].Nom de = "inconnu"; } pour (uint8_t j = 0; j<6; j++) devices[i].id[j]=Inconnu[j]; devices[i].actif = 1; devices[i].de service= newtcaetType; devices[i].Charge = ""; configuration en écriture("/configuration.csv"); new-Geraet = false; } } // Service Fonction du serveur Web void handleRoot() { char htmlbuf[1024]; char tmp1[20]; char tmp2[20]; char tmp3[20]; int Indice; // le bouton Supprimer est-il activé? if (serveur.hasArg("delete")) { Indice = serveur.arg("delete").toInt(); #ifdef DEGUG série.printf("Suppression du service %i =",Indice); série.println(devices[Indice].Nom de); #endif devices[Indice].actif=0; configuration en écriture("/configuration.csv"); } // a été cliqué sur le bouton Enregistrer? if (serveur.hasArg("Enregistrement")) { geraetRegister(); } // Envoyer la page HTML en cours au navigateur serveur.setContentLength(CONTENT_LENGTH_UNKNOWN); // En-tête WiFi.localIP().toString().toCharArray(tmp1,20); sprintf(htmlbuf,EN-TÊTE HTML_HEADER,tmp1); serveur.send(200, "text/html",htmlbuf); // Début du formulaire serveur.sendContent("< div class = \ "titre \" >" Passerelle MQTT</div><form>"); // Table des périphériques actifs serveur.sendContent(HTML_TAB_GERAETE); pour (uint8_t i = 0; i<MAXDEVICE; i++) { if (devices[i].actif == 1) { getId(devices[i].id).toCharArray(tmp1,20); devices[i].Nom de.toCharArray(tmp2,20); devices[i].Charge.toCharArray(tmp3,20); sprintf(htmlbuf,LIGNE HTML_TAB_LIGNE,tmp1,i,i*8,i*8+7,tmp2,tmp3,i); serveur.sendContent(htmlbuf); } } serveur.sendContent(HTML_TAB_END); // Si un nouvel appliance a été trouvé, son ID et une zone de saisie pour le nom // et un bouton pour enregistrer le nouvel appareil if (new-Geraet) { getId(Inconnu).toCharArray(tmp1,20); sprintf(htmlbuf,HTML_NEWDEVICE,tmp1,tmp1); serveur.sendContent(htmlbuf); } serveur.sendContent(HTML_END); } // Fonction de recherche d'un périphérique dans la liste des périphériques // renvoie l'index de l'appareil ou -1 s'il n'a pas été trouvé int findDevice(uint8_t dev[6]) { uint8_t j; uint8_t i = 0; boolean found = false; do { j = 0; if (devices[i].actif == 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;} } // la fonction d'affichage de l'état de l'écran OLED void Affichage() { display.clear(); display.drawString(0,0,"passerelle MQTT"); 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(); } // Traiter un message à partir d'un client LoRa void readLoRa() { int devnr; uint8_t devices[6]; uint8_t channel; uint8_t type; uint8_t len; uint8_t dat; boolean output; // les données le cas échéant int packetSize = LoRa.parsePacket(); // avons-nous obtenu des données? if (packetSize > 5) { #ifdef DÉBOGAGE série.println(getLocalTime()); série.print("RX"); série.print(packetSize); série.println("Octets"); série.print("ID unité"); #endif // avant de lire le Id du périphérique pour (uint8_t i=0; i<6;i++){ devices[i]=LoRa.lecture(); #ifdef DÉBOGAGE série.printf("-%02x",devices[i]); #endif } #ifdef DÉBOGAGE série.println(); #endif // Calculer le reste du paquet packetSize -= 6; // pour vérifier si le périphérique est enregistré devnr = findDevice(devices); if (devnr >= 0) { // si oui, nous fixons la date du dernier message et // lire les données devices[devnr].Charge = getLocalTime(); configuration en écriture("/configuration.csv"); while (packetSize > 0) { // Numéro de canal = Numéro d'unité * 16 + Canal de l'appareil channel = LoRa.lecture() + devnr*16; #ifdef DÉBOGAGE série.printf("Canal: %02x",channel); #endif // Type de canal type = LoRa.lecture(); #ifdef DÉBOGAGE série.printf("Type: %02x",type); #endif // détermine la longueur du paquet de données et si le canal est un actionneur output = false; switch(type) { case LPP_DIGITAL_INPUT : len = LPP_NUMÉRISAL_INPUT_SIZE - 2; break; case LPP_NUMÉRISAL_OUTPUT : len = LPP_DIGITAL_OUTPUT_SIZE - 2; output = vrai; break; case ANALOGIQUE LPP_INPUT : len = LPP_ANALOG_INPUT_SIZE - 2; break; case OUTPUT DE LPP_ANALOGIQUE : len = LPP_ANALOG_OUTPUT_SIZE - 2; output = vrai; break; case LPP_LUMINOSITY : len = LPP_LUMINOSITY_SIZE - 2; break; case LPP_PRESENCE : len = LPP_PRESENCE_SIZE - 2; break; case LPP_TEMPERATURE : len = LPP_TEMPÉRATURE _SIZE - 2; break; case LPP_RELATIVE_HUMIDITY : len = LPP_RELATIVE_HUMIDITY_SIZE - 2; break; case LPP_ACCELEROMÈTRE : len = LPP_ACCELEROME_SIZE - 2; break; case LPP_BAROMETRIC_PRESSURE : len = LPP_BAROMETRIC_PRESSURE_SIZE - 2; break; case LPP_GYROMÈTRE : len = LPP_GYROME_SIZE - 2; break; case LPP_GPS : len = LPP_GPS_SIZE - 2; break; par défaut: len = 0; } // si le canal n'est pas un actionneur, nous redéfinissez la valeur 1 dans la buffer de message. // pour que les données soient envoyées au serveur MQTT à la prochaine occasion if (!output) messages[channel].neuf =1; messages[channel].type = type; // Regroupement = 2 moins le canal et le type lus packetSize -= 2; #ifdef DÉBOGAGE série.print("Données:"); #endif // A présent, nous lions les données reçues avec la longueur déterminée. pour (uint8_t i=0; i<len; i++) { dat = LoRa.lecture(); // pour les actuateurs, nous ne nous souvenez pas des données if (! output) messages[channel].Données[i] = dat; #ifdef DÉBOGAGE série.printf("-%02x",dat); #endif // Réduire le paquet restant de 1 packetSize --; } #ifdef DÉBOGAGE série.println(); #endif } // Mettre à jour l'état loraCnt++; loraLast = getLocalTime(); Affichage(); } else { // Le périphérique n'est pas enregistré // nous nous rendons compte de l'Id de l'applium pour les afficher pour le réalisateur pour (uint8_t i = 0; i<6; i++) Inconnu[i] = devices[i]; new-Geraet = vrai; newtcaetType = 0; // LoRa appliance } // Envoyez une partie de la réponse à la zone LoRa Délay(100); LoRa.beginPacket(); // au début de l'ID du périphérique LoRa.write(devices,6); // nous vérifions si nous avons des données de sortie pour le périphérique LoRa actuel int devbase = devnr*16; pour (int i = devbase; i<devbase+8; i++) { // selon le type de données numériques ou analogiques switch (messages[i].type) { case LPP_NUMÉRISAL_OUTPUT : LoRa.write(i-devbase); LoRa.write(messages[i].type); LoRa.write(messages[i].Données,1); #ifdef DÉBOGAGE série.println("Sortie numérique"); #endif break; case OUTPUT DE LPP_ANALOGIQUE : LoRa.write(i-devbase); LoRa.write(messages[i].type); LoRa.write(messages[i].Données,2); #ifdef DÉBOGAGE série.println("Sortie analogique"); #endif break; } } int lstatus = LoRa.endPacket(); #ifdef DÉBOGAGE série.print("Etat d'envoi ="); série.println(lstatus); #endif } } // Fonction de lecture de la configuration void lecture seule(const char *fn) { uint8_t i = 0; Chaîne tmp; char hex[3]; if (!SPIFFS.existe(fn)) { // n'existe pas encore configuration en écriture(fn); return; } File f = SPIFFS.open(fn, "r"); if (!f) { série.println(F("ERREUR:: SPIFFS ne peut pas ouvrir la configuration")); return; } while (f.available() && (i<MAXDEVICE)) { tmp = f.readStringUntil(','); devices[i].actif = (tmp == "1"); tmp = f.readStringUntil(','); devices[i].de service = tmp.toInt(); tmp = f.readStringUntil(','); pour (uint8_t j=0; j<6; j++){ hex[0]=tmp[j*3]; hex[1]=tmp[j*3+1]; hex[2]=0; devices[i].id[j]= (octets) stritol(hex,ZÉRO,16); } tmp = f.readStringUntil(','); devices[i].Nom de = tmp; tmp = f.readStringUntil(','); devices[i].Charge = tmp; i++; } } void setup() { // Initialisation de la mémoire du périphérique pour (uint8_t i =0; i<MAXDEVICE; i++) devices[i].actif = 0; // Initialisation de OLED Display rose(16,SORTIES); digitalWrite(16, LOW); Délay(50); digitalWrite(16, ÉLEVÉ); display.init(); display.flipScreenVertically(); display.setFont(ArialMT_Plain_10); display.setTextAlignment(TEXT_ALIGN_LEFT); // Démarre l'interface série série.begin(115200); while (!série); série.println("Démarrer"); // Flash File syastem if (SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED)) série.println(F("SPIFFS chargé")); // Lire la configuration lecture seule("/configuration.csv"); initMessageBuffer(); // Initialisation de SPI et de LoRa SPI.begin(5,19,27,18); LoRa.setPins(SS,RST,DI0); série.println("LoRa TRX"); if (!LoRa.begin(BANDE)) { série.println("Starting LoRa failed!"); while (1); } LoRa.enableCrc(); série.println("LoRa Initial OK!"); Délay(2000); // Connectez-vous au serveur WLAN et au serveur MQTT. série.println("Connexion à Internet Wifi"); Cayenne.begin(MQTT_USER, MQTT_PASSWORD, MQTT_CLIENTID, WIFI_SSID, MOT DE PASSE WIFI_PASSWORD); série.print("Adresse IP:"); série.println(WiFi.localIP()); // Initialisation du serveur Web serveur.on("/", handleRoot); serveur.begin(); // Synchroniser l'horloge avec le serveur d'horloge configTime(GMT_OFFSET_SEC, DAYLIGHT_OFFSET_SEC, SERVEUR NTP_SERVER); // Imprime l'heure en cours série.println(getLocalTime()); } void boucle() { Affichage(); // Vérification de l'interface LoRa sur les données readLoRa(); // communiquer avec Cayenne MQTT Server Cayenne.boucle(1); // utiliser le serveur Web serveur.handleClient(); } // Envoie les données de la mémoire tampon de messages au serveur MQTT CAYENNE_OUT_DEFAULT() { boolean output = false; boolean sentData = false; #ifdef DÉBOGAGE série.println(getLocalTime()); série.println("Cayenne send"); #endif pour (int i = 0; i<MAXCHANNELS; i++) { // envoie uniquement de nouveaux messages if (messages[i].neuf == 1) { #ifdef DÉBOGAGE série.printf("Envoi du type MQTT de type %i \n",messages[i].type); #endif // en fonction du type de données switch (messages[i].type) { case LPP_DIGITAL_INPUT : Cayenne.digitalSensorWrite(i,messages[i].Données[0]); break; case LPP_NUMÉRISAL_OUTPUT : output = vrai; break; // case LPP_ANALOG_INPUT: Cayenne.virtualWrite (i, (messages [i] .données [0] * 256 + messages [i] .données [1]) /100, "nom_capteur ", UNIT_UNDEFINED) ; break ; break ; case OUTPUT DE LPP_ANALOGIQUE : output = vrai; break; case LPP_LUMINOSITY : Cayenne.luxueux(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 : Cayenne.celsiusWrite(i,(messages[i].Données[0]*256 + messages[i].Données[1])/10); break; case LPP_RELATIVE_HUMIDITY : Cayenne.virtualWrite(i,messages[i].Données[0]/2,TYPE_RELATIVE_HUMIDITY,UNIT_PERCENT); break; case LPP_ACCELEROMÈTRE : Cayenne.virtualWrite(i,(messages[i].Données[0]*256 + messages[i].Données[1])/1000,"gx","g"); break; case LPP_BAROMETRIC_PRESSURE : Cayenne.hectoPascalWrite(i,(messages[i].Données[0]*256 + messages[i].Données[1])/10); break; // case LPP_GYROMETER: len = LPP_GYROMETER_SIZE-2 ; break ; // case LPP_GPS: len = LPP_GPS_SIZE-2 ; break ; } if (!output) { messages[i].neuf = 0; sentData = vrai; } } } if (sentData) { // Mettre à jour l'état cayCnt++; cayLast = getLocalTime(); Affichage(); } } CAYENNE_IN_DEFAULT() { uint8_t * pData; int val; int tou = request.channel; #ifdef DÉBOGAGE série.println("Cayenne recive"); série.printf("Données MQTT pour le canal %i = %s \n",tou,getValue.asString()); #endif switch (messages[tou].type) { case LPP_NUMÉRISAL_OUTPUT : messages[tou].Données[0] = getValue.asInt(); messages[tou].neuf = 1; break; case OUTPUT DE LPP_ANALOGIQUE : val = Round(getValue.asdouble()*100); messages[tou].Données[0] = val / 256; messages[tou].Données[1] = val % 256; messages[tou].neuf = 1; break; } }
3 commentaires
moi
für was genau ist der cayenne server zuständig?
kann ich auch einfach eine lokale ip eines mqtt servers eingeben und die pakete werden an diesen weiter geleitet?
Gerald Lechner
Hallo Marco
Ja du brauchst dafür einen zweiter ESP32 mit LoRa und im nächsten Teil folgt der notwendige Code.
Gruß Gerald
Marco
Hallo,
toller Artikel der Lust aufs Ausprobieren macht. Noch eine Frage. Ihr beschreibt hier das Gateway. Das “spricht” auf der einen Seite LoRa und auf der anderen Seite (via WLan) mit einem Netzwerk.
Ich bräuchte dann für die Kommunikation mittels LoRa dann noch einen zweiten ESP als Client, richtig? Könnt Ihr darüber vielleicht einen 4. Teil machen und erklären wie man dann damit ein Ende-Ende Szenario aufbaut?
Viele Grüße
Marco