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

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

 

Grundlagen software

2 commenti

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?

Lascia un commento

Tutti i commenti vengono moderati prima della pubblicazione