Werken met het Cayenne Dashboard - Verbeterde gateway met ESP-Now (Deel 6)

Na verder testen slaagde ik erin om de MQTT Gateway uit te breiden, zodat het apparaten met ESP-Now kan ondersteunen. Dit maakt het gebruik van de zeer goedkope boards op basis van de ESP8266. Het bereik is dan echter beperkt tot het gebied van het lokale Wlan-netwerk. Er is een andere beperking. ESPNow werkt alleen met Wi-Fi kanaal 1. Het is daarom noodzakelijk om de router voor het lokale netwerk (bijvoorbeeld Fritzbox) in te stellen op kanaal 1.

Aangezien ik voorheen alleen de ESP-Now-verbinding van het apparaat naar de gateway naar het werk bracht, kan het ESP-Now-apparaat alleen gegevens van sensoren naar de gateway leveren, maar geen opdrachten van de gateway ontvangen. Echter, ik zal proberen om dit probleem op te lossen en post het op deze blog.

De code bevat ook een aantal verbeteringen en de oplossing voor een fout opslaan van het apparaat lijst, die zich voordeed toen meer dan een apparaat werd geregistreerd.

 

/* De MQTT Gateway vormt een interface tussen LoRa-apparaten of ESP Nowe-apparaten 
 * en Cayenne MQTT dashboards. Het draait op ESP32 met LoRa en OLED-scherm
 * De configuratie wordt gedaan door de browser
 */
#include <Spi.H>
#include <Lora.H>
#include "SSD1306.h"
#include<Arduino.H>
#include <CayenneMQTTESP32.H>
#include <CayenneLPP CayenneLPP.H>
#include <Wifi.H>
#include <Web.H>
#include <Tijd.H>
#include "FS.h"
#include "SPIFFS.h"
#include <esp_now.H>

NTP-server voor tijdsynchronisatie
#define NTP_SERVER "de.pool.ntp.org"
#define GMT_OFFSET_SEC 3600
#define DAYLIGHT_OFFSET_SEC 0

Pinnen voor de LoRa-chip
#define Ss      18
#define Rst     14
#define DI0     26
Frequentie voor de LoRa-chip
#define Band    433175000

Vastmaken voor het opnieuw instellen van het scherm
#define DISPLRESET 16

//
#define MAXKANALEN 256 maximaal aantal beheerde kanalen
#define MAXDEVICE 32 maximaal aantal beheerde apparaten MAXCHANNELS/MAXDEVICE = 8 resulteert in het maximum aantal kanalen per apparaat
#define MAX-KANAAL 8 maximaal aantal kanalen per apparaat

Flash Filesystem opmaken als dit nog niet is gedaan
#define FORMAT_SPIFFS_IF_FAILED Waar

#define APPWD "123456789"
#define APCHANNEL 0

#define Debug 0

Const Tekenreeks gwversie = "1.0";

Bouwstenen voor de webserver
Const PROGMEM Char HTML_HEADER[] =
"<! DOCTYPE HTML>"
"<html>"
"<head>"
"<metaname = "viewport" 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>"
"<stijl>"
"lichaam - achtergrond-kleur: #d2f3eb; lettertype-familie: Arial, Helvetica, Sans-Serif; Kleur: #000000;tekengrootte:12pt; }"
"de achtergrondkleur: #b6c0db; kleur: #050ed2;lettertypegewicht:lichter;tekengrootte:10pt;
"tabel, th, td "rand: 1px effen zwart;"
".titel .font-size:18pt;font-weight:bold;text-align:center; "
"</stijl>";

Const PROGMEM Char HTML_HEADER_END[] = 
"</hoofd>"
"<body><div style='margin-left:30px;' >";

Const PROGMEM Char HTML_SCRIPT[] =
"<scripttaal="javascript">"
"functie herladen()
"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%">No.</th>"
"<th style=""width:20%">Channels</th><th style="width:20%">Name</th>"
"<th style=""width:20%">Recent Data</th><th style="width:10%">Action</th></tr>";
Const PROGMEM Char HTML_TAB_END[] =
"</tabel>";
Const PROGMEM Char HTML_NEWDEVICE[] =
"<div style=""margin-top:20px;">%s Name: <input type="text" style="width:200px" name="devname"" maxlength="20" value="> <name="register" value="%s">Register</button></div>";
Const PROGMEM Char HTML_TAB_ZEILE[] =
"<tr><td>%s</td><td>%i</td><td>%i tot %i</td><td>%s>%s>%s>Lt;//td><td>%s</td><td><button name="delete" value="%i">Delete</button></td></tr>";
Const PROGMEM Char HTML_CONFIG[] = 
"<form method="post"><h1>Access data</h1><table>"
"<tr><td>WLAN SSID</td><td><input type="text"" name="ssid" value="%s" size=50 maxlen=30/></td>></tr>"
"<tr><td>WLAN Password</td><td><input type="text" name="pwd" value="%s" size=50 maxlen=30/><td></tr>"
"<tr><td>Cayenne Gebruikersnaam</td><td><input type="text"" name="mquser" value="%s" size=50 maxlen=40/></td></tr>"
"<tr><td>Cayenne Password</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="save" value=>Save</button></td></tr>"
"</table></form></body></html>";

Structuren
Nieuws Buffer
Struct MSG_BUF {   uint8_t Type;   uint8_t Nieuw;   uint8_t Gegevens[10];
};

Apparaatdefinitie
Struct Apparaat {   uint8_t Actieve = 0;   uint8_t Service = 0; 0=LoRa, 1=ESP-Nu   uint8_t Id[6] = {0,0,0,0};   Tekenreeks Naam = "";   Tekenreeks Laatste = "";
};

Globale variabele
Toegang tot gegevens deze kunnen worden ingevoerd via de webserver
Tekenreeks wlanssid wlanssid = "Lechner LAN";
Tekenreeks wlanpwd wlanpwd wlanpwd = "Guadalquivir2711";
Tekenreeks mqttuser = "";
Tekenreeks mqttpwd = "";
Tekenreeks mqttid = "";

Webserverinstantie
Web Server(80);

OLED-scherm
SSD1306  Weergeven(0x3c, 4, 15);

Buffer voor cachingberichten per kanaal
MSG_BUF Berichten[MAXKANALEN];

Lijst van gedefinieerde hulpmiddelen
Apparaat Apparaten[MAXDEVICE];

MQTT-status
Int mqtt_con = 0;
Id van een niet-geregistreerd apparaat
uint8_t Onbekende[6];
Vlag altijd waar wanneer een nieuw apparaat wordt gedetecteerd
Booleaanse newGeraet = Valse;
Type nieuw apparaat 0=LöRa 1 =ESPNow
uint8_t newGeraetType = 0;

Counters en activiteiten Status voor het display
uint32_t loraCnt loraCnt = 0; Aantal ontvangen LoRa-berichten
Tekenreeks loraLast = ""; Datum en tijd van laatst ontvangen LoRa-bericht
uint32_t nowCnt = 0; Aantal ontvangen ESP Now-berichten
Tekenreeks nowLast = ""; Datum en tijd van laatst ontvangen LoRa-bericht
uint32_t cayCnt = 0; Aantal verzonden MQTT-berichten
Tekenreeks cayLast = ""; Datum en tijd van laatst verzonden MQTT-bericht


Functie retourneert datum en tijd in het formaat yyyy-mm-dd hh:mm:ss als een tekenreeks
Tekenreeks getLocalTime()
{   Char sttime[20] = "";   Struct Tm timeinfo;   Als (Wifi.Status() == WL_CONNECTED) {     Als(!getLocalTime(&timeinfo)){       Seriële.println("Niet om tijd te verkrijgen");       Terug sttime;     }     Strftime Strftime Strftime(sttime, Grootte van(sttime), "%Y-%m-%d %H:%M:%S", &timeinfo);   }   Terug sttime;
}

Funktion liefert eine 6-Byte Geräte-Id im format xx:xx:xx:xx:xx:xx als String
Tekenreeks Getid (Getid)(uint8_t Id[6])
{   Tekenreeks stid;   Char Tmp[4];   Sprintf (Sprintf)(Tmp,"%02x",Id[0]);   stid=Tmp;   Voor (uint8_t J = 1; J<6; J++) {     Sprintf (Sprintf)(Tmp,":%02x",Id[J]);     stid = stid += Tmp ;   }   Terug stid;
}

Functie retourneert een deel van een gegevensbuffer in indeling xx, xx, xx .... als tekenreeks
Tekenreeks Downloadgegevens(uint8_t Buf[], uint8_t Start, uint8_t Einde)
{   Tekenreeks stdata;   Char Tmp[4];   Sprintf (Sprintf)(Tmp,"%02x",Buf[Start]);   stdata=Tmp;   Voor (uint8_t J = Start+1; J<Einde; J++) {     Sprintf (Sprintf)(Tmp,",%02x",Buf[J]);     stdata = stdata += Tmp ;   }   Terug stdata;
}

bereidt de berichtbuffer voor
stelt alle berichten op gedaan
Void initMessageBuffer() {   Voor (Int I. = 0;I.<MAXKANALEN;I.++) {     Berichten[I.].Nieuw = 0;   }
}

Functie om de configuratie op te slaan
Void writeConfiguratie(Const Char *Fn) {   Bestand V = SPIFFS (SPIFFS).Open(Fn, FILE_WRITE);   Als (!V) {     Seriële.println(V("FOUT: SPIFFS kan configuratie niet opslaan"));     Terug;   }   Voor (uint8_t I. = 0; I.<MAXDEVICE; I.++) {     V.Afdrukken(Apparaten[I.].Actieve);V.Afdrukken('n');     Als (Apparaten[I.].Actieve) {       V.Afdrukken(Apparaten[I.].Service);V.Afdrukken('n');       V.Afdrukken(Getid (Getid)(Apparaten[I.].Id));V.Afdrukken('n');       V.Afdrukken(Apparaten[I.].Naam);V.Afdrukken('n');       V.Afdrukken(Apparaten[I.].Laatste);V.Afdrukken('n');     } Anders {       V.Printf("0-n00:00:00:00:00:00:00-n-n-n");     }   }
}

Functie voor het opslaan van de toegangsgegevens
Void writingAccess(Const Char *Fn) {   Bestand V = SPIFFS (SPIFFS).Open(Fn, FILE_WRITE);   Als (!V) {     Seriële.println(V("FOUT: SPIFFS kan referenties niet opslaan"));     Terug;   }   V.Afdrukken("WLANSSID=");V.Afdrukken(wlanssid wlanssid);V.Afdrukken('n');   V.Afdrukken("WLANPWD=");V.Afdrukken(wlanpwd wlanpwd wlanpwd);V.Afdrukken('n');   V.Afdrukken("MQTTUSER=");V.Afdrukken(mqttuser);V.Afdrukken('n');   V.Afdrukken("MQTTPWD=");V.Afdrukken(mqttpwd);V.Afdrukken('n');   V.Afdrukken("MQTTID=");V.Afdrukken(mqttid);V.Afdrukken('n');    }

Functie om de configuratie te lezen
Void leesConfiguratie(Const Char *Fn) {   uint8_t I. = 0;   Tekenreeks Tmp;   Char Hex[3];   Als (!SPIFFS (SPIFFS).Bestaat(Fn)) {     bestaat nog niet en genereert dan     writeConfiguratie(Fn);     Terug;   }   Bestand V = SPIFFS (SPIFFS).Open(Fn, "r");   Als (!V) {     Seriële.println(V("FOUT:: SPIFFS kan configuratie niet openen"));     Terug;   }
#ifdef Debug   Seriële.println("Lees apparaatlijst");
#endif   Terwijl (V.Beschikbaar() && (I.<MAXDEVICE)) {     Seriële.Printf("Lees apparaat %i",I.);     Tmp = V.leesStringUntil('n');     Apparaten[I.].Actieve = (Tmp == "1");     Tmp = V.leesStringUntil('n');     Apparaten[I.].Service = Tmp.toInt();     Tmp = V.leesStringUntil('n');     Voor (uint8_t J=0; J<6; J++){       Hex[0]=Tmp[J*3];       Hex[1]=Tmp[J*3+1];       Hex[2]=0;       Apparaten[I.].Id[J]= (Byte) strtol strtol(Hex,Null Null Null,16);     }     Tmp = V.leesStringUntil('n');     Apparaten[I.].Naam = Tmp;     Tmp = V.leesStringUntil('n');     Apparaten[I.].Laatste = Tmp;
#ifdef Debug   Seriële.Afdrukken("Apparaat"+Getid (Getid)(Apparaten[I.].Id)+ " Naam " + Apparaten[I.].Naam);   Seriële.Printf(" Service %i Active %i'r'n',Apparaten[I.].Service,Apparaten[I.].Actieve);
#endif     I.++;   }    }
Functie voor het lezen van de toegangsgegevens
Void leesAccess(Const Char *Fn) {   uint8_t I. = 0;   Tekenreeks Sleutel;   Tekenreeks Val;   Char Hex[3];   Als (!SPIFFS (SPIFFS).Bestaat(Fn)) {     bestaat nog niet en genereert dan     writingAccess(Fn);     Terug;   }   Bestand V = SPIFFS (SPIFFS).Open(Fn, "r");   Als (!V) {     Seriële.println(V("FOUT:: SPIFFS kan geen referenties openen"));     Terug;   }   Terwijl (V.Beschikbaar() && (I.<MAXDEVICE)) {     Sleutel = V.leesStringUntil('=');     Val = V.leesStringUntil('n');     Als (Sleutel == "WLANSSID") wlanssid wlanssid = Val;     Als (Sleutel == "WLANPWD") wlanpwd wlanpwd wlanpwd = Val;      Als (Sleutel == "MQTTUSER") mqttuser = Val;      Als (Sleutel == "MQTTPWD") mqttpwd = Val;      Als (Sleutel == "MQTTID") mqttid = Val;    }    }


Functie om een nieuw apparaat te registreren
Void geraetRegister() {   uint8_t I. = 0;   zoeken gratis toegang   Terwijl ((I.<MAXDEVICE) && Apparaten[I.].Actieve) I.++;   er is geen nieuwe inzending we doen niets   Als (I. < MAXDEVICE) {     anders registreren geraet naam = ingevoerde naam      of onbekend als er geen is ingevoerd     Als (Server.hasArg hasArg("devname")) {       Apparaten[I.].Naam = Server.Slechte("devname");     } Anders {       Apparaten[I.].Naam = "Onbekend";     }     Voor (uint8_t J = 0; J<6; J++) Apparaten[I.].Id[J]=Onbekende[J];     Apparaten[I.].Actieve = 1;     Apparaten[I.].Service= newGeraetType;     Apparaten[I.].Laatste = "";     writeConfiguratie("/configuration.csv");     newGeraet = Valse;   }
}

De configuratiepagina wordt weergegeven door de webserver
Void handleConfig(){   Char htmlbuf[1024];   Booleaanse Opnieuw starten = Valse;   Int Index;   is de geheugenknop ingedrukt?   Als (Server.hasArg hasArg("opslaan")) {     Gegevens van de POST-aanvraag     wlanssid wlanssid = Server.Slechte("ssid");     als de SSID een ruimte bevat, ontvangen we een "+"     dit moet weer worden veranderd in een ruimte voor de registratie     wlanssid wlanssid.Vervangen("+"," ");     wlanpwd wlanpwd wlanpwd = Server.Slechte("pwd");     mqttuser = Server.Slechte("mquser");     mqttpwd = Server.Slechte("mqpwd");     mqttid = Server.Slechte("mqid");     Seriële.println("Nieuwe configuratie:");     Seriële.Afdrukken("SSID: ");Seriële.println(wlanssid wlanssid);     Seriële.Afdrukken("Wachtwoord: ");Seriële.println(wlanpwd wlanpwd wlanpwd);     Seriële.Afdrukken("Gebruiker: ");Seriële.println(mqttuser);     Seriële.Afdrukken("Wachtwoord: ");Seriële.println(mqttpwd);     Seriële.Afdrukken("ID: ");Seriële.println(mqttid);     De nieuwe configuratie opslaan in SPIFFS     writingAccess("/access.txt");     we onthouden dat de WiFi-verbinding opnieuw moet worden opgestart     maar eerst moet de webserver de HTML-pagina leveren     Opnieuw starten = Waar;   }   Uitvoer van de configuratiepagina   we vormen verwijzingen naar het interne geheugen van de toegangstekenreeksen   om ze te gebruiken voor sprintf en om de Wi-Fi en Cayenne verbinding te starten   Char* txtSSID txtSSID = const_cast<Char*>(wlanssid wlanssid.c_str());   Char* txtPassword txtPassword = const_cast<Char*>(wlanpwd wlanpwd wlanpwd.c_str());      Char* txtUser txtUser = const_cast<Char*>(mqttuser.c_str());   Char* txtPwd txtPwd = const_cast<Char*>(mqttpwd.c_str());   Char* txtId txtId = const_cast<Char*>(mqttid.c_str());   Huidige HTML-pagina naar browser verzenden   Server.setContentLength(CONTENT_LENGTH_UNKNOWN);   Header   Server.Verzenden(200, "tekst/html",HTML_HEADER);   Server.sendContent(HTML_HEADER_END);   Het formulier met de invoervelden is gevuld met de huidige waarden   Sprintf (Sprintf)(htmlbuf,HTML_CONFIG,txtSSID txtSSID,txtPassword txtPassword,txtUser txtUser,txtPwd txtPwd,txtId txtId);   en verzonden naar de Browsewr   Server.sendContent(htmlbuf);   Server.sendContent(HTML_END);   Als (Opnieuw starten) {     Is de startvlag set moet de WiFi-verbinding loskoppelen en opnieuw verbinding maken     worden opgebouwd     mqtt_con = 0;     Seriële.println("Opnieuw opstarten");     uint8_t Timeout = 0;     Seriële.println("Loskoppelen");     Wifi.Verbreken();     Terwijl ((Wifi.Status() == WL_CONNECTED) && (Timeout < 10))     {       Vertraging(1000);       Timeout++;     }     Seriële.println("Opnieuw verbinding maken");     Wifi.Beginnen(txtSSID txtSSID,txtPassword txtPassword);     Terwijl ((Wifi.Status() != WL_CONNECTED) && (Timeout < 10))     {       Vertraging(1000);       Timeout++;     }     Seriële.Afdrukken("IP-adres: ");     Seriële.println(Wifi.localIP());     Als (Wifi.Status() == WL_CONNECTED) {       neustrart was succesvol, moet de verbinding aan Cayenne ook worden herbouwd.       Als ((mqttuser != "")&&(mqttpwd != "") && (mqttid != "")) {         Seriële.println("Aansluiten cayennepeper");         Cayenne.Beginnen(txtUser txtUser, txtPwd txtPwd, txtId txtId);         mqtt_con = 1;       }     Klok synchroniseren met tijdserver     configTime configTime(GMT_OFFSET_SEC, DAYLIGHT_OFFSET_SEC, NTP_SERVER);     Huidige tijd uitvoer     Seriële.println(getLocalTime());     }   }
}

De resetpagina is opgevraagd door de webserver
Void handleReset() {   we resetten de toegangsgegevens    wlanssid wlanssid= "";    wlanpwd wlanpwd wlanpwd = "";    mqttuser = "";    mqttpwd="";    mqttid="";    en de configuratiegegevens weer te geven    alleen wanneer de knop op de configuratiepagina    opslaan wordt geklikt, de toegangsgegevens worden     ook verwijderd in SPIFFS.    handleConfig();
}

De pagina met de apparaatlijst is opgevraagd door de webserver
Void handleWLANRequest(){   Char htmlbuf[512];   Char tmp1 tmp1[20];   Char tmp2[20];   Char tmp3 tmp3[20];   Int Index;   was de knop verwijderen geklikt?   Als (Server.hasArg hasArg("verwijderen")) {     Index = Server.Slechte("verwijderen").toInt();
#ifdef DEGUG DEGUG     Seriële.Printf("Verwijder apparaat %i = ",Index);     Seriële.println(Apparaten[Index].Naam);
#endif     Apparaten[Index].Actieve=0;     writeConfiguratie("/configuration.csv");   }   is er op de knop Registreren geklikt?   Als (Server.hasArg hasArg("registreren")) {     geraetRegister();     Seriële.println("Configuratie wordt opgeslagen");     writeConfiguratie("/configuration.csv");   }   Huidige HTML-pagina naar browser verzenden   Server.setContentLength(CONTENT_LENGTH_UNKNOWN);   Header   Server.Verzenden(200, "tekst/html",HTML_HEADER);   IP-adres voor herladen script   Wifi.localIP().Tostring().Tochararray(tmp1 tmp1,20);   Sprintf (Sprintf)(htmlbuf,HTML_SCRIPT,tmp1 tmp1);   Server.sendContent(htmlbuf);   Server.sendContent(HTML_HEADER_END);   Begin van het formulier   Server.sendContent("<div class="titel">MQTT - Gateway</div><form method="post">");   Tabel met actieve apparaten   Server.sendContent(HTML_TAB_GERAETE);   Voor (uint8_t I. = 0; I.<MAXDEVICE; I.++) {      Als (Apparaten[I.].Actieve == 1) {        Getid (Getid)(Apparaten[I.].Id).Tochararray(tmp1 tmp1,20);       Apparaten[I.].Naam.Tochararray(tmp2,20);       Apparaten[I.].Laatste.Tochararray(tmp3 tmp3,20);       Sprintf (Sprintf)(htmlbuf,HTML_TAB_ZEILE,tmp1 tmp1,I.,I.*8,I.*8+7,tmp2,tmp3 tmp3,I.);       Server.sendContent(htmlbuf);     }   }   Server.sendContent(HTML_TAB_END);   Als er een nieuw apparaat wordt gevonden, wordt de ID en een invoerveld voor de naam van de   en er wordt een knop weergegeven om het nieuwe apparaat te registreren   Als (newGeraet) {     Getid (Getid)(Onbekende).Tochararray(tmp1 tmp1,20);     Sprintf (Sprintf)(htmlbuf,HTML_NEWDEVICE,tmp1 tmp1,tmp1 tmp1);     Server.sendContent(htmlbuf);   }   Server.sendContent(HTML_END_RELOAD);
}

Webserverservicefunctie voor de hoofdmap
Void handleRoot() {   Als (Wifi.Status() != WL_CONNECTED) {     als we geen verbinding hebben met het routernetwerk     de configuratiepagina wordt weergegeven, zodat de toegangsgegevens kunnen worden ingevoerd     handleConfig();   } Anders {     handleWLANRequest();   }
}


Functie om een apparaat in de apparaatlijst te vinden
Retourindex van het apparaat of -1 als deze niet is gevonden
Int findDevice(uint8_t Dev[6]) {   uint8_t J;   uint8_t I. = 0;   Booleaanse Gevonden = Valse;   Do {     J = 0;     Als (Apparaten[I.].Actieve == 0) {       I.++;     } Anders {       Terwijl ((J < 6) && (Dev[J] == Apparaten[I.].Id[J])) {J++;}       Gevonden = (J == 6);       Als (!Gevonden) I.++;      }    } Terwijl ((I.<MAXDEVICE) && (!Gevonden));   Als (Gevonden) {Terug I.;} Anders {Terug -1;}
}

Functie om de status op het OLED-scherm weer te geven
Void Weergeven() {   Weergeven.Duidelijk();   Weergeven.Koord(0,0,"MQTT Gateway"+gwversie);   Weergeven.Koord(0,10,getLocalTime());   Weergeven.Koord(0,20,Wifi.localIP().Tostring());   Weergeven.Koord(0,34,"MQTT: ");   Weergeven.Koord(60,34,Tekenreeks(cayCnt));   Weergeven.Koord(0,44,"LoRa: ");   Weergeven.Koord(60,44,Tekenreeks(loraCnt loraCnt));   Weergeven.Koord(0,54,"NU: ");   Weergeven.Koord(60,54,Tekenreeks(nowCnt));   Weergeven.Weergeven();
}

Ontvangen gegevens opslaan in de berichtbuffer
Retourwaarde het apparaatnummer of -1 als deze niet is geregistreerd
uint8_t processData(uint8_t Buf[], Int buflen) {   Int devnr;   Int Index;   uint8_t Daniel[6];   uint8_t Kanaal;   uint8_t Type;   uint8_t Len;   uint8_t I.;   Booleaanse Output;   Index = 0;   Terwijl ((Index < 6) && (Index < buflen)) {     Daniel[Index] = Buf[Index];     Index++;   }
#ifdef Debug   Seriële.Afdrukken("Apparaten-id = ");Seriële.println(Getid (Getid)(Daniel));
#endif     controleren of het apparaat is geregistreerd   devnr = findDevice(Daniel);   Als (devnr >= 0)  {
#ifdef Debug     Seriële.println(getLocalTime());     Seriële.Afdrukken("Apparatennummer = ");Seriële.println(devnr);
#endif       zo ja, stellen we de tijdstempel in voor het laatste bericht en     lees de gegevens     Apparaten[devnr].Laatste = getLocalTime();     writeconfiguration("/configuration.csv");     lees nu de gegevens     Terwijl (Index < buflen) {       Kanaal = Buf[Index++]+devnr*MAX-KANAAL;       Als (Index == buflen) Breken;       Type = Buf[Index++];       Output = Valse;       Schakelen(Type) {         Geval LPP_DIGITAL_INPUT : Len = LPP_DIGITAL_INPUT_SIZE - 2; Breken;         Geval LPP_DIGITAL_OUTPUT : Len = LPP_DIGITAL_OUTPUT_SIZE - 2; Output = Waar; Breken;         Geval LPP_ANALOG_INPUT : Len = LPP_ANALOG_INPUT_SIZE - 2; Breken;         Geval LPP_ANALOG_OUTPUT : Len = LPP_ANALOG_OUTPUT_SIZE - 2; Output = Waar; Breken;         Geval LPP_LUMINOSITY : Len = LPP_LUMINOSITY_SIZE - 2; Breken;         Geval LPP_PRESENCE : Len = LPP_PRESENCE_SIZE - 2; Breken;         Geval LPP_TEMPERATURE : Len = LPP_TEMPERATURE_SIZE - 2; Breken;         Geval LPP_RELATIVE_HUMIDITY : Len = LPP_RELATIVE_HUMIDITY_SIZE - 2; Breken;         Geval LPP_ACCELEROMETER : Len = LPP_ACCELEROMETER_SIZE - 2; Breken;         Geval LPP_BAROMETRIC_PRESSURE : Len = LPP_BAROMETRIC_PRESSURE_SIZE - 2; Breken;         Geval LPP_GYROMETER : Len = LPP_GYROMETER_SIZE - 2; Breken;         Geval LPP_GPS : Len = LPP_GPS_SIZE - 2; Breken;         Standaard: Len =  0;       }       als het kanaal geen actuator is, stellen we de berichtbuffer opnieuw in 1       zodat de gegevens bij de volgende gelegenheid naar de MQTT-server worden verzonden       Als (!Output) Berichten[Kanaal].Nieuw =1;       Berichten[Kanaal].Type = Type;       I. = 0;       Terwijl ((I.<Len) && (Index < buflen)) {         Als (!Output) Berichten[Kanaal].Gegevens[I.] = Buf[Index];         I.++; Index++;       }
#ifdef Debug       Seriële.Printf("Kanaal %i Type %i Gegevens: ",Kanaal,Type);Seriële.println(Downloadgegevens(Berichten[Kanaal].Gegevens,0,Len));
#endif       }     Terug devnr;   } Anders {     Voor (uint8_t I. = 0; I.<6; I.++) Onbekende[I.] = Daniel[I.];     newGeraet = Waar;     Terug -1;   }    }

uint8_t antwoordBilden(uint8_t Buf[], uint8_t devnr) {   we controleren of we outputgegevens hebben voor het huidige LoRa-apparaat   Int Index = 6; eerste zes bytes zonde van de apparaten Id   Int devbase = devnr*MAX-KANAAL;
#ifdef Debug   Seriële.Printf("Activators voor device %i Channel %i tot %i-r-n",devnr,devbase,devbase+8);
#endif   Voor (Int I. = devbase; I.<devbase+8; I.++) {     afhankelijk van het type digitale of analoge gegevens     Schakelen (Berichten[I.].Type) {         Geval LPP_DIGITAL_OUTPUT : Buf[Index++]= I.-devbase;           Buf[Index++]=Berichten[I.].Type;           Buf[Index++]=Berichten[I.].Gegevens[0];
#ifdef Debug           Seriële.println("Digitale output");
#endif           Breken;         Geval LPP_ANALOG_OUTPUT :   Buf[Index++]= I.-devbase;           Buf[Index++]=Berichten[I.].Type;           Buf[Index++]=Berichten[I.].Gegevens[0];           Buf[Index++]=Berichten[I.].Gegevens[1];
#ifdef Debug           Seriële.println("Analoge uitgang");
#endif           Breken;     }   }   Terug Index;
}

Een bericht verwerken van een LoRa-client
Void readLoRa() {   uint8_t Buf[256];   Int Ix;   Int devnr;   uint8_t Len;   uint8_t Být;   Gegevens opvragen indien beschikbaar   Int packetSize = Lora.parsePacket();   hebben we gegevens ontvangen?   Als (packetSize > 0) {
#ifdef Debug     Seriële.Printf("%i Bytes ontvangen van LoRa",packetSize);
#endif     Terwijl ((Ix < packetSize) && (Ix < 256)) {       Být= Lora.Lezen();
Serial.printf(%2x ",byt);       Buf[Ix++] = Být;     }
Serial.println();
#ifdef Debug     Seriële.println(Downloadgegevens(Buf,0,packetSize));
#endif     devnr = processData(Buf, packetSize);     Als (devnr >=0) {       Status bijwerken       loraCnt loraCnt++;       loraLast = getLocalTime();     } Anders {       newGeraetType = 0; LoRa-apparaat     }     Deel twee Reactie verzenden naar LoRa-apparaat     vertraging(500);     in de eerste zes bytes van de buffer, de deviceId     Len = 6;     als we een geregistreerd apparaat hebben, sturen we ook gegevens met     Als (devnr >= 0) Len = antwoordBilden(Buf, devnr);
#ifdef Debug     Seriële.Printf("Verzenden naar apparaat %i %i bytes"r-n",devnr,Len);     Seriële.println(Downloadgegevens(Buf,0,Len));
#endif     Lora.beginPacket();     Lora.Schrijven(Buf,Len);     Int lstatus = Lora.endPacket();
#ifdef Debug     Seriële.Afdrukken("Status verzenden = ");     Seriële.println(lstatus);
#endif   }
}

callback voor ESP Now
Void readESPNow(Const uint8_t *mac_addr, Const uint8_t *r_data, Int data_len) {   uint8_t Gegevens[70];   uint8_t devnr;   uint8_t Len;    #ifdef Debug   Seriële.Printf("%ik ontvang bytes van ESP-Nu",data_len);
#endif   Memcpy Memcpy(&Gegevens, r_data, Grootte van(Gegevens));   devnr = processData(Gegevens,data_len);   Als (devnr >=0) {     Status bijwerken     nowCnt++;     nowLast = getLocalTime();   } Anders {     newGeraetType = 1; ESP Now-apparaat   }   Vertraging(100);   Deel twee Reactie verzenden naar ESP-Now-apparaat   in de eerste zes bytes van de buffer, de deviceId   Len = 6;   als we een geregistreerd apparaat hebben, sturen we ook gegevens met   Als (devnr >= 0) Len = antwoordBilden(Gegevens, devnr);
#ifdef Debug   Seriële.Printf("Verzenden naar apparaat %i %i bytes"r-n",devnr,Len);   Seriële.println(Downloadgegevens(Gegevens,0,Len));
#endif   esp_now_send(Gegevens, Gegevens, Len); 
#ifdef Debug   Seriële.println("Einde");
#endif   }


Void Setup() {   Apparaatopslag initialiseren   Voor (uint8_t I. =0; I.<MAXDEVICE; I.++) Apparaten[I.].Actieve = 0;   OLED-scherm initialiseren   pinMode(DISPLRESET,Output);   digitalWrite(DISPLRESET, Lage);   Vertraging(50);    digitalWrite(DISPLRESET, Hoge);   Weergeven.Init();   Weergeven.flipScreenVerticaal();   Weergeven.setFont(ArialMT_Plain_10);   Weergeven.setTextAlignment(TEXT_ALIGN_LEFT);   Seriële interface starten   Seriële.Beginnen(115200);   Terwijl (!Seriële);    Seriële.println("Begin");   Flash-bestandssysteem   Als (SPIFFS (SPIFFS).Beginnen(FORMAT_SPIFFS_IF_FAILED)) Seriële.println(V("SPIFFS geladen"));   Lees in configuratie- en toegangsgegevens   leesConfiguratie("/configuration.csv");   leesAccess("/access.txt");   initMessageBuffer();   Spi en LoRa initialiseren   Spi.Beginnen(5,19,27,18);   Lora.setPins(Ss,Rst,DI0);   Seriële.println("LoRa TRX");   Als (!Lora.Beginnen(Band)) {     Seriële.println("BeginnenLoRa mislukt!");     Terwijl (1);   }   Lora.enableCrc();   Seriële.println("LoRa Aanvankelijk OK!");   Vertraging(2000);   Uitvoer van leestoegangsgegevens voor besturingselement   Seriële.Afdrukken("SSID: ");Seriële.println(wlanssid wlanssid);   Seriële.Afdrukken("Wachtwoord: ");Seriële.println(wlanpwd wlanpwd wlanpwd);   Seriële.Afdrukken("Gebruiker: ");Seriële.println(mqttuser);   Seriële.Afdrukken("Wachtwoord: ");Seriële.println(mqttpwd);   Seriële.Afdrukken("ID: ");Seriële.println(mqttid);   Verbinding maken met de Wi-Fi- en MQTT-server   Seriële.println("Sluit Wi-Fi aan");   we gebruiken de ESP32 als access poin, maar ook als client in het routernetwerk   Wifi.Mode(WIFI_AP_STA);   we hebben verwijzingen naar het tekengeheugen binnen de tekenreeksen nodig   Char* txtSSID txtSSID = const_cast<Char*>(wlanssid wlanssid.c_str());   Char* txtPassword txtPassword = const_cast<Char*>(wlanpwd wlanpwd wlanpwd.c_str());      Char* txtUser txtUser = const_cast<Char*>(mqttuser.c_str());   Char* txtPwd txtPwd = const_cast<Char*>(mqttpwd.c_str());   Char* txtId txtId = const_cast<Char*>(mqttid.c_str());   Ongeacht de verbinding met het routernetwerk starten we de AccessPoint   dit maakt configuratie via een browser mogelijk, als we deze    Aanmelden bij AccessPoint   Wifi.softAP("MQTTGateway",APPWD,APCHANNEL,0);   Verbinding maken met het routernetwerk   Wifi.Beginnen(txtSSID txtSSID, txtPassword txtPassword);   uint8_t Timeout = 0;   Terwijl ((Wifi.Status() != WL_CONNECTED) && (Timeout<10)) {     Timeout++;     Vertraging(1000);   }   we wachten maximaal 10 seconden tot de verbinding op zijn plaats is   Als (Wifi.Status() == WL_CONNECTED) {     Als de verbinding met het routernetwerk succesvol is, starten we MQTT naar Cayenne     en de interne klok synchroniseren met de tijdserver     Seriële.Afdrukken("IP-adres: ");     Seriële.println(Wifi.localIP());     Als ((mqttid != "") && (mqttuser != "") && (mqttpwd != "")) {       Seriële.println("Staat MQTT");       Cayenne.Beginnen(txtUser txtUser, txtPwd txtPwd, txtId txtId);       Seriële.println("Cayenne Verbinding gemaakt");       mqtt_con = 1;     }     Klok synchroniseren met tijdserver     configTime configTime(GMT_OFFSET_SEC, DAYLIGHT_OFFSET_SEC, NTP_SERVER);     Huidige tijd uitvoer     Seriële.println(getLocalTime());   }   Webserver initialiseren   Server.Op("/", handleRoot);   Server.Op("/conf",handleConfig);   Server.Op("/reset",handleReset);   Server.Beginnen();   Als (esp_now_init() == ESP_OK) Seriële.println("ESP-Nu geïnitialiseerd!");   esp_now_register_recv_cb(readESPNow);   Seriële.println("*********************************************");


}


Void Lus() {   Weergeven();   Als (Wifi.Status() == WL_CONNECTED) {     LoRa-interface controleren op gegevens     readLoRa();     communiceren met Cayenne MQTT Server     Als (mqtt_con == 1) Cayenne.Lus(1);   }   Webserver serveren   Server.handleClient();   Vertraging(100);

}

Gegevens van de berichtbuffer verzenden naar de MQTT-server
CAYENNE_OUT_DEFAULT()
{   Booleaanse Output = Valse;   Booleaanse verzondenGegevens = Valse;   Float Val;
#ifdef Debug   Seriële.println(getLocalTime());   Seriële.println("Cayenne sturen");
#endif   Voor (Int I. = 0; I.<MAXKANALEN; I.++) {     alleen nieuwe berichten verzenden     Als (Berichten[I.].Nieuw == 1) {
#ifdef Debug       Seriële.Printf("Stuur MQTT Channel %i Type %i'n",I.,Berichten[I.].Type);
#endif       gegevens verzenden, afhankelijk van het type       Schakelen (Berichten[I.].Type) {           Geval LPP_DIGITAL_INPUT : Cayenne.digitalSensorWrite(I.,Berichten[I.].Gegevens[0]); Breken;           Geval LPP_DIGITAL_OUTPUT : Output = Waar; Breken;           Geval LPP_ANALOG_INPUT : Val = (Berichten[I.].Gegevens[0]*256 + Berichten[I.].Gegevens[1]);Cayenne.virtualWrite(I.,Val/100,"analog_sensor",UNIT_UNDEFINED); Breken; Breken;           Geval LPP_ANALOG_OUTPUT : Output = Waar; Breken;           Geval LPP_LUMINOSITY : Cayenne.luxSchrijven(I.,Berichten[I.].Gegevens[0]*256 + Berichten[I.].Gegevens[1]); Breken;           Geval LPP_PRESENCE : Cayenne.digitalSensorWrite(I.,Berichten[I.].Gegevens[0]); Breken;           Geval LPP_TEMPERATURE : Val = (Berichten[I.].Gegevens[0]*256 + Berichten[I.].Gegevens[1]); Cayenne.celsiusSchrijf(I.,Val/10); Breken;           Geval LPP_RELATIVE_HUMIDITY : Val=Berichten[I.].Gegevens[0];Cayenne.virtualWrite(I.,Val/2,TYPE_RELATIVE_HUMIDITY,UNIT_PERCENT); Breken;           Geval LPP_ACCELEROMETER : Val = (Berichten[I.].Gegevens[0]*256 + Berichten[I.].Gegevens[1]);Cayenne.virtualWrite(I.,Val/1000,"gx","g"); Breken;           Geval LPP_BAROMETRIC_PRESSURE : Val = (Berichten[I.].Gegevens[0]*256 + Berichten[I.].Gegevens[1]);Cayenne.hectoPascalWrite hectoPascalWrite(I.,Val/10); Breken;           geval LPP_GYROMETER : len = LPP_GYROMETER_SIZE - 2; breken;           geval LPP_GPS : len = LPP_GPS_SIZE - 2; breken;       }       Als (!Output) {         Berichten[I.].Nieuw = 0;         verzondenGegevens = Waar;       }            }   }   Als (verzondenGegevens) {     Status bijwerken     cayCnt++;     cayLast = getLocalTime();   }

}

CAYENNE_IN_DEFAULT()
{   uint8_t * Pdata;   Int Val;   Int Ch = Verzoek.Kanaal;
#ifdef Debug   Seriële.println("Cayenne recive");   Seriële.Printf("MQTT-gegevens voor kanaal %i = %s"n",Ch,Getvalue.asString());
#endif   Schakelen (Berichten[Ch].Type) {       Geval LPP_DIGITAL_OUTPUT : Berichten[Ch].Gegevens[0] = Getvalue.asInt();         Berichten[Ch].Nieuw = 1;         Breken;       Geval LPP_ANALOG_OUTPUT :  Val = Ronde(Getvalue.asDubbel()*100);         Berichten[Ch].Gegevens[0] = Val / 256;         Berichten[Ch].Gegevens[1] = Val % 256;         Berichten[Ch].Nieuw = 1;         Breken;   }   CAYENNE_LOG("Kanaal %u, waarde %s", Verzoek.Kanaal, Getvalue.asString());   Proces bericht hier. Als er een fout is ingesteld, stelt u een foutbericht in met getValue.setError(), bijvoorbeeld getValue.setError('Foutbericht');    }

Het display toont nu ook een versienummer. Meer informatie over deze gateway is te vinden in de andere delen van deze serie.

 

Grundlagen software

2 Kommentare

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?

Einen Kommentar hinterlassen

Alle Kommentare werden vor der Veröffentlichung moderiert

Aanbevolen blog berichten

  1. Installeer ESP32 nu van de raad van bestuur
  2. Lüftersteuerung Raspberry Pi
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1
  4. ESP32 - das Multitalent
  5. OTA - Over the Air - ESP Programmeren via Wi-Fi