Werken met de Cayenne Dashboard van de Gateway als een Access Point en een netwerk Client(deel 5)

Inch Deel 3 we hebben een gateway gebouwd die werkt als een client op een Wi-Fi-netwerk. Het was daarom noodzakelijk om de bijbehorende toegangsgegevens in constanten op te slaan in het geheugen van het programma. Aangezien we de gateway ook bruikbaar willen maken voor ESP-Now, zou het handig zijn als de gateway ook als toegangspunt zou kunnen werken.

Nu kan de ESP32 dat doen. Wanneer we zitten de WiFi-modus op WIFI_AP_STA de ESP werkt als zowel een access point en een station. Er kan echter slechts één kanaal worden gebruikt. De verbinding met het routernetwerk is een prioriteit voor kanaalselectie. Dit betekent dat het toegangspunt altijd hetzelfde kanaal gebruikt als de verbinding met het routernetwerk.

We willen nu deze dubbele modus gebruiken om onze gateway via een browser te configureren. De nodige toegangsgegevens zoals SSID en wachtwoord, evenals de toegangsgegevens tot Cayenne gewoon op lege snaren. Als de gateway is gestart, kan deze geen verbinding maken met het routernetwerk omdat de referenties ontbreken. Nadat de verbindingspoging is getimed, wordt het toegangspunt gestart met de SSID MQTTGateway. Het IP-adres van de gateway is altijd 192.168.4.1 in dit netwerk

Om de gateway te configureren, loggen we een computer of smartphone in op dit netwerk (geen wachtwoord) en starten we een browser met het adres http://192.168.4.1 We moeten dan de volgende configuratiepagina zien.

Wanneer de referenties worden opgeslagen, probeert de gateway verbinding te maken met het routernetwerk. Als de verbindingspoging is geslaagd, geeft het display het IP-adres weer waarmee de gateway in het routernetwerk kan worden bereikt. 

Na een verbinding met het routernetwerk krijgt u altijd de lijst met geregistreerde apparaten in de browser. U hebt toegang tot de configuratiepagina en wijzigt de toegangsgegevens via het /conf-pad. 

Schets:

 

/* 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"


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

//
#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

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

#define Debug 1

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="10" 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;   uint8_t Service; 0=LoRa, 1=ESP-Nu   uint8_t Id[6];   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];

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 het laatst verzonden MQTT-bericht


// Functie retourneert datum en tijd in de notatie jjjj-mm-dd hh: mm: ss als een tekenreeks
String getLocalTime()
{   char sttime[20] = "";   struct tm tijdinfo;   als (WiFi.status() == WL_CONNECTED) {     als(!getLocalTime(&tijdinfo)){       Serie.println("Kan tijd niet verkrijgen");       terug sttime;     }     strftime(sttime, grootte van(sttime), "%Y-%m-%d %H:%M:%S", &tijdinfo);   }   terug sttime;
}

// Functie retourneert een 6-byte apparaat-ID in de notatie xx: xx: xx: xx: xx: xx als een tekenreeks
String krijgen(uint8_t id[6])
{   String stid;   char tmp[4];   sprintf(tmp,"% 02x",id[0]);   stid=tmp;   voor (uint8_t j = 1; j<6; j++) {     sprintf(tmp,":% 02x",id[j]);     stid = stid += tmp ;   }   terug stid;
}

// bereidt de berichtenbuffer voor
// stelt alle berichten in op Klaar
nietig initMessageBuffer() {   voor (int ik = 0;ik<MAXKANALEN;ik++) berichten[ik].nieuw = 0;
}

// Functie om de configuratie op te slaan
nietig schrijf configuratie(const char *fn) {   Bestand f = SPIFFS.open(fn, FILE_WRITE);   als (!f) {     Serie.println(F("FOUT: SPIFFS kan configuratie niet opslaan"));     terug;   }   voor (uint8_t ik = 0; ik<MAXDEVICE; ik++) {     f.afdrukken(apparaten[ik].actief);f.afdrukken(",");     f.afdrukken(apparaten[ik].dienst);f.afdrukken(",");     f.afdrukken(krijgen(apparaten[ik].id));f.afdrukken(",");     f.afdrukken(apparaten[ik].naam);f.afdrukken(",");     f.println(apparaten[ik].laatste);   }
}

// Functie voor het opslaan van de toegangsgegevens
nietig schrijf toegang(const char *fn) {   Bestand f = SPIFFS.open(fn, FILE_WRITE);   als (!f) {     Serie.println(F("FOUT: SPIFFS kan aanmeldingsgegevens niet opslaan"));     terug;   }   f.afdrukken("WLANSSID =");f.afdrukken(wlanssid);f.afdrukken('\ n');   f.afdrukken("WLANPWD =");f.afdrukken(wlanpwd);f.afdrukken('\ n');   f.afdrukken("MQTTUSER =");f.afdrukken(mqttuser);f.afdrukken('\ n');   f.afdrukken("MQTTPWD =");f.afdrukken(mqttpwd);f.afdrukken('\ n');   f.afdrukken("MQTTID =");f.afdrukken(mqttid);f.afdrukken('\ n');    }

// Functie voor het registreren van een nieuw apparaat
nietig apparaat Registreren() {   uint8_t ik = 0;   // zoek gratis toegang   terwijl ((ik<MAXDEVICE) && apparaten[ik].actief) ik++;   // als er geen nieuwe invoer is, doen we niets   als (ik < MAXDEVICE) {     // registreer anders apparaatnaam = ingevoerde naam      // of onbekend als er geen is ingevoerd     als (server.hasArg("devname")) {       apparaten[ik].naam = server.slecht("devname");     } anders {       apparaten[ik].naam = "onbekend";     }     voor (uint8_t j = 0; j<6; j++) apparaten[ik].id[j]=onbekend[j];     apparaten[ik].actief = 1;     apparaten[ik].dienst= type nieuw apparaat;     apparaten[ik].laatste = "";     schrijf configuratie("/konfiguration.csv");     nieuw apparaat = fout;   }
}

// De configuratiepagina wordt weergegeven door de webserver
nietig handleConfig(){   char htmlbuf[1024];   Boolean herstart = fout;   int index;   // werd de geheugenknop ingedrukt?   als (server.hasArg("opslaan")) {     // Gegevens van het POST-verzoek     wlanssid = server.slecht("ssid");     // als de SSID een spatie bevat, krijgen we een "+"     // dit moet weer worden omgezet in een spatie voor de registratie     wlanssid.vervangen("+"," ");     wlanpwd = server.slecht("pwd");     mqttuser = server.slecht("mquser");     mqttpwd = server.slecht("mqpwd");     mqttid = server.slecht("mqid");     Serie.println("Nieuwe configuratie:");     Serie.afdrukken("SSID:");Serie.println(wlanssid);     Serie.afdrukken("Wachtwoord:");Serie.println(wlanpwd);     Serie.afdrukken("Gebruiker:");Serie.println(mqttuser);     Serie.afdrukken("Wachtwoord:");Serie.println(mqttpwd);     Serie.afdrukken("ID:");Serie.println(mqttid);     // Sla de nieuwe configuratie op in SPIFFS     schrijf toegang("/zugang.txt");     // we onthouden dat de wifi-verbinding opnieuw moet worden gestart     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     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.       Seriële.println("Aansluiten cayennepeper");       Cayenne.Beginnen(txtUser txtUser, txtPwd txtPwd, txtId txtId);     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();   }   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 een nieuw apparaat is gevonden, de ID en een invoerveld voor de naam   // en een knop voor het registreren van het nieuwe apparaat wordt weergegeven   als (nieuw apparaat) {     krijgen(onbekend).toCharArray(tmp1,20);     sprintf(htmlbuf,HTML_NEWDEVICE,tmp1,tmp1);     server.sendContent(htmlbuf);   }   server.sendContent(HTML_END_RELOAD);
}

// Servicefuncties van de webserver voor de hoofdmap
nietig 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 naar een apparaat in de apparatenlijst te zoeken
// Retourindex van het apparaat of -1 als het niet werd gevonden
int findDevice(uint8_t dev[6]) {   uint8_t j;   uint8_t ik = 0;   Boolean gevonden = fout;   doen {     j = 0;     als (apparaten[ik].actief == 0) {       ik++;     } anders {       terwijl ((j < 6) && (dev[j] == apparaten[ik].id[j])) {j++;}       gevonden = (j == 6);       als (!gevonden) ik++;      }    } terwijl ((ik<MAXDEVICE) && (!gevonden));   als (gevonden) {terug ik;} anders {terug -1;}
}

// Functie voor het weergeven van de status op het OLED-display
nietig weer te geven() {   weer te geven.duidelijk();   weer te geven.drawString(0,0,"MQTT Gateway");   weer te geven.drawString(0,10,getLocalTime());   weer te geven.drawString(0,20,WiFi.localIP().toString());   weer te geven.drawString(0,34,"MQTT:");   weer te geven.drawString(60,34,String(cayCnt));   weer te geven.drawString(0,44,"LoRa:");   weer te geven.drawString(60,44,String(loraCnt));   weer te geven.drawString(0,54,"NU:");   weer te geven.drawString(60,54,String(nowCnt));   weer te geven.weer te geven();
}


// Verwerk een bericht van een LoRa-client
nietig readLoRa() {   int devnr;   uint8_t devid[6];   uint8_t kanaal;   uint8_t typ;   uint8_t len;   uint8_t dat;   Boolean uitgang;   // haal gegevens op indien beschikbaar   int pakketgrootte = LoRa.parsePacket();   // hebben we gegevens ontvangen?   als (pakketgrootte > 5) {
#ifdef DEBUG         Serie.println(getLocalTime());     Serie.afdrukken("RX");     Serie.afdrukken(pakketgrootte);     Serie.println("Bytes");     Serie.afdrukken("Device ID");
#endif      // lees eerst het apparaat-ID     voor (uint8_t ik=0; ik<6;ik++){       devid[ik]=LoRa.lezen();
#ifdef DEBUG       Serie.printf("-% 02x",devid[ik]);
#endif     }
#ifdef DEBUG     Serie.println();
#endif     // bereken het resterende pakket     pakketgrootte -= 6;     // controleer of het apparaat is geregistreerd     devnr = findDevice(devid);     als (devnr >= 0)  {       // zo ja, dan stellen we de tijdstempel in voor het laatste bericht en       // lees de gegevens       apparaten[devnr].laatste = getLocalTime();       schrijf configuratie("/konfiguration.csv");       terwijl (pakketgrootte > 0) {         // Kanaalnummer = apparaatnummer * 16 + apparaatkanaal         kanaal = LoRa.lezen() + devnr*16;
#ifdef DEBUG         Serie.printf("Kanaal:% 02x",kanaal);
#endif         // type kanaal         typ = LoRa.lezen();
#ifdef DEBUG         Serie.printf("Type:% 02x",typ);
#endif         // bepaal de lengte van het datapakket en of het kanaal een actuator is         uitgang = fout;         schakelaar(typ) {           geval LPP_DIGITAL_INPUT : len = LPP_DIGITAL_INPUT_SIZE - 2; pauze;           geval LPP_DIGITAL_OUTPUT : len = LPP_DIGITAL_OUTPUT_SIZE - 2; uitgang = waar; pauze;           geval LPP_ANALOG_INPUT : len = LPP_ANALOG_INPUT_SIZE - 2; pauze;           geval LPP_ANALOG_OUTPUT : len = LPP_ANALOG_OUTPUT_SIZE - 2; uitgang = waar; pauze;           geval LPP_LUMINOSITY : len = LPP_LUMINOSITY_SIZE - 2; pauze;           geval LPP_PRESENCE : len = LPP_PRESENCE_SIZE - 2; pauze;           geval LPP_TEMPERATURE : len = LPP_TEMPERATURE_SIZE - 2; pauze;           geval LPP_RELATIVE_HUMIDITY : len = LPP_RELATIVE_HUMIDITY_SIZE - 2; pauze;           geval LPP_ACCELEROMETER : len = LPP_ACCELEROMETER_SIZE - 2; pauze;           geval LPP_BAROMETRIC_PRESSURE : len = LPP_BAROMETRIC_PRESSURE_SIZE - 2; pauze;           geval LPP_GYROMETER : len = LPP_GYROMETER_SIZE - 2; pauze;           geval LPP_GPS : len = LPP_GPS_SIZE - 2; pauze;           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;         Resterende pakket = 2 minder omdat kanaal en type werden gelezen         packetSize -= 2;
#ifdef Debug         Seriële.Afdrukken("Gegevens:");
#endif         nu lezen we de ontvangen gegevens met de bepaalde lengte         Voor (uint8_t I.=0; I.<Len; I.++) {           Dat = Lora.Lezen();           voor actuatoren herinneren we ons geen gegevens           Als (! Output) Berichten[Kanaal].Gegevens[I.] = Dat;
#ifdef Debug           Seriële.Printf("-%02x",Dat);
#endif           Het resterende pakket met één verminderen           packetSize --;         }
#ifdef Debug         Seriële.println();
#endif       }       Status bijwerken       loraCnt loraCnt++;       loraLast = getLocalTime();       Weergeven();     } Anders {       Het apparaat is niet geregistreerd        we herinneren ons de apparaat-id om het weer te geven voor registratie       Voor (uint8_t I. = 0; I.<6; I.++) Onbekende[I.] = Daniel[I.];       newGeraet = Waar;       newGeraetType = 0; LoRa-apparaat     }     Deel twee Reactie verzenden naar LoRa-apparaat     Vertraging(100);     Lora.beginPacket();     aan het begin is de apparaat-id     Lora.Schrijven(Daniel,6);     we controleren of we outputgegevens hebben voor het huidige LoRa-apparaat     Int devbase = devnr*16;     Voor (Int I. = devbase; I.<devbase+8; I.++) {       afhankelijk van het type digitale of analoge gegevens       Schakelen (Berichten[I.].Type) {           Geval LPP_DIGITAL_OUTPUT : Lora.Schrijven(I.-devbase);             Lora.Schrijven(Berichten[I.].Type);             Lora.Schrijven(Berichten[I.].Gegevens,1);
#ifdef Debug             Seriële.println("Digitale output");
#endif             Breken;           Geval LPP_ANALOG_OUTPUT :  Lora.Schrijven(I.-devbase);             Lora.Schrijven(Berichten[I.].Type);             Lora.Schrijven(Berichten[I.].Gegevens,2);
#ifdef Debug             Seriële.println("Analoge uitgang");
#endif             Breken;       }     }          Int lstatus = Lora.endPacket();
#ifdef Debug     Seriële.Afdrukken("Status verzenden = ");     Seriële.println(lstatus);
#endif   }
}

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;   }   Terwijl (V.Beschikbaar() && (I.<MAXDEVICE)) {     Tmp = V.leesStringUntil(',');     Apparaten[I.].Actieve = (Tmp == "1");     Tmp = V.leesStringUntil(',');     Apparaten[I.].Service = Tmp.toInt();     Tmp = V.leesStringUntil(',');     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(',');     Apparaten[I.].Naam = Tmp;     Tmp = V.leesStringUntil(',');     Apparaten[I.].Laatste = Tmp;     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;    }    }

Void Setup() {   Apparaatopslag initialiseren   Voor (uint8_t I. =0; I.<MAXDEVICE; I.++) Apparaten[I.].Actieve = 0;   OLED-scherm initialiseren   pinMode(16,Output);   digitalWrite(16, Lage);   Vertraging(50);    digitalWrite(16, 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());   Wifi.Beginnen(txtSSID txtSSID, txtPassword txtPassword);   Verbinding maken met het routernetwerk   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   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");   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());     Cayenne.Beginnen(txtUser txtUser, txtPwd txtPwd, txtId txtId);     Seriële.println("Cayenne Verbinding gemaakt");     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();   Seriële.println("*********************************************");


}


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

}

Gegevens van de berichtbuffer verzenden naar de MQTT-server
CAYENNE_OUT_DEFAULT()
{   Booleaanse Output = Valse;   Booleaanse verzondenGegevens = Valse;
#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 Type %i'n",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;           case LPP_ANALOG_INPUT : Cayenne.virtualWrite(i,(berichten[i].daten[0]*256 + berichten[i].data[1])/100,"analog_sensor",UNIT_UNDEFINED); breken; breken;           Geval LPP_ANALOG_OUTPUT : Output = Waar; Breken;           Geval LPP_LUMINOSITY : Cayenne.luxSchrijven(I,Berichten[I].daten[0]*256 + Berichten[I].daten[1]); Breken;           Geval LPP_PRESENCE : Cayenne.digitalSensorWrite(I,Berichten[I].daten[0]); Breken;           Geval LPP_TEMPERATURE : Cayenne.celsiusSchrijf(I,(Berichten[I].daten[0]*256 + Berichten[I].daten[1])/10); Breken;           Geval LPP_RELATIVE_HUMIDITY : Cayenne.virtualWrite(I,Berichten[I].daten[0]/2,TYPE_RELATIVE_HUMIDITY,UNIT_PERCENT); Breken;           Geval LPP_ACCELEROMETER : Cayenne.virtualWrite(I,(Berichten[I].daten[0]*256 + Berichten[I].daten[1])/1000,"gx","g"); Breken;           Geval LPP_BAROMETRIC_PRESSURE : Cayenne.hectoPascalWrite hectoPascalWrite(I,(Berichten[I].daten[0]*256 + Berichten[I].daten[1])/10); Breken;           geval LPP_GYROMETER : len = LPP_GYROMETER_SIZE - 2; breken;           geval LPP_GPS : len = LPP_GPS_SIZE - 2; breken;       }       Als (!Output) {         Berichten[I].Neu = 0;         verzondenGegevens = Waar;       }            }   }   Als (verzondenGegevens) {     Status aktualisieren     cayCnt++;     cayLast = getLocalTime();     Anzeige();   }

}

CAYENNE_IN_DEFAULT()
{   uint8_t * pData;   Int Val;   Int Ch = Verzoek.Kanaal;
#ifdef Debug   Seriële.println("Cayenne recive");   Seriële.Printf("MQTT Daten für Kanal %i = %s\n",Ch,getValue.asString());
#endif   Schakelen (Berichten[Ch].typ) {       Geval LPP_DIGITAL_OUTPUT : Berichten[Ch].daten[0] = getValue.asInt();         Berichten[Ch].Neu = 1;         Breken;       Geval LPP_ANALOG_OUTPUT :  Val = Ronde(getValue.asDubbel()*100);         Berichten[Ch].daten[0] = Val / 256;         Berichten[Ch].daten[1] = Val % 256;         Berichten[Ch].Neu = 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');    }

 

Viel Spaß beim Testen.

Esp-32Projekte für fortgeschrittene

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