Utilisation du tableau de bord de Cayenne - Lora à mqtt (Partie 3)

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;   }    }

 

 

EtalagesEsp-32Projets pour avancé

3 commentaires

moi

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

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

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

Laisser un commentaire

Tous les commentaires sont modérés avant d'être publiés

Messages de blogs recommandés

  1. Installez maintenant ESP32 via l'administrateur de la carte
  2. Lüftersteuerung Raspberry Pi
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1
  4. ESP32 - das Multitalent
  5. OTA-Over the Air-ESP Programmation par WiFi