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> </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.
2 Reacties
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?