Arbeiten mit dem Cayenne Dashboard - Verbessertes Gateway mit ESP-Now (Teil 6) - AZ-Delivery

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>&nbsp;</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.

 

Grundlagen software

2 commentaires

Roland

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

Roland

Jetzt spiele ich mich mit den Projekten von 1 bis 7
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!

Wie in der Beschreibung erwähnt startet aber der Access-Point „MQTTGateway“ nicht.
Was mache ich da falsch?

Laisser un commentaire

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

Articles de blog recommandés

  1. ESP32 jetzt über den Boardverwalter installieren - AZ-Delivery
  2. Internet-Radio mit dem ESP32 - UPDATE - AZ-Delivery
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1 - AZ-Delivery
  4. ESP32 - das Multitalent - AZ-Delivery