Dopo ulteriori Test è riuscito il MQTT Gateway in modo da estendere i Dispositivi con ESP Now in grado di supportare. Ciò consente l'Utilizzo di molto poco costoso Schede su Base ESP8266. La Portata è, tuttavia, l'Area del locale Rete WIRELESS limitata. C'è ancora un altro Vincolo. ESPNow funziona solo con il wi-FI, il Canale 1. È pertanto necessario il Router per la Rete locale (ad esempio, Fritzbox) fix sul Canale 1.
Perché, finora, ESP Now solo la Connessione tra il Dispositivo e il Gateway per il lavoro ha portato, l'ESP-Now Dispositivo solo i Dati dei Sensori al Gateway di fornire, ma non i Comandi dal Gateway ottenere. Io, tuttavia, cercare di risolvere questo Problema e in questo Blog per la pubblicazione.
Il Codice contiene anche alcuni Miglioramenti e Correzione di un Errore durante il Salvataggio della lista dei Dispositivi, che poi si è verificato, se più di un Dispositivo registrato.
/* Il MQTT Gateway costituisce un'Interfaccia tra LoRa Dispositivi o ESP Nowe Dispositivi * e Cayenne MQTT Cruscotto. Funziona su ESP32 con LoRa e Display OLED * La Configurazione viene eseguita dal Browser */ #include <SPI.h> #include <LoRa.h> #include "SSD1306.h" #include<Arduino.h> #include <CayenneMQTTESP32.h> #include <CayenneLPP.h> #include <WiFi.h> #include <server Web.h> #include <time.h> #include "FS.h" #include "SPIFFS.h" #include <esp_now.h> //Server NTP per la Sincronizzazione del tempo #define NTP_SERVER "de.pool.ntp.org" #define GMT_OFFSET_SEC 3600 #define DAYLIGHT_OFFSET_SEC 0 //Pin per il LoRa Chip #define SS 18 #define RST 14 #define DI0 26 //Frequenza per il LoRa Chip #define BAND 433175000 //Pin per il Display Reset #define DISPLRESET 16 // #define MAXCHANNELS 256 //Numero massimo di Canali gestiti #define MAXDEVICE 32 //Numero massimo di Dispositivi gestiti MAXCHANNELS/MAXDEVICE = uguale a 8 il Numero massimo di Canali per Dispositivo di #define MAXKANAL 8 //Numero massimo di Canali per Dispositivo //Formato Flash Filesystem se non l'avete ancora fatto #define FORMAT_SPIFFS_IF_FAILED true #define APPWD "123456789" #define APCHANNEL 0 #define DEBUG 0 const String gwversion = "1.0"; //Piastrelle per il Web-Server const PROGMEM char HTML_HEADER[] = "<!DOCTYPE HTML>" "<html>" "<head>" "<meta name = \"vista\" content = \"width = device-width, initial-scale = 1.0, maximum-scale = 1.0, user-scalable=0>\">" "<meta http-equiv=\"content-type\" content=\"text/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:chiaro;font-size:10pt;}" "table th, td {border: 1px solid black;}" ".titolo {font-size:18pt;font-weight:bold;text-align:center;} " "</style>"; const PROGMEM char HTML_HEADER_END[] = "</head>" "<body><div style='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 style=\"width:100%\"><tr><th style=\"width:20%\">ID</th><th style=\"width:10%\">N.</th>" "<th style=\"width:20%\">Canali</th><th style=\"width:20%\">Nome</th>" "<th style=\"width:20%\">ultimi Dati</th><th style=\"width:10%\">Azione</th></tr>"; const PROGMEM char HTML_TAB_END[] = "</table>"; const PROGMEM char HTML_NEWDEVICE[] = "<div style=\"margin-top:20px;\">%s Nome: <input type=\"text\" style=\"width:200px\" name=\"devname\" maxlength=\"20\" value=\"\"> <button name=\"registrati\" value=\"%s\">Registrazione</button></div>"; const PROGMEM char HTML_TAB_ZEILE[] = "<tr><td>%s</td><td>%i</td><td>%i bis %i</td><td>%s</td><td>%s</td><td><button name=\"cancella\" value=\"%i\">Löschen</button></td></tr>"; const PROGMEM char HTML_CONFIG[] = "<form method=\"post\"><h1>Zugangsdaten</h1><table>" "<tr><td>WLAN SSID</td><td><input type=\"text\" name=\"ssid\" value=\"%s\" size=50 maxlen=30/a></td></tr>" "<tr><td>WLAN Passwort</td><td><input type=\"text\" name=\"password\" value=\"%s\" size=50 maxlen=30/a></td></tr>" "<tr><td>Cayenne Benutzername</td><td><input type=\"text\" name=\"mquser\" value=\"%s\" size=50 maxlen=40/></td></tr>" "<tr><td>Cayenne Passwort</td><td><input type=\"text\" name=\"mqpwd\" value=\"%s\" size=50 maxlen=50/></td></tr>" "<tr><td>Cayenne Client Id</td><td><input type=\"text\" name=\"mqid\" value=\"%s\" size=50 maxlen=40/></td></tr>" "<tr><td> </td><td><button name=\"salva\" value=>Salvare</button></td></tr>" "</table></form></body></html>"; //Datenstrukturen //Nachrichten Buffer struct MSG_BUF { uint8_t tip; uint8_t neu; uint8_t daten[10]; }; //Gerätedefinition struct DISPOSITIVO { uint8_t aktiv = 0; uint8_t dienst = 0; //0=LoRa, 1=ESP-Ora uint8_t id[6] = {0,0,0,0}; String nome, = ""; String ultimo = ""; }; //Variabile Globale //Zugangsdaten diese können über den Web-Server eingegeben werden Stringa wlanssid = "Lechner LAN"; Stringa wlanpwd = "Guadalquivir2711"; Stringa mqttuser = ""; Stringa mqttpwd = ""; Stringa mqttid = ""; //Webserver Instanz WebServer server(80); //OLED SSD1306 display(0x3c, 4, 15); //Buffer zum Zwischenspeichern der Nachrichten je Kanal MSG_BUF messaggi[MAXCHANNELS]; //Liste der definierten Geräte DISPOSITIVO dispositivi[MAXDEVICE]; //MQTT Stato int mqtt_con = 0; //Id eines nicht registrierten Gerätes uint8_t unbekannt[6]; //Flag di immer dann wahr wenn ein neues Gerät entdeckt wurde boolean neuesGeraet = false; //Typ des neuen Gerätes 0=LöRa 1 =ESPNow uint8_t neuesGeraetTyp = 0; //Zähler und Aktivitaets Stato für das Display uint32_t loraCnt = 0; //Anzahl der empfangenen LoRa Nachrichten Stringa loraLast = ""; //Datum und Zeit der letzten empfangenen LoRa Nachricht uint32_t nowCnt = 0; //Anzahl der empfangenen ESP Ora Nachrichten Stringa nowLast = ""; //Datum und Zeit der letzten empfangenen LoRa Nachricht uint32_t cayCnt = 0; //Anzahl der gesendeten MQTT Nachrichten Stringa cayLast = ""; //Datum und Zeit der letzten gesendeten MQTT Nachricht //Funzione ritorna con la sua Datum und Uhrzeit im Formato yyyy-mm-dd hh:mm:ss als Stringa Stringa getLocalTime() { char sttime[20] = ""; struct tm timeinfo; se (WiFi.di stato() == WL_CONNECTED) { se(!getLocalTime(&timeinfo)){ di Serie.println("non è Riuscito a ottenere il tempo di"); ritorno sttime; } strftime(sttime, sizeof(sttime), "%Y-%m-%d %H:%M:%S", &timeinfo); } ritorno sttime; } //Funzione ritorna con la sua eine 6 Byte Geräte-Id im formato xx:xx:xx:xx:xx:xx als Stringa Stringa getId(uint8_t id[6]) { Stringa di stid; char tmp[4]; sprintf(tmp,"%02x",id[0]); stid=tmp; per (uint8_t j = 1; j<6; j++) { sprintf(tmp,":% 02x",id[j]); STID = STID += tmp ; } ritorno STID; } La funzione // fornisce parte di un buffer di dati in formato xx, xx, xx .... come stringa stringa getData(uint8_t buf[], uint8_t inizio, uint8_t fine) { stringa STDATA; carbonizzare tmp[4]; sprintf(tmp,"% 02x",buf[inizio]); STDATA=tmp; per (uint8_t j = inizio+1; j<fine; j++) { sprintf(tmp,",% 02x",buf[j]); STDATA = STDATA += tmp ; } ritorno STDATA; } // prepara il buffer dei messaggi // imposta tutti i messaggi su done vuoto buffer dei messaggi init() { per (int io = 0;io<MaxChannels;io++) { messaggi[io].nuovo = 0; } } // Funzione per salvare la configurazione vuoto scrivi configurazione(const carbonizzare *fn) { file f = spiffs.aperto(fn, file_write); se (!f) { serial.println(F("ERRORE: SPIFFS Impossibile salvare la configurazione")); ritorno; } per (uint8_t io = 0; io<MAXDEVICE; io++) { f.stampare(dispositivi[io].attivamente);f.stampare('\ n'); se (dispositivi[io].attivamente) { f.stampare(dispositivi[io].servizio);f.stampare('\ n'); f.stampare(getId(dispositivi[io].id));f.stampare('\ n'); f.stampare(dispositivi[io].nome);f.stampare('\ n'); f.stampare(dispositivi[io].carico);f.stampare('\ n'); } altro { f.printf("0 \ n00: 00: 00: 00: 00: 00 \ n- \ n- \ n"); } } } // Funzione per la memorizzazione dei dati di accesso vuoto accesso in scrittura(const carbonizzare *fn) { file f = spiffs.aperto(fn, file_write); se (!f) { serial.println(F("ERRORE: SPIFFS non può salvare i dati di accesso")); ritorno; } f.stampare("WLANSSID =");f.stampare(wlanssid);f.stampare('\ n'); f.stampare("WLANPWD =");f.stampare(wlanpwd);f.stampare('\ n'); f.stampare("MQTTUSER =");f.stampare(mqttuser);f.stampare('\ n'); f.stampare("MQTTPWD =");f.stampare(mqttpwd);f.stampare('\ n'); f.stampare("MQTTID =");f.stampare(mqttid);f.stampare('\ n'); } // Funzione per la lettura della configurazione vuoto configurazione della lettura(const carbonizzare *fn) { uint8_t io = 0; stringa tmp; carbonizzare hex[3]; se (!spiffs.esiste(fn)) { // non esiste ancora quindi crea scrivi configurazione(fn); ritorno; } file f = spiffs.aperto(fn, "R"); se (!f) { serial.println(F("ERRORE :: SPIFFS Impossibile aprire la configurazione")); ritorno; } #ifdef DEBUG serial.println("Leggi elenco dispositivi"); #endif mentre (f.disponibile() && (io<MAXDEVICE)) { serial.printf("Leggi dispositivo% i",io); tmp = f.readStringUntil('\ n'); dispositivi[io].attivamente = (tmp == "1"); tmp = f.readStringUntil('\ n'); dispositivi[io].servizio = tmp.Toint(); tmp = f.readStringUntil('\ n'); per (uint8_t j=0; j<6; j++){ hex[0]=tmp[j*3]; hex[1]=tmp[j*3+1]; hex[2]=0; dispositivi[io].id[j]= (byte) strtol(hex,NULL,16); } tmp = f.readStringUntil('\ n'); dispositivi[io].nome = tmp; tmp = f.readStringUntil('\ n'); dispositivi[io].carico = tmp; #ifdef DEBUG serial.stampare("Dispositivo"+getId(dispositivi[io].id)+ "Nome" + dispositivi[io].nome); serial.printf("Servizio% i attivo% i \ r \ n",dispositivi[io].servizio,dispositivi[io].attivamente); #endif io++; } } // Funzione per la lettura dei dati di accesso vuoto accesso in lettura(const carbonizzare *fn) { uint8_t io = 0; stringa chiave; stringa val; carbonizzare hex[3]; se (!spiffs.esiste(fn)) { // non esiste ancora quindi crea accesso in scrittura(fn); ritorno; } file f = spiffs.aperto(fn, "R"); se (!f) { serial.println(F("ERRORE :: SPIFFS non può aprire i dati di accesso")); ritorno; } mentre (f.disponibile() && (io<MAXDEVICE)) { chiave = f.readStringUntil('='); val = f.readStringUntil('\ n'); se (chiave == "WLANSSID") wlanssid = val; se (chiave == "WLANPWD") wlanpwd = val; se (chiave == "MQTTUSER") mqttuser = val; se (chiave == "MQTTPWD") mqttpwd = val; se (chiave == "MQTTID") mqttid = val; } } // Funzione per la registrazione di un nuovo dispositivo vuoto geraetRegistrieren() { uint8_t io = 0; // cerca l'ingresso gratuito mentre ((io<MAXDEVICE) && dispositivi[io].attivamente) io++; // se non ci sono nuove voci, non facciamo nulla se (io < MAXDEVICE) { // altrimenti registra Nome dispositivo = nome inserito // o sconosciuto se non ne è stato inserito nessuno se (server.hasArg("Devname")) { dispositivi[io].nome = server.cattivo("Devname"); } altro { dispositivi[io].nome = "Sconosciuto"; } per (uint8_t j = 0; j<6; j++) dispositivi[io].id[j]=sconosciuto[j]; dispositivi[io].attivamente = 1; dispositivi[io].servizio= nuovo tipo di dispositivo; dispositivi[io].carico = ""; scrivi configurazione("/Konfiguration.csv"); nuovo dispositivo = falso; } } // La pagina di configurazione viene visualizzata dal server Web vuoto handleConfig(){ carbonizzare htmlbuf[1024]; booleano nuovo inizio = falso; int indice; // è stato premuto il pulsante di memoria? se (server.hasArg("Salva")) { // Dati dalla richiesta POST wlanssid = server.cattivo("SSID"); // se il SSID contiene uno spazio otteniamo un "+" // questo deve essere riconvertito in uno spazio per la registrazione wlanssid.sostituire("+"," "); wlanpwd = server.cattivo("PWD"); mqttuser = server.cattivo("Mquser"); mqttpwd = server.cattivo("Mqpwd"); mqttid = server.cattivo("Mqid"); serial.println("Nuova configurazione:"); serial.stampare("SSID");serial.println(wlanssid); serial.stampare("Password");serial.println(wlanpwd); serial.stampare("Utente");serial.println(mqttuser); serial.stampare("Password");serial.println(mqttpwd); serial.stampare("ID");serial.println(mqttid); // Salva la nuova configurazione in SPIFFS accesso in scrittura("/Zugang.txt"); // ricordiamo che è necessario riavviare la connessione WiFi // ma prima il web server deve consegnare la pagina HTML nuovo inizio = vero; } // Uscita della pagina di configurazione // creiamo puntatori alla memoria interna delle stringhe di accesso // per usarlo per sprintf e per avviare la connessione WiFi e Cayenne carbonizzare* txtSSID = const_cast<carbonizzare*>(wlanssid.c_str()); carbonizzare* txtPassword = const_cast<carbonizzare*>(wlanpwd.c_str()); carbonizzare* txtUser = const_cast<carbonizzare*>(mqttuser.c_str()); carbonizzare* txtPWD = const_cast<carbonizzare*>(mqttpwd.c_str()); carbonizzare* txtID = const_cast<carbonizzare*>(mqttid.c_str()); // Invia la pagina HTML corrente al browser server.setContentLength(CONTENT_LENGTH_UNKNOWN); // header server.trasmissione(200, "testo / html",HTML_HEADER); server.Invia contenuti(HTML_HEADER_END); // Il modulo con i campi di input è riempito con i valori correnti sprintf(htmlbuf,HTML_CONFIG,txtSSID,txtPassword,txtUser,txtPWD,txtID); // e inviato al browser server.Invia contenuti(htmlbuf); server.Invia contenuti(HTML_END); se (nuovo inizio) { // Se è stato impostato il flag di riavvio, la connessione WiFi deve essere disconnessa e nuova // essere costruito mqtt_con = 0; serial.println("Restart"); uint8_t timeout = 0; serial.println("Disconnect"); WiFi.disconnect(); mentre ((WiFi.stato() == WL_CONNECTED) && (timeout < 10)) { ritardo(1000); timeout++; } serial.println("Reconnect"); WiFi.iniziare(txtSSID,txtPassword); mentre ((WiFi.stato() != WL_CONNECTED) && (timeout < 10)) { ritardo(1000); timeout++; } serial.stampare("Indirizzo IP:"); serial.println(WiFi.LocalIP()); se (WiFi.stato() == WL_CONNECTED) { // se il riavvio ha avuto esito positivo, è necessario ristabilire anche la connessione a Cayenne. se ((mqttuser != "")&&(mqttpwd != "") && (mqttid != "")) { serial.println("Connect Cayenne"); caienna.iniziare(txtUser, txtPWD, txtID); mqtt_con = 1; } // sincronizza l'orologio con il time server configTime(GMT_OFFSET_SEC, DAYLIGHT_OFFSET_SEC, NTP_SERVER); // Ora corrente di uscita serial.println(GetLocalTime()); } } } // La pagina di ripristino è stata interrogata dal server web vuoto handleReset() { //wir setzen morire Zugangsdaten zurück wlanssid= ""; wlanpwd = ""; mqttuser = ""; mqttpwd=""; mqttid=""; //und zeigen morire Konfigurationsdaten un' //erst wenn auf der Konfigurationsseite der Pulsante //Speichern geklickt wird, werden die Zugangsdaten //auch im SPIFFS gelöscht. handleConfig(); } //Die Seite mit der Geräteliste wurde vom Webserver abgefragt void handleWLANRequest(){ char htmlbuf[512]; char tmp1[20]; char tmp2[20]; char tmp3[20]; int indice; //wurde der Lösch Knopf geklickt ? se il (server.hasArg("elimina")) { indice di = server.arg("elimina").toInt(); #ifdef DEGUG di Serie.printf("Lösche periferica %i = ",indice); di Serie.println(dispositivi[indice].nome); #endif dispositivi[indice].aktiv=0; schreibeKonfiguration("/konfiguration.csv"); } //wurde der Registrieren Knopf geklickt ? se il (server.hasArg("registrare")) { geraetRegistrieren(); Serial.system.out.println("Configurazione viene salvata"); schreibeKonfiguration("/configurazione.csv"); } //Corrente in una Pagina HTML invia al Browser server.setContentLength(CONTENT_LENGTH_UNKNOWN); //Header server.send(200, "text/html",HTML_HEADER); //Indirizzo IP per il reload script WiFi.localIP().toString().toCharArray(tmp1,20); sprintf(htmlbuf,HTML_SCRIPT,tmp1); server.sendContent(htmlbuf); server.sendContent(HTML_HEADER_END); //Modulo di Inizio server.sendContent("<div class=\"titolo\">MQTT Gateway</div><form method=\"post\">"); //Tabella dei Dispositivi attivi server.sendContent(HTML_TAB_GERAETE); for (uint8_t i = 0; i<MAXDEVICE; i++) { if (devices[i].attivo == 1) { getId(devices[i].id).toCharArray(tmp1,20); devices[i].nome.toCharArray(tmp2,20); devices[i].last.toCharArray(tmp3,20); sprintf(htmlbuf,HTML_TAB_ZEILE,tmp1,i,i*8,i*8+7,tmp2,tmp3,i); server.sendContent(htmlbuf); } } server.sendContent(HTML_TAB_END); //Se viene rilevata una nuova Periferica è il suo ID e un Campo per il Nome // e un Pulsante per la Registrazione del nuovo Dispositivo di errore if (neuesGeraet) { getId(sconosciuta).toCharArray(tmp1,20); sprintf(htmlbuf,HTML_NEWDEVICE,tmp1,tmp1); server.sendContent(htmlbuf); } server.sendContent(HTML_END_RELOAD); } /Servizio/Funzione di Web Server per il Root Directory void handleRoot() { if (WiFi.di stato() != WL_CONNECTED) { //se non siamo in Routernetz hanno //viene visualizzata la pagina di Configurazione, in modo che le Credenziali di accesso possono essere immessi handleConfig(); } else { handleWLANRequest(); } } //Funzione per la Ricerca di un Dispositivo nell'Elenco delle periferiche //Restituzione Indice dell'Apparecchio o -1 se non è stato trovato int findDevice(uint8_t dev[6]) { uint8_t j; uint8_t i = 0; boolean found = false; do { j = 0; if (devices[i].attivo == 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;} } //Funzione per la Visualizzazione dello Stato del Display OLED void display() { display.clear(); display.coulisse(0,0,"MQTT Gateway "+gwversion); display.coulisse(0,10,getLocalTime()); display.coulisse(0,20,WiFi.localIP().toString()); display.coulisse(0,34,"MQTT: "); display.coulisse(60,34,String(cayCnt)); display.coulisse(0,44,"LoRa: "); display.coulisse(60,44,String(loraCnt)); display.coulisse(0,54,"NOW: "); display.coulisse(60,54,String(nowCnt)); display.display(); } //Dati Ricevuti in Nachrichtenbuffer salvare //Restituisce il Numero del dispositivo o -1 se non è registrato uint8_t processData(uint8_t buf[], , int buflen) { int devnr; int indice; uint8_t devid[6]; uint8_t channel; uint8_t tipo; uint8_t len; uint8_t i; boolean output; indice = 0; while ((indice < 6) && (indice < buflen)) { devid[indice] = buf[indice]; indice++; } #ifdef DEBUG serial.stampare("ID dispositivo =");serial.println(getId(devid)); #endif // controlla se il dispositivo è registrato devnr = dispositivo posto(devid); se (devnr >= 0) { #ifdef DEBUG serial.println(GetLocalTime()); serial.stampare("Numero dispositivo =");serial.println(devnr); #endif // se sì, impostiamo il timestamp per l'ultimo messaggio e // leggi i dati dispositivi[devnr].carico = GetLocalTime(); //writeconfiguration("/konfiguration.csv "); // ora legge i dati mentre (indice < buflen) { canale = buf[indice++]+devnr*CANALE MAX; se (indice == buflen) pausa; tipo = buf[indice++]; produzione = falso; interruttore(tipo) { caso LPP_DIGITAL_INPUT : len = LPP_DIGITAL_INPUT_SIZE - 2; pausa; caso LPP_DIGITAL_OUTPUT : len = LPP_DIGITAL_OUTPUT_SIZE - 2; produzione = vero; pausa; caso LPP_ANALOG_INPUT : len = LPP_ANALOG_INPUT_SIZE - 2; pausa; caso LPP_ANALOG_OUTPUT : len = LPP_ANALOG_OUTPUT_SIZE - 2; produzione = vero; pausa; caso LPP_LUMINOSITY : len = LPP_LUMINOSITY_SIZE - 2; pausa; caso LPP_PRESENCE : len = LPP_PRESENCE_SIZE - 2; pausa; caso LPP_TEMPERATURE : len = LPP_TEMPERATURE_SIZE - 2; pausa; caso LPP_RELATIVE_HUMIDITY : len = LPP_RELATIVE_HUMIDITY_SIZE - 2; pausa; caso LPP_ACCELEROMETER : len = LPP_ACCELEROMETER_SIZE - 2; pausa; caso LPP_BAROMETRIC_PRESSURE : len = LPP_BAROMETRIC_PRESSURE_SIZE - 2; pausa; caso LPP_GYROMETER : len = LPP_GYROMETER_SIZE - 2; pausa; caso LPP_GPS : len = LPP_GPS_SIZE - 2; pausa; difetto: len = 0; } // se il canale non è un attuatore, ripristiniamo 1 nel buffer dei messaggi // in modo che i dati vengano inviati al server MQTT alla prossima occasione se (!produzione) messaggi[canale].nuovo =1; messaggi[canale].tipo = tipo; io = 0; mentre ((io<len) && (indice < buflen)) { se (!produzione) messaggi[canale].dati[io] = buf[indice]; io++; indice++; } #ifdef DEBUG serial.printf("Canale% i tipo% i dati:",canale,tipo);serial.println(getData(messaggi[canale].dati,0,len)); #endif } ritorno devnr; } altro { per (uint8_t io = 0; io<6; io++) sconosciuto[io] = devid[io]; nuovo dispositivo = vero; ritorno -1; } } uint8_t modulo di risposta(uint8_t buf[], uint8_t devnr) { // controlliamo se disponiamo di dati di output per il dispositivo LoRa corrente int indice = 6; // i primi sei byte sono l'ID del dispositivo int devbase = devnr*CANALE MAX; #ifdef DEBUG serial.printf("Attivatori per dispositivo% i canale da% i a% i \ r \ n",devnr,devbase,devbase+8); #endif per (int io = devbase; io<devbase+8; io++) { // a seconda del tipo di dati digitali o analogici interruttore (messaggi[io].tipo) { caso LPP_DIGITAL_OUTPUT : buf[indice++]= io-devbase; buf[indice++]=messaggi[io].tipo; buf[indice++]=messaggi[io].dati[0]; #ifdef DEBUG serial.println("Uscita digitale"); #endif pausa; caso LPP_ANALOG_OUTPUT : buf[indice++]= io-devbase; buf[indice++]=messaggi[io].tipo; buf[indice++]=messaggi[io].dati[0]; buf[indice++]=messaggi[io].dati[1]; #ifdef DEBUG serial.println("Uscita analogica"); #endif pausa; } } ritorno indice; } // Elabora un messaggio da un client LoRa vuoto readLoRa() { uint8_t buf[256]; int ix; int devnr; uint8_t len; uint8_t byt; // recupera i dati se disponibili int dimensione del pacchetto = LoRa.parsePacket(); // abbiamo ricevuto dati? se (dimensione del pacchetto > 0) { #ifdef DEBUG serial.printf("% i byte ricevuti da LoRa \ r \ n",dimensione del pacchetto); #endif mentre ((ix < dimensione del pacchetto) && (ix < 256)) { byt= LoRa.leggere(); // Serial.printf ("% 2x", byt); buf[ix++] = byt; } // Serial.println (); #ifdef DEBUG serial.println(getData(buf,0,dimensione del pacchetto)); #endif devnr = processData(buf, dimensione del pacchetto); se (devnr >=0) { // aggiorna lo stato loraCnt++; loraLast = GetLocalTime(); } altro { nuovo tipo di dispositivo = 0; // Dispositivo LoRa } // Invia la risposta della seconda parte al dispositivo LoRa // ritardo (500); // L'ID dispositivo si trova già nei primi sei byte del buffer len = 6; // se disponiamo di un dispositivo registrato, inviamo anche dati se (devnr >= 0) len = modulo di risposta(buf, devnr); #ifdef DEBUG serial.printf("Invia al dispositivo% i% i byte \ r \ n",devnr,len); serial.println(getData(buf,0,len)); #endif LoRa.cominciare pacchetto(); LoRa.write(buf,len); int stato dell'olio = LoRa.endPacket(); #ifdef DEBUG serial.stampare("Invia stato ="); serial.println(stato dell'olio); #endif } } // callback per ESP Now vuoto readESPNow(const uint8_t *mac_addr, const uint8_t *R_DATA, int data_len) { uint8_t dati[70]; uint8_t devnr; uint8_t len; #ifdef DEBUG serial.printf("% i byte ricevuti da ESP-Now \ r \ n",data_len); #endif memcpy(&dati, R_DATA, sizeof(dati)); devnr = processData(dati,data_len); se (devnr >=0) { // aggiorna lo stato nowCnt++; nowLast = GetLocalTime(); } altro { nuovo tipo di dispositivo = 1; // ESP Now dispositivo } ritardo(100); // Invia la risposta della seconda parte al dispositivo ESP-Now // L'ID dispositivo si trova già nei primi sei byte del buffer len = 6; // se disponiamo di un dispositivo registrato, inviamo anche dati se (devnr >= 0) len = modulo di risposta(dati, devnr); #ifdef DEBUG serial.printf("Invia al dispositivo% i% i byte \ r \ n",devnr,len); serial.println(getData(dati,0,len)); #endif esp_now_send(dati, dati, len); #ifdef DEBUG serial.println("End"); #endif } vuoto configurazione() { // inizializza la memoria del dispositivo per (uint8_t io =0; io<MAXDEVICE; io++) dispositivi[io].attivamente = 0; // Inizializza il display OLED pinMode(DISPLRESET,USCITA); digitalWrite(DISPLRESET, LOW); ritardo(50); digitalWrite(DISPLRESET, ALTA); display.init(); display.flipScreenVertically(); display.setFont(ArialMT_Plain_10); display.setTextAlignment(TEXT_ALIGN_LEFT); // Avvia l'interfaccia seriale serial.iniziare(115200); mentre (!serial); serial.println("Start"); // File system Flash se (spiffs.iniziare(FORMAT_SPIFFS_IF_FAILED)) serial.println(F("SPIFFS caricato")); // Leggi i dati di configurazione e di accesso configurazione della lettura("/Konfiguration.csv"); accesso in lettura("/Zugang.txt"); buffer dei messaggi init(); // Inizializza SPI e LoRa SPI.iniziare(5,19,27,18); LoRa.setPins(SS,RST,DI0); serial.println("LoRa TRX"); se (!LoRa.iniziare(BAND)) { serial.println("Avvio di LoRa fallito!"); mentre (1); } LoRa.enableCrc(); serial.println("LoRa Initial OK!"); ritardo(2000); // Uscita dei dati di accesso in lettura per il controllo serial.stampare("SSID");serial.println(wlanssid); serial.stampare("Password");serial.println(wlanpwd); serial.stampare("Utente");serial.println(mqttuser); serial.stampare("Password");serial.println(mqttpwd); serial.stampare("ID");serial.println(mqttid); // Connettersi al server WLAN e MQTT serial.println("Connetti WLAN"); // usiamo ESP32 come punto di accesso ma anche come client nella rete del router WiFi.moda(WIFI_AP_STA); // abbiamo bisogno di puntatori alla memoria dei caratteri all'interno delle stringhe carbonizzare* txtSSID = const_cast<carbonizzare*>(wlanssid.c_str()); carbonizzare* txtPassword = const_cast<carbonizzare*>(wlanpwd.c_str()); carbonizzare* txtUser = const_cast<carbonizzare*>(mqttuser.c_str()); carbonizzare* txtPWD = const_cast<carbonizzare*>(mqttpwd.c_str()); carbonizzare* txtID = const_cast<carbonizzare*>(mqttid.c_str()); // Indipendentemente dalla connessione alla rete del router, avviamo AccessPoint // che consente la configurazione tramite browser se questo è disponibile // accedere al punto di accesso WiFi.SofTap("MQTTGateway",APPWD,APCHANNEL,0); //In Routernetz viene stabilita WiFi.begin(txtSSID, txtPassword); uint8_t timeout = 0; while ((WiFi.di stato() != WL_CONNECTED) && (timeout<10)) { timeout++; delay(1000); } //siamo in attesa di un massimo di 10 Secondi fino a quando la Connessione è if (WiFi.di stato() == WL_CONNECTED) { //la Connessione Era in Routernetz successo, dobbiamo iniziare a MQTT a Cayenne //e sincronizzare l'Orologio interno con il Time Server Serial.print("IP address: "); Serial.system.out.println(WiFi.localIP()); if ((mqttid != "") && (mqttuser != "") && (mqttpwd != "")) { Serial.system.out.println("State MQTT"); Cayenne.begin(txtUser, txtPwd, txtId); Serial.system.out.println("Cayenne Connessione"); mqtt_con = 1; } //Orologio con un server di riferimento orario di sincronizzare configTime(GMT_OFFSET_SEC, DAYLIGHT_OFFSET_SEC, NTP_SERVER); //Ora Corrente spendere Serial.system.out.println(getLocalTime()); } //Web Server inizializzare il server.on("/", handleRoot); server.on("/conf",handleConfig); server.on("/reset",handleReset); server di.iniziare(); se (esp_now_init() == ESP_OK) di Serie.println("ESP-Ora initialisiert!"); esp_now_register_recv_cb(readESPNow); di Serie.println("*********************************************"); } void loop() { anzeige(); se (WiFi.di stato() == WL_CONNECTED) { //LoRa Interfaccia auf Daten prüfen readLoRa(); //mit Cayenne MQTT Server kommunizieren se (mqtt_con == 1) Cayenne.loop(1); } //Web Server bedienen server.handleClient(); ritardo(100); } //Daten aus dem Nachrichtenbuffer an den MQTT Server senden CAYENNE_OUT_DEFAULT() { boolean uscita = false; boolean sentData = false; float val; #ifdef DEBUG Seriale.println(getLocalTime()); di Serie.println(Cayenne, inviare"); #endif per (int io = 0; ho<MAXCHANNELS; i++) { //nur neue Nachrichten senden se (i messaggi[che ho].neu == 1) { #ifdef DEBUG Seriale.printf("Sende MQTT Kanal %i Tip %i\n",,i,messaggi[che ho].tip); #endif //je nach Tip Daten senden passare (messaggi[ho].tip) { caso LPP_DIGITAL_INPUT : Cayenne.digitalSensorWrite(i,messaggi[ho].daten[0]); pausa; caso LPP_DIGITAL_OUTPUT : uscita = vera; pausa; caso LPP_ANALOG_INPUT : val = (messaggi[ho].daten[0]*256 + messaggi[ho].daten[1]);Cayenne.virtualWrite(ho,val/100,"analog_sensor",UNIT_UNDEFINED); pausa; pausa; caso LPP_ANALOG_OUTPUT : uscita = vera; pausa; caso LPP_LUMINOSITY : Cayenne.luxWrite(i,messaggi[ho].daten[0]*256 + messaggi[ho].daten[1]); pausa; caso LPP_PRESENCE : Cayenne.digitalSensorWrite(i,messaggi[ho].daten[0]); pausa; caso LPP_TEMPERATURE : val = (messaggi[ho].daten[0]*256 + messaggi[ho].daten[1]); Cayenne.celsiusWrite(ho,val/10); pausa; caso LPP_RELATIVE_HUMIDITY : val=messaggi[ho].daten[0];Cayenne.virtualWrite(ho,val/2,TYPE_RELATIVE_HUMIDITY,UNIT_PERCENT); pausa; caso LPP_ACCELEROMETER : val = (messaggi[ho].daten[0]*256 + messaggi[ho].daten[1]);Cayenne.virtualWrite(ho,val/1000,"gx","g"); pausa; caso LPP_BAROMETRIC_PRESSURE : val = (messaggi[ho].daten[0]*256 + messaggi[ho].daten[1]);Cayenne.hectoPascalWrite(ho,val/10); di interruzione; //caso LPP_GYROMETER : len = LPP_GYROMETER_SIZE - 2; break; //caso LPP_GPS : len = LPP_GPS_SIZE - 2; break; } se (!l'output) { dei messaggi[ho].neu = 0; sentData = vero; } } } se (sentData) { //Stato aktualisieren cayCnt++; cayLast = getLocalTime(); } } CAYENNE_IN_DEFAULT() { uint8_t * pData; int val; int ch = richiesta.canale; #ifdef DEBUG Seriale.println("Cayenne ricevere"); Seriale.printf("MQTT Daten für Kanal %i = %s\n",, ch,getValue.asString()); #endif passare (messaggi[ch].tip) { caso LPP_DIGITAL_OUTPUT : messaggi[ch].daten[0] = getValue.asInt(); messaggi[ch].neu = 1; pausa; caso LPP_ANALOG_OUTPUT : val = giro(getValue.asDouble()*100); messaggi[ch].daten[0] = val / 256; messaggi[ch].daten[1] = val % 256; messaggi[ch].neu = 1; pausa; } CAYENNE_LOG("Canale %u, %valore s", richiesta.canale, getValue.asString()); //Processo messaggio qui. Se c'è un errore di impostare un messaggio di errore tramite getValue.setError(), e.g getValue.setError("messaggio di Errore"); }
Das Display zeigt jetzt auch eine Versionsnummer un. More Informationen zu diesem Gateway findet Ihr den anderen Teilen dieser Serie.
2 commenti
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?