In Parte 3 se abbiamo costruito una porta che lavora come un cliente su una rete WLAN. Dunque, doveva esser posato inevitabilmente i dati di accesso adatti in costanti nella memoria di programma. Perché vogliamo utilizzare la porta anche per ESP Adesso, sarebbe pratico se la porta anche come un punto di Accesso poteva lavorare.
Adesso dell'ESP32 questo è capace. Se noi WiFi moda su WIFI_AP_STA stzen lavori dell'ESP come un punto di Accesso così come come una stazione. Infatti, solo un canale può esser usato. La connessione sulla rete d'instradatore ha la priorità con la scelta di canale. Questo è il punto di Accesso sempre usa lo stesso canale come la connessione sulla rete d'instradatore.
Adesso vogliamo usare questa moda doppia per esso per configurare la nostra porta su un navigatore. I dati di accesso necessari come SSID e parola d'ordine, comunque, anche i dati di accesso a Caienna semplicemente su spago vuoto. Se la porta è assente cominciato quindi non può aumentare connessione sulla rete d'instradatore, là i dati di accesso. Dopo che il tentativo connettente è entrato in Time out, il punto di Accesso con lo SSID MQTTGateway è cominciato. L'indirizzo IP della porta è in questa rete sempre 192.168.4.1
Per configurare adesso la porta annunciamo un computer o uno smartphone in questa rete (nessuna parola d'ordine) e cominciamo un navigatore con l'indirizzo http://192.168.4.1 Noi allora deve vedere la parte di configurazione seguente.
Se i dati di accesso sono immagazzinati, la porta prova a produrre una connessione con la rete d'instradatore. Se il tentativo connettente è di successo, l'esposizione mostra all'indirizzo IP in con che la porta nella rete d'instradatore può esser raggiunta.
Dopo che una connessione con la rete d'instradatore esiste uno riceve nel navigatore sempre la lista dei dispositivi iscritti. Sul path/conf uno può accedere alla parte di configurazione e cambiare i dati di accesso.
Sketch:
/* La porta MQTT forma un'interfaccia tra LoRa a dispositivi o dispositivi SPECIALMENTE Nowe * e Caienna Cruscotti di MQTT. Dirige su ESP32 con LoRa ed esposizione OLED * La configurazione succede dal navigatore */ #include <SPI.H> #include <LoRa.H> #include «SSD1306.h» #include<Arduino.H> #include <CayenneMQTTESP32.H> #include <CayenneLPP.H> #include <WiFi.H> #include <Server Web.H> #include <tempo.H> #include «FS.h» #include «SPIFFS.h» //Server NTP alla sincronizzazione di tempo #define NTP_SERVER «de.pool.ntp.org» #define GMT_OFFSET_SEC 3600 #define DAYLIGHT_OFFSET_SEC 0 //Spilli per il chip di LoRa #define SS 18 #define RST 14 #define DI0 26 //Frequenza per il chip di LoRa #define NASTRO 433175000 // #define MAXCHANNELS 256 //numero massimo dei canali amministrati #define MAXDEVICE 32 //il numero massimo dei dispositivi amministrati MAXCHANNELS/MAXDEVICE = 8 dimostra il numero massimo di canali per dispositivo //Il sistema di File di Lampo di formato se non avvengono già #define FORMAT_SPIFFS_IF_FAILED vero #define MESSA A PUNTO 1 //Pietre per il server Web può PROGMEM lavoro a giornata HTML_HEADER[] = «<!DOCTYPE HTML>»; «<html>»; «<head>»; «<meta chiamano = \«viewport \» i contenuti = \«la larghezza = la larghezza del dispositivo, la scala iniziale = 1.0, la scala massima = 1.0, user-scalable=0> \«>»; «<meta http-equiv = \«tipo contento \» contenuti = \«testo / html; charset=UTF-8 \«>»; «<title>MQTT Gateway</title>»; «<style>»; «corpo {colore di sfondo: #d2f3eb; famiglia della serie completa di caratteri: Arial, Helvetica, Sans-grazia; Colore: #000000;font-size:12pt;}» «Th {colore di sfondo: #b6c0db; colore: #050ed2;font-weight:lighter;font-size:10pt;}» «tavolo, th, td {confine: 1px px nero affidabile;}» «.titel {font-size:18pt;font-weight:bold;text-align:center;}» «</style>»;; può PROGMEM lavoro a giornata HTML_HEADER_END[] = «</head>»; «<body><div disegna = 'il margine-left:30px; '>»;; può PROGMEM lavoro a giornata HTML_SCRIPT[] = «<script lingua = \«javascript \«>»; «la funzione ricarica () {» «document.location = \«http://%s \»;}» «</script>»;; può PROGMEM lavoro a giornata HTML_END_RELOAD[] = «</div><script la lingua = \«javascript \«>setTimeout (ricaricano, 10000) ;</script></body>»; «</html>»;; può PROGMEM lavoro a giornata HTML_END[] = «</body></html>»;; può PROGMEM lavoro a giornata HTML_TAB_GERAETE[] = «<table disegna = \«width:100 il % \«><tr><th gli stili = \«width:20 il % \«>ID</th><th gli stili = \«width:10 il % \«>Nr.</th>»; «<th disegna = \«width:20 il % \«>Kanäle</th><th gli stili = \«width:20 il % \«>Name</th>»; «<th disegna = \«width:20 il % \«>Letzte Daten</th><th gli stili = \«width:10 il % \«>Aktion</th></tr>»;; può PROGMEM lavoro a giornata HTML_TAB_END[] = «</table>»;; può PROGMEM lavoro a giornata HTML_NEWDEVICE[] = «<div disegna = \«il margine-top:20px; \«>%s nome: <input battono a macchina = \«il testo \»» il nome = \«devname \» maxlength = \«gli stili = \«width:200px \10 \» il valore = \» \» > <button il nome = \«il registro \» il valore = \» il % vede \«>Registrieren</button></div>»;; può PROGMEM lavoro a giornata HTML_TAB_ZEILE[] = «<tr><td>%s</td><td>%i</td><td>%i a %i</td><td>%s</td><td>%s</td><td><button il nome = \«cancellano \» il valore = \» il % i \«>Löschen</button></td></tr>»;; può PROGMEM lavoro a giornata HTML_CONFIG[] = «<form il metodo = \«annunciano \«><h1>Zugangsdaten</h1><table>»; «<tr><td>WLAN SSID</td><td><input il tipo = \«il testo \» il nome = \«ssid \» il valore = \«il % vede \» size=50 maxlen=30/></td></tr>»; «<tr><td>WLAN Passwort</td><td><input il tipo = \«il testo \» il nome = \«pwd \» il valore = \«il % vede \» size=50 maxlen=30/></td></tr>»; «<tr><td>Cayenne Benutzername</td><td><input il tipo = \«il testo \» il nome = \«mquser \» il valore = \«il % vede \» size=50 maxlen=40/></td></tr>»; «<tr><td>Cayenne Passwort</td><td><input il tipo = \«il testo \» il nome = \«mqpwd \» il valore = \«il % vede \» size=50 maxlen=50/></td></tr>»; «<tr><td>Cayenne il cliente Id</td><td><input il tipo = \«il testo \» il nome = \«mqid \» il valore = \«il % vede \» size=50 maxlen=40/></td></tr>»; «<tr><td> </td><td><button il nome = \«fa economie \» value=>Speichern</button></td></tr>»; «</table></form></body></html>»;; //Strutture di dati //Respingente di notizie struct MESSAGE_BUF { uint8_t battere a macchina; uint8_t di nuovo; uint8_t dati[10]; }; //Definizione di dispositivo struct DISPOSITIVO { uint8_t attivamente; uint8_t servizi; //0=LoRa, 1=ESP-Now uint8_t id[6]; Spago nome; Spago leggere; }; //Variabili globali //I dati di accesso questo può esser dato sul server Web Spago wlanssid = «Lechner LAN»; Spago wlanpwd = «Guadalquivir2711»; Spago mqttuser = ""; Spago mqttpwd = ""; Spago mqttid = ""; //Autorità di server Web Server Web server(80); //Esposizione OLED SSD1306 esposizione(0x3c, 4, 15); //Respingente al respingente del canale di notizie MESSAGE_BUF messaggi[MAXCHANNELS]; //Lista dei dispositivi definiti DISPOSITIVO dispositivi[MAXDEVICE]; //Id di non dispositivo registrato uint8_t sconosciuto[6]; //Si affievolisca sempre allora vero quando un nuovo dispositivo fu scoperto boolean nuovo dispositivo = falso; //Tipo del nuovo dispositivo 0=LöRa 1 =ESPNow uint8_t neuesGeraetTyp = 0; //Counter e stato di Aktivitaets per l'esposizione uint32_t loraCnt = 0; //Numero delle notizie di LoRa ricevute Spago loraLast = ""; //Data e tempo delle ultime notizie di LoRa ricevute uint32_t nowCnt = 0; //Numero delle notizie ricevute SPECIALMENTE Adesso Spago nowLast = ""; //Data e tempo delle ultime notizie di LoRa ricevute uint32_t cayCnt = 0; //Numero delle notizie mandate MQTT Spago cayLast = ""; // Data e ora dell'ultimo messaggio MQTT inviato // La funzione restituisce data e ora nel formato aaaa-mm-gg hh: mm: ss come stringa stringa GetLocalTime() { carbonizzare stTime[20] = ""; struct tm informazioni tempo; se (WiFi.stato() == WL_CONNECTED) { se(!GetLocalTime(&informazioni tempo)){ serial.println("Impossibile ottenere il tempo"); ritorno stTime; } strftime(stTime, sizeof(stTime), "%Y-%m-%d %H:%M:%S", &informazioni tempo); } ritorno stTime; } // La funzione restituisce un ID dispositivo a 6 byte nel formato xx: xx: xx: xx: xx: xx come stringa stringa getId(uint8_t id[6]) { stringa STID; carbonizzare tmp[4]; sprintf(tmp,"% 02x",id[0]); STID=tmp; per (uint8_t j = 1; j<6; j++) { sprintf(tmp,":% 02x",id[j]); STID = STID += tmp ; } ritorno STID; } // prepara il buffer dei messaggi // imposta tutti i messaggi su done vuoto buffer dei messaggi init() { per (int io = 0;io<MaxChannels;io++) messaggi[io].nuovo = 0; } // Funzione per salvare la configurazione vuoto scrivi configurazione(const carbonizzare *fn) { file f = spiffs.aperto(fn, file_write); se (!f) { serial.println(F("ERRORE: SPIFFS Impossibile salvare la configurazione")); ritorno; } per (uint8_t io = 0; io<MAXDEVICE; io++) { f.stampare(dispositivi[io].attivamente);f.stampare(","); f.stampare(dispositivi[io].servizio);f.stampare(","); f.stampare(getId(dispositivi[io].id));f.stampare(","); f.stampare(dispositivi[io].nome);f.stampare(","); f.println(dispositivi[io].carico); } } // Funzione per la memorizzazione dei dati di accesso vuoto accesso in scrittura(const carbonizzare *fn) { file f = spiffs.aperto(fn, file_write); se (!f) { serial.println(F("ERRORE: SPIFFS non può salvare i dati di accesso")); ritorno; } f.stampare("WLANSSID =");f.stampare(wlanssid);f.stampare('\ n'); f.stampare("WLANPWD =");f.stampare(wlanpwd);f.stampare('\ n'); f.stampare("MQTTUSER =");f.stampare(mqttuser);f.stampare('\ n'); f.stampare("MQTTPWD =");f.stampare(mqttpwd);f.stampare('\ n'); f.stampare("MQTTID =");f.stampare(mqttid);f.stampare('\ n'); } // Funzione per la registrazione di un nuovo dispositivo vuoto geraetRegistrieren() { uint8_t io = 0; // cerca l'ingresso gratuito mentre ((io<MAXDEVICE) && dispositivi[io].attivamente) io++; // se non ci sono nuove voci, non facciamo nulla se (io < MAXDEVICE) { // altrimenti registra Nome dispositivo = nome inserito // o sconosciuto se non ne è stato inserito nessuno se (server.hasArg("Devname")) { dispositivi[io].nome = server.cattivo("Devname"); } altro { dispositivi[io].nome = "Sconosciuto"; } per (uint8_t j = 0; j<6; j++) dispositivi[io].id[j]=sconosciuto[j]; dispositivi[io].attivamente = 1; dispositivi[io].servizio= nuovo tipo di dispositivo; dispositivi[io].carico = ""; scrivi configurazione("/Konfiguration.csv"); nuovo dispositivo = falso; } } // La pagina di configurazione viene visualizzata dal server Web vuoto handleConfig(){ carbonizzare htmlbuf[1024]; booleano nuovo inizio = falso; int indice; // è stato premuto il pulsante di memoria? se (server.hasArg("Salva")) { // Dati dalla richiesta POST wlanssid = server.cattivo("SSID"); // se il SSID contiene uno spazio otteniamo un "+" // questo deve essere riconvertito in uno spazio per la registrazione wlanssid.sostituire("+"," "); wlanpwd = server.cattivo("PWD"); mqttuser = server.cattivo("Mquser"); mqttpwd = server.cattivo("Mqpwd"); mqttid = server.cattivo("Mqid"); serial.println("Nuova configurazione:"); serial.stampare("SSID");serial.println(wlanssid); serial.stampare("Password");serial.println(wlanpwd); serial.stampare("Utente");serial.println(mqttuser); serial.stampare("Password");serial.println(mqttpwd); serial.stampare("ID");serial.println(mqttid); // Salva la nuova configurazione in SPIFFS accesso in scrittura("/Zugang.txt"); // ricordiamo che è necessario riavviare la connessione WiFi //comunque, prima deve consegnare tessono il server la parte di HTML genere di riposo = vero; } //Problema della parte di configurazione //formiamo la lancetta sulla memoria interna dello spago di accesso //usare la connessione intorno a questo per sprintf e per iniziare il WLAN e Caienna lavoro a giornata* txtSSID = const_cast<lavoro a giornata*>(wlanssid.c_str()); lavoro a giornata* txtPassword = const_cast<lavoro a giornata*>(wlanpwd.c_str()); lavoro a giornata* txtUser = const_cast<lavoro a giornata*>(mqttuser.c_str()); lavoro a giornata* txtPwd = const_cast<lavoro a giornata*>(mqttpwd.c_str()); lavoro a giornata* txtId = const_cast<lavoro a giornata*>(mqttid.c_str()); //Mandi la parte di HTML di attualità a navigatore server.setContentLength(CONTENT_LENGTH_UNKNOWN); //Testata server.mandare(200, «testo / html»,HTML_HEADER); server.sendContent(HTML_HEADER_END); //La forma con i campi d'impiego diventa con i valori di attualità befüllt sprintf(htmlbuf,HTML_CONFIG,txtSSID,txtPassword,txtUser,txtPwd,txtId); //e in Browsewr mandato server.sendContent(htmlbuf); server.sendContent(HTML_END); se (genere di riposo) { //Se il resto che la bandiera gentile è stata in modo posato deve fare la connessione di WiFi separatamente e di nuovo //sono costruiti Seriale.println(«Ripresa»); uint8_t time out = 0; Seriale.println(«Connessione separata»); WiFi.sconnettere(); mentre ((WiFi.stato() == WL_CONNECTED) && (time out < 10)) { ritardo(1000); time out++; } Seriale.println(«Di nuovo si connetta»); WiFi.cominciare(txtSSID,txtPassword); mentre ((WiFi.stato() != WL_CONNECTED) && (time out < 10)) { ritardo(1000); time out++; } Seriale.stampa(«Indirizzo IP»:); Seriale.println(WiFi.localIP()); se (WiFi.stato() == WL_CONNECTED) { //è stato di Neustrart con successo la connessione con Caienna deve esser anche aumentata di nuovo. Seriale.println(«Caienna si connette»); Caienna.cominciare(txtUser, txtPwd, txtId); //L'orologio sincronizza con server di tempo configTime(GMT_OFFSET_SEC, DAYLIGHT_OFFSET_SEC, NTP_SERVER); //Trascorra il tempo di attualità Seriale.println(getLocalTime()); } } } //La parte di azzerramento è stata interrogata dal server Web vuoto handleReset() { //mettiamo i dati di accesso da parte wlanssid= ""; wlanpwd = ""; mqttuser = ""; mqttpwd=""; mqttid=""; //e indichi i dati di configurazione //solo se sulla configurazione parteggiano il distintivo //A memorie è fatto clic, diventi i dati di accesso //anche nello SPIFFS estinto. handleConfig(); } //La parte con la lista di dispositivo è stata interrogata dal server Web vuoto handleWLANRequest(){ lavoro a giornata htmlbuf[512]; lavoro a giornata tmp1[20]; lavoro a giornata tmp2[20]; lavoro a giornata tmp3[20]; intervallo indice; //è stato fatto clic il pulsante di estinzione? se (server.hasArg(«cancellare»)) { indice = server.male(«cancellare»).toInt(); #ifdef DEGUG Seriale.printf(«Dispositivo di Lösche %i =»,indice); Seriale.println(dispositivi[indice].nome); #endif dispositivi[indice].attivamente=0; schreibeKonfiguration(«/konfiguration.csv»); } //è stata fatta clic la registrazione di pulsante? se (server.hasArg(«registro»)) { geraetRegistrieren(); } //Mandi la parte di HTML di attualità a navigatore server.setContentLength(CONTENT_LENGTH_UNKNOWN); //Testata server.mandare(200, «testo / html»,HTML_HEADER); //Si rivolga a IP per ricaricano il copione WiFi.localIP().toString().toCharArray(tmp1,20); sprintf(htmlbuf,HTML_SCRIPT,tmp1); server.sendContent(htmlbuf); server.sendContent(HTML_HEADER_END); //Inizio di forma server.sendContent(«<div la classe = \«il titolo \«>MQTT - Gateway</div><form il metodo = \«annunciano \«>»;); //Tavolo dei dispositivi attivi server.sendContent(HTML_TAB_GERAETE); per (uint8_t io = 0; io<MAXDEVICE; io++) { se (dispositivi[io].attivamente == 1) { getId(dispositivi[io].id).toCharArray(tmp1,20); dispositivi[io].nome.toCharArray(tmp2,20); dispositivi[io].leggere.toCharArray(tmp3,20); sprintf(htmlbuf,HTML_TAB_ZEILE,tmp1,io,io*8,io*8+7,tmp2,tmp3,io); server.sendContent(htmlbuf); } } server.sendContent(HTML_TAB_END); // Se viene trovato un nuovo dispositivo, il suo ID e un campo di input per il nome // e viene visualizzato un pulsante per la registrazione del nuovo dispositivo se (nuovo dispositivo) { getId(sconosciuto).ToCharArray(tmp1,20); sprintf(htmlbuf,HTML_NEWDEVICE,tmp1,tmp1); server.Invia contenuti(htmlbuf); } server.Invia contenuti(HTML_END_RELOAD); } // Funzioni di servizio del server Web per la directory principale vuoto handleRoot() { se (WiFi.stato() != WL_CONNECTED) { // se non abbiamo alcuna connessione alla rete del router // Viene visualizzata la pagina di configurazione in modo da poter inserire i dati di accesso handleConfig(); } altro { handleWLANRequest(); } } // Funzione per cercare un dispositivo nell'elenco dei dispositivi // Restituisce l'indice del dispositivo o -1 se non è stato trovato int dispositivo posto(uint8_t dev[6]) { uint8_t j; uint8_t io = 0; booleano fondare = falso; fare { j = 0; se (dispositivi[io].attivamente == 0) { io++; } altro { mentre ((j < 6) && (dev[j] == dispositivi[io].id[j])) {j++;} fondare = (j == 6); se (!fondare) io++; } } mentre ((io<MAXDEVICE) && (!fondare)); se (fondare) {ritorno io;} altro {ritorno -1;} } // Funzione per visualizzare lo stato sul display OLED vuoto display() { display.chiaro(); display.drawString(0,0,"MQTT Gateway"); display.drawString(0,10,GetLocalTime()); display.drawString(0,20,WiFi.LocalIP().toString()); display.drawString(0,34,"MQTT"); display.drawString(60,34,stringa(cayCnt)); display.drawString(0,44,"LoRa"); display.drawString(60,44,stringa(loraCnt)); display.drawString(0,54,"NOW"); display.drawString(60,54,stringa(nowCnt)); display.display(); } // Elabora un messaggio da un client LoRa vuoto readLoRa() { int devnr; uint8_t devid[6]; uint8_t canale; uint8_t tipo; uint8_t len; uint8_t dat; booleano produzione; // recupera i dati se disponibili int dimensione del pacchetto = LoRa.parsePacket(); // abbiamo ricevuto dati? se (dimensione del pacchetto > 5) { #ifdef DEBUG serial.println(GetLocalTime()); serial.stampare("RX"); serial.stampare(dimensione del pacchetto); serial.println("Byte"); serial.stampare("ID dispositivo"); #endif // legge prima l'ID del dispositivo per (uint8_t io=0; io<6;io++){ devid[io]=LoRa.leggere(); #ifdef DEBUG serial.printf("-% 02x",devid[io]); #endif } #ifdef DEBUG serial.println(); #endif // calcola il pacchetto rimanente dimensione del pacchetto -= 6; // controlla se il dispositivo è registrato devnr = dispositivo posto(devid); se (devnr >= 0) { // se sì, impostiamo il timestamp per l'ultimo messaggio e // leggi i dati dispositivi[devnr].carico = GetLocalTime(); scrivi configurazione("/Konfiguration.csv"); mentre (dimensione del pacchetto > 0) { // Numero canale = numero dispositivo * 16 + canale dispositivo canale = LoRa.leggere() + devnr*16; #ifdef DEBUG serial.printf("Canale:% 02x",canale); #endif // tipo di canale tipo = LoRa.leggere(); #ifdef DEBUG serial.printf("Tipo:% 02x",tipo); #endif // determina la lunghezza del pacchetto di dati e se il canale è un attuatore produzione = falso; interruttore(tipo) { caso LPP_DIGITAL_INPUT : len = LPP_DIGITAL_INPUT_SIZE - 2; pausa; caso LPP_DIGITAL_OUTPUT : len = LPP_DIGITAL_OUTPUT_SIZE - 2; produzione = vero; pausa; caso LPP_ANALOG_INPUT : len = LPP_ANALOG_INPUT_SIZE - 2; pausa; caso LPP_ANALOG_OUTPUT : len = LPP_ANALOG_OUTPUT_SIZE - 2; produzione = vero; pausa; caso LPP_LUMINOSITY : len = LPP_LUMINOSITY_SIZE - 2; pausa; caso LPP_PRESENCE : len = LPP_PRESENCE_SIZE - 2; pausa; caso LPP_TEMPERATURE : len = LPP_TEMPERATURE_SIZE - 2; pausa; caso LPP_RELATIVE_HUMIDITY : len = LPP_RELATIVE_HUMIDITY_SIZE - 2; pausa; caso LPP_ACCELEROMETER : len = LPP_ACCELEROMETER_SIZE - 2; pausa; caso LPP_BAROMETRIC_PRESSURE : len = LPP_BAROMETRIC_PRESSURE_SIZE - 2; pausa; caso LPP_GYROMETER : len = LPP_GYROMETER_SIZE - 2; pausa; caso LPP_GPS : len = LPP_GPS_SIZE - 2; pausa; difetto: len = 0; } //se il canale non è nessun attuatore, mettiamo nel respingente di notizie di nuovo su 1 //con esso i dati sono mandati con la prossima opportunità al server MQTT se (!uscita) messaggi[canale].di nuovo =1; messaggi[canale].battere a macchina = battere a macchina; //Il pacco di riposo = 2 meno canali là e tipo è stato letto packetSize -= 2; #ifdef MESSA A PUNTO Seriale.stampa(«Dati»:); #endif //adesso leggiamo i dati ricevuti con la lunghezza accertata per (uint8_t io=0; io<len; io++) { dat = LoRa.Leggere(); //per attuatori non ci notiamo nessun dato se (! uscita) messaggi[canale].dati[io] = dat; #ifdef MESSA A PUNTO Seriale.printf(«-x»,dat); #endif //Pacco di riposo di diminuzione intorno a uno packetSize --; } #ifdef MESSA A PUNTO Seriale.println(); #endif } //Aggiornamenti di stato loraCnt++; loraLast = getLocalTime(); registri(); } altro { //Il dispositivo non è registrato //ci notiamo che il Geräte-Id intorno a loro per Registriuerung si iscrive per (uint8_t io = 0; io<6; io++) sconosciuto[io] = devid[io]; nuovo dispositivo = vero; neuesGeraetTyp = 0; //Dispositivo di LoRa } //La parte due risposte manda al dispositivo di LoRa ritardo(100); LoRa.beginPacket(); //all'inizio il Geräte-Id LoRa.scrivere(devid,6); //chiediamo se i dati di uscita per il dispositivo di LoRa di attualità abbiamo intervallo devbase = devnr*16; per (intervallo io = devbase; io<devbase+8; io++) { //secondo tipo Digitalmente o dati analoghi interruttore (messaggi[io].battere a macchina) { caso LPP_DIGITAL_OUTPUT : LoRa.scrivere(io-devbase); LoRa.scrivere(messaggi[io].battere a macchina); LoRa.scrivere(messaggi[io].dati,1); #ifdef MESSA A PUNTO Seriale.println(«Digitalmente uscita»); #endif pausa; caso LPP_ANALOG_OUTPUT : LoRa.scrivere(io-devbase); LoRa.scrivere(messaggi[io].battere a macchina); LoRa.scrivere(messaggi[io].dati,2); #ifdef MESSA A PUNTO Seriale.println(«Analogamente uscita»); #endif pausa; } } intervallo lstatus = LoRa.endPacket(); #ifdef MESSA A PUNTO Seriale.stampa(«Stato trasmittente =»); Seriale.println(lstatus); #endif } } //Funzione alla lettura della configurazione vuoto lettura di configurazione(può lavoro a giornata *fn) { uint8_t io = 0; Spago tmp; lavoro a giornata stregoneria di pratica[3]; se (!SPIFFS.esiste(fn)) { //non esiste già allora generano schreibeKonfiguration(fn); ritornare; } File e il seguente = SPIFFS.aperto(fn, «r»); se (!e il seguente) { Seriale.println(E IL SEGUENTE(«ERRORE:: SPIFFS essere la configurazione capace non si aprono»)); ritornare; } mentre (e il seguente.disponibile() && (io<MAXDEVICE)) { tmp = e il seguente.readStringUntil(','); dispositivi[io].attivamente = (tmp == "1"); tmp = e il seguente.readStringUntil(','); dispositivi[io].servizi = tmp.toInt(); tmp = e il seguente.readStringUntil(','); per (uint8_t j=0; j<6; j++){ stregoneria di pratica[0]=tmp[j*3]; stregoneria di pratica[1]=tmp[j*3+1]; stregoneria di pratica[2]=0; dispositivi[io].id[j]= (byte) strtol(stregoneria di pratica,ZERO,16); } tmp = e il seguente.readStringUntil(','); dispositivi[io].nome = tmp; tmp = e il seguente.readStringUntil(','); dispositivi[io].leggere = tmp; io++; } } //Funzione alla lettura dei dati di accesso vuoto lettura di accesso(può lavoro a giornata *fn) { uint8_t io = 0; Spago chiave; Spago val; lavoro a giornata stregoneria di pratica[3]; se (!SPIFFS.esiste(fn)) { //non esiste già allora generano schreibeZugang(fn); ritornare; } File e il seguente = SPIFFS.aperto(fn, «r»); se (!e il seguente) { Seriale.println(E IL SEGUENTE(«ERRORE:: SPIFFS essere dati di accesso capaci non si aprono»)); ritornare; } mentre (e il seguente.disponibile() && (io<MAXDEVICE)) { chiave = e il seguente.readStringUntil('='); val = e il seguente.readStringUntil(di '\n'); se (chiave == «WLANSSID») wlanssid = val; se (chiave == «WLANPWD») wlanpwd = val; se (chiave == «MQTTUSER») mqttuser = val; se (chiave == «MQTTPWD») mqttpwd = val; se (chiave == «MQTTID») mqttid = val; } } vuoto situazione() { //le memorie di dispositivo inizializzano per (uint8_t io =0; io<MAXDEVICE; io++) dispositivi[io].attivamente = 0; //Inizializzi l'esposizione OLED pinMode(16,USCITA); digitalWrite(16, IN BASSO); ritardo(50); digitalWrite(16, IN ALTO); esposizione.init(); esposizione.flipScreenVertically(); esposizione.setFont(ArialMT_Plain_10); esposizione.setTextAlignment(TEXT_ALIGN_LEFT); //Cominci l'interfaccia seriale Seriale.cominciare(115200); mentre (!Seriale); Seriale.println(«Cominciare»); //Sistema di file di lampo se (SPIFFS.cominciare(FORMAT_SPIFFS_IF_FAILED)) Seriale.println(E IL SEGUENTE(«SPIFFS caricato»)); //Legga in dati di accesso e di configurazione lettura di configurazione(«/konfiguration.csv»); lettura di accesso(«/zugang.txt»); initMessageBuffer(); //SPI e LoRa inizializzano SPI.cominciare(5,19,27,18); LoRa.setPins(SS,RST,DI0); Seriale.println(«LoRa TRX»); se (!LoRa.cominciare(NASTRO)) { Seriale.println(«L'inizio di LoRa ha fallito!»); mentre (1); } LoRa.enableCrc(); Seriale.println(«LoRa inizialmente va bene!»); ritardo(2000); //Problema dei dati di accesso letti al controllo Seriale.stampa(«SSID»:);Seriale.println(wlanssid); Seriale.stampa(«Parola d'ordine»:);Seriale.println(wlanpwd); Seriale.stampa(«Utente»:);Seriale.println(mqttuser); Seriale.stampa(«Parola d'ordine»:);Seriale.println(mqttpwd); Seriale.stampa(«ID»:);Seriale.println(mqttid); //Colleghi al WLAN e il server MQTT Seriale.println(«WLAN si connettono»); //usiamo l'ESP32 come un Accesso Poin, comunque, anche come un cliente nella rete d'instradatore WiFi.moda(WIFI_AP_STA); //abbiamo bisogno di lancetta sulla memoria di segno dentro lo spago lavoro a giornata* txtSSID = const_cast<lavoro a giornata*>(wlanssid.c_str()); lavoro a giornata* txtPassword = const_cast<lavoro a giornata*>(wlanpwd.c_str()); lavoro a giornata* txtUser = const_cast<lavoro a giornata*>(mqttuser.c_str()); lavoro a giornata* txtPwd = const_cast<lavoro a giornata*>(mqttpwd.c_str()); lavoro a giornata* txtId = const_cast<lavoro a giornata*>(mqttid.c_str()); WiFi.cominciare(txtSSID, txtPassword); //La connessione nella rete d'instradatore è prodotta uint8_t time out = 0; mentre ((WiFi.stato() != WL_CONNECTED) && (time out<10)) { time out++; ritardo(1000); } //aspettiamo 10 secondi massimi agli stand di connessione //Senza badare alla connessione nella rete d'instradatore cominciamo AccessPoint //questo permette la configurazione su un navigatore, se noi a questi //in AccessPoint annunciano WiFi.softAP(«MQTTGateway»); se (WiFi.stato() == WL_CONNECTED) { //Se la connessione è stata di successo nella rete d'instradatore, cominciamo MQTT a Caienna //e sincronizzi l'orologio interno con il server di tempo Seriale.stampa(«Indirizzo IP»:); Seriale.println(WiFi.localIP()); Caienna.cominciare(txtUser, txtPwd, txtId); Seriale.println(«Connessione di Caienna fatta»); //L'orologio sincronizza con server di tempo configTime(GMT_OFFSET_SEC, DAYLIGHT_OFFSET_SEC, NTP_SERVER); //Trascorra il tempo di attualità Seriale.println(getLocalTime()); } //I server Web inizializzano server.su("/", handleRoot); server.su(«/conf»,handleConfig); server.su(«/azzerramento»,handleReset); server.cominciare(); Seriale.println("*********************************************"); } vuoto cappio() { registri(); se (WiFi.stato() == WL_CONNECTED) { //Controlli l'interfaccia LoRa per dati readLoRa(); //con Caienna i server di MQTT comunicano Caienna.cappio(1); } //Servizio di server Web server.handleClient(); } //I dati dal respingente di notizie mandano al server MQTT CAYENNE_OUT_DEFAULT() { boolean uscita = falso; boolean sentData = falso; #ifdef MESSA A PUNTO Seriale.println(getLocalTime()); Seriale.println(«Caienna manda»); #endif per (intervallo io = 0; io<MAXCHANNELS; io++) { //solo le notizie mandano se (messaggi[io].di nuovo == 1) { #ifdef MESSA A PUNTO Seriale.printf(«Sende MQTT Typ %i\n»,messaggi[io].battere a macchina); #endif //secondo tipo i Dati mandano interruttore (messaggi[io].battere a macchina) { caso LPP_DIGITAL_INPUT : Caienna.digitalSensorWrite(io,messaggi[io].dati[0]); pausa; caso LPP_DIGITAL_OUTPUT : uscita = vero; pausa; //caso LPP_ANALOG_INPUT: Cayenne.virtualWrite (io, (messaggi [io] .daten [0] *256 messaggi [io] .daten [1])/100, «analog_sensor», UNIT_UNDEFINED); pausa; pausa; caso LPP_ANALOG_OUTPUT : uscita = vero; pausa; caso LPP_LUMINOSITY : Caienna.luxWrite(io,messaggi[io].dati[0]*256 + messaggi[io].dati[1]); pausa; caso LPP_PRESENCE : Caienna.digitalSensorWrite(io,messaggi[io].dati[0]); pausa; caso LPP_TEMPERATURE : Caienna.celsiusWrite(io,(messaggi[io].dati[0]*256 + messaggi[io].dati[1])/10); pausa; caso LPP_RELATIVE_HUMIDITY : Caienna.virtualWrite(io,messaggi[io].dati[0]/2,TYPE_RELATIVE_HUMIDITY,UNIT_PERCENT); pausa; caso LPP_ACCELEROMETER : Caienna.virtualWrite(io,(messaggi[io].dati[0]*256 + messaggi[io].dati[1])/1000,«gx»,«g»); pausa; caso LPP_BAROMETRIC_PRESSURE : Caienna.hectoPascalWrite(io,(messaggi[io].dati[0]*256 + messaggi[io].dati[1])/10); pausa; //caso LPP_GYROMETER: len = LPP_GYROMETER_SIZE - 2; pausa; //caso LPP_GPS: len = LPP_GPS_SIZE - 2; pausa; } se (!uscita) { messaggi[io].di nuovo = 0; sentData = vero; } } } se (sentData) { //Aggiornamenti di stato cayCnt++; cayLast = getLocalTime(); registri(); } } CAYENNE_IN_DEFAULT() { uint8_t * pData; intervallo val; intervallo ch = richiesta.canale; #ifdef MESSA A PUNTO Seriale.println(«Caienna riceve»); Seriale.printf(«Dati MQTT per canale %i = %s\n»,ch,getValue.asString()); #endif interruttore (messaggi[ch].battere a macchina) { caso LPP_DIGITAL_OUTPUT : messaggi[ch].dati[0] = getValue.santo(); messaggi[ch].di nuovo = 1; pausa; caso LPP_ANALOG_OUTPUT : val = intorno(getValue.asDouble()*100); messaggi[ch].dati[0] = val / 256; messaggi[ch].dati[1] = val % 256; messaggi[ch].di nuovo = 1; pausa; } CAYENNE_LOG(«Il canale %u, valuti %s», richiesta.canale, getValue.asString()); //Messaggio di processo qui. Se c'è in serie di errore in messaggio di errore usando getValue.setError (), ad esempio getValue.setError («L'errore di messaggio»); }
Molto divertimento con la prova.