En la Parte 3 , tenemos una Pasarela construida como Cliente en una Red WI-fi funciona. Era necesario, por tanto los datos de Acceso correspondientes Constantes en la Memoria del programa de inmersión. Ya tenemos la puerta de enlace también para ESP-Now desea utilizar, sería conveniente si la puerta de enlace también como Punto de Acceso podría trabajar.
Ahora la ESP32 puede. Si tenemos el WiFi de Moda WIFI_AP_STA tasas funciona el ESP, tanto como Access Point y también como Estación. Sin embargo, sólo un Canal. La Conexión en Routernetzwerk en la selección del Canal de Prioridad. Es decir, el Punto de Acceso utiliza siempre el mismo Canal, como la Conexión en Routernetzwerk.
Ahora, vamos a este Doppelmode utilizar nuestro Gateway a través de un Navegador para configurarlo. La información de Acceso necesaria, como el SSID y la Contraseña, pero los datos de Acceso a Cayenne simplemente en Leerstrings. La puerta de enlace se inicia lo que no puede tener Conexión en Routernetzwerk construir, ya que los datos que faltan. Después de que el Intento de conexión en tiempo de espera se ha ido, el Punto de Acceso con el SSID MQTTGateway se inicia. La Dirección IP de la puerta de enlace es en esta web, siempre 192.168.4.1
Para la puerta de enlace para configurar informar de un Ordenador o un Smartphone, en esta Red (sin Contraseña) e iniciar el Navegador con la Dirección http://192.168.4.1 Debemos entonces la siguiente página de Configuración ver.
Si las Credenciales se almacenan, tratando de puerta de enlace se conecta con el Routernetz de fabricar. Es la conexión se realiza correctamente, la Pantalla muestra la Dirección IP de la puerta de enlace en el Routernetz se puede lograr.
Después de una Conexión con el Routernetz compuesto se obtiene en el Navegador siempre la Lista de Dispositivos registrados. A través de la Ruta de acceso /conf se puede mirar en la página de Configuración para acceder y cambiar los datos de Acceso.
Sketch:
/* El MQTT Gateway proporciona una Interfaz entre LoRa Dispositivos o ESP Nowe Dispositivos * y la Cayena MQTT cuadro de Mandos. Se ejecuta en ESP32 con LoRa y Pantalla OLED * La Configuración se realiza desde el Navegador */ #include <SPI.h> #include <LoRa.h> #include "SSD1306.h" #include<Arduino.h> #include <CayenneMQTTESP32.h> #include <CayenneLPP.h> #include <WiFi.h> #include <Servidor web.h> #include <time.h> #include "FS.h" #include "SPIFFS.h" //Servidor NTP para sincronizar la hora #define NTP_SERVER "de.pool.ntp.org" #define GMT_OFFSET_SEC 3600 #define DAYLIGHT_OFFSET_SEC 0 //pin de la LoRa Chip #define SS 18 #define RST 14 #define DI0 26 //Frecuencia de la LoRa Chip #define BANDA 433175000 // #define MAXCHANNELS 256 //Número máximo de los Canales #define MAXDEVICE 32 //Número máximo de Dispositivos administrados MAXCHANNELS/MAXDEVICE = 8 da como resultado el Número máximo de Canales por Unidad //Formato Flash Filesystem si aún no lo ha hecho #define FORMAT_SPIFFS_IF_FAILED true #define DEBUG 1 //Bloques de construcción para el Servidor Web const PROGMEM char HTML_HEADER[] = "<!DOCTYPE HTML>" "<html>" "<head>" "<meta name = \"ventanilla\" 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 puerta de enlace</title>" "<style>" "body { background-color: #d2f3eb; font-family: Arial, Helvetica, Sans-Serif; Color: #000000;font-size:12pt; }" "th { background-color: #b6c0db; color: #050ed2;font-weight:lighter;font-size:10pt;}" "table, th, td {border: 1px solid black;}" ".título {font-size:18 pto;font-weight:bold;text-align:center;} " "</style>"; const PROGMEM char HTML_HEADER_END[] = "</head>" "<body><div style='margin-left:30px;'>"; const PROGMEM char HTML_SCRIPT[] = "<script language=\"javascript\">" "function reload() {" "document.location=\"http://%s\";}" "</script>"; const PROGMEM char HTML_END_RELOAD[] = "</div><script language=\"javascript\">setTimeout(reload, 10000);</script></body>" "</html>"; const PROGMEM char HTML_END[] = "</body></html>"; const PROGMEM char HTML_TAB_GERAETE[] = "<table style=\"width:100%\"><tr><th style=\"width:20%\">ID</th><th style=\"width:10%\">Número</th>" "<th style=\"width:20%\">Kanäle</th><th style=\"width:20%\">Nombre</th>" "<th style=\"width:20%\">Letzte Daten</th><th style=\"width:10%\">Acción</th></tr>"; const PROGMEM char HTML_TAB_END[] = "</table>"; const PROGMEM char HTML_NEWDEVICE[] = "<div style=\"margin-top:20px;\">%s Nombre: <input type=\"text\" style=\"width:200px\" name=\"devname\" maxlength=\"10\" value=\"\"> <button name=\"registrieren\" value=\"%s\">Registrieren</button></div>"; const PROGMEM char HTML_TAB_ZEILE[] = "<tr><td>%s</td><td>%i</td><td>%i bis %i</td><td>%s</td><td>%s</td><td><button name=\"delete\" value=\"%i\">Löschen</button></td></tr>"; const PROGMEM char HTML_CONFIG[] = "<form method=\"post\"><h1>Zugangsdaten</h1><table>" "<tr><td>WLAN SSID</td><td><input type=\"text\" name=\"ssid\" value=\"%s\" size=50 maxlen=30/></td></tr>" "<tr><td>WLAN Contraseña</td><td><input type=\"text\" name=\"pwd\" value=\"%s\" size=50 maxlen=30/></td></tr>" "<tr><td>Cayenne Benutzername</td><td><input type=\"text\" name=\"mquser\" value=\"%s\" size=50 maxlen=40/></td></tr>" "<tr><td>Cayenne Contraseña</td><td><input type=\"text\" name=\"mqpwd\" value=\"%s\" size=50 maxlen=50/></td></tr>" "<tr><td>Cayenne Cliente Id</td><td><input type=\"text\" name=\"mqid\" value=\"%s\" size=50 maxlen=40/></td></tr>" "<tr><td> </td><td><button name=\"guardar\" value=>Speichern</button></td></tr>" "</table></form></body></html>"; //Datenstrukturen //Nachrichten Búfer struct MSG_BUF { uint8_t typ; uint8_t neu; uint8_t daten[10]; }; //Gerätedefinition struct DISPOSITIVO { uint8_t aktiv; uint8_t dienst; //0=LoRa, 1=ESP-Ahora uint8_t id[6]; String nombre; String última; }; //Globale Variable //Zugangsdaten diese können über den Servidor Web eingegeben werden Cadena wlanssid = "Lechner LAN"; Cadena de wlanpwd = "Guadalquivir2711"; Cadena de mqttuser = ""; Cadena mqttpwd = ""; Cadena mqttid = ""; //Webserver Instanz servidor Web servidor(80); //Pantalla OLED SSD1306 pantalla(0x3c, 4, 15); //Búfer zum Zwischenspeichern der Nachrichten je Kanal MSG_BUF mensajes[MAXCHANNELS]; //Liste der definierten Geräte DISPOSITIVO dispositivos[MAXDEVICE]; //Id eines nicht registrierten Gerätes uint8_t unbekannt[6]; //Bandera immer dann wahr wenn ein neues Gerät entdeckt wurde booleano neuesGeraet = false; //Typ des neuen Gerätes 0=LöRa 1 =ESPNow uint8_t neuesGeraetTyp = 0; //Zähler und Aktivitaets Estado für das Pantalla uint32_t loraCnt = 0; //Anzahl der empfangenen LoRa Nachrichten Cadena loraLast = ""; //Datum und Zeit der letzten empfangenen LoRa que el mensaje uint32_t nowCnt = 0; //Anzahl der empfangenen ESP Ahora Nachrichten Cadena nowLast = ""; //Datum und Zeit der letzten empfangenen LoRa que el mensaje uint32_t cayCnt = 0; //Anzahl der gesendeten MQTT Nachrichten Cadena cayLast = ""; //Datum und Zeit der letzten gesendeten MQTT que el mensaje //Funktion liefert Dato und Uhrzeit im Formato aaaa-mm-dd hh:mm:ss ela Cadena Cadena getLocalTime() { char sttime[20] = ""; struct tm timeinfo; si (WiFi.de estado() == WL_CONNECTED) { si(!getLocalTime(&timeinfo)){ Serie.println("Error al obtener el tiempo de"); volver sttime; } strftime(sttime, sizeof(sttime), "%Y-%m-%d %H:%M:%S", &timeinfo); } volver sttime; } //Funktion liefert eine 6 Bytes Geräte-Id im formato xx:xx:xx:xx:xx:xx ela Cadena String getId(uint8_t id de[6]) { Cadena stid; char tmp[4]; sprintf(tmp,"%02x",id[0]); stid=tmp; para (uint8_t j = 1; j<6; j++) { sprintf(tmp,":%02x",id[j]); stid = stid += tmp ; } volver stid; } //bereitet den Nachrichtenbuffer vor //setzt alle Nachrichten auf erledigt vacío initMessageBuffer() { para (int i = 0;i<MAXCHANNELS;i++) de los mensajes de la[i].neu = 0; } //Funktion zum Speichern der Konfiguration vacío schreibeKonfiguration(const char *fn) { de Archivo f = SPIFFS.open(fn, FILE_WRITE); if (!f) { Serial.println(F("ERROR: SPIFFS Configuración Puede no guardar")); return; } for (uint8_t i = 0; i<MAXDEVICE; i++) { f.print(devices[i].activo);f.print(","); f.print(devices[i].servicio);f.print(","); f.print(getId(devices[i].id));f.print(","); f.print(devices[i].nombre);f.print(","); f.println(devices[i].carga); } } //Para Guardar los datos de Acceso void schreibeZugang(const char *fn) { File f = SPIFFS.open(fn, FILE_WRITE); if (!f) { Serial.println(F("ERROR: SPIFFS Puede Credenciales no guardar")); return; } f.print("WLANSSID=");f.print(wlanssid);f.print('\n'); f.print("WLANPWD=");f.print(wlanpwd);f.print('\n'); f.print("MQTTUSER=");f.print(mqttuser);f.print('\n'); f.print("MQTTPWD=");f.print(mqttpwd);f.print('\n'); f.print("MQTTID=");f.print(mqttid);f.print('\n'); } ;//Función para Registrar un nuevo Dispositivo void geraetRegistrieren() { uint8_t i = 0; //búsqueda libre Entrada while ((i<MAXDEVICE) && devices[i].activo) i++; //no hay nueva Entrada en la que no hacemos nada if (i < MAXDEVICE) { //de lo contrario Dispositivo registrar Nombre = Nombre introducido //o desconocido si alguna se ha introducido if (server.hasArg("devname")) { devices[i].nombre del = server.arg("devname"); } else { devices[i].nombre de = "desconocido"; } for (uint8_t j = 0; j<6; j++) devices[i].id[j]=desconocido[j]; devices[i].activo = 1; devices[i].servicio= neuesGeraetTyp; devices[i].carga = ""; schreibeKonfiguration("/configuración.csv"); neuesGeraet = false; } } //La página de Configuración del Servidor Web muestra void handleConfig(){ char htmlbuf[1024]; boolean restart = false; int índice; //la Speicherknopf el botón ? if (server.hasArg("save")) { //Datos de la POST request wlanssid = server.arg("ssid"); //si el SSID contiene un Espacio en blanco, obtenemos un "+" //el necesario para iniciar la Sesión de nuevo en un Espacio transformado, se wlanssid.replace("+"," "); wlanpwd = server.arg("pwd"); mqttuser = server.arg("mquser"); mqttpwd = server.arg("mqpwd"); mqttid = server.arg("mqid"); Serial.println("Nueva Configuración:"); Serial.print("SSID: ");Serial.println(wlanssid); Serial.print("Contraseña: ");Serial.println(wlanpwd); Serial.print("Usuario: ");Serial.println(mqttuser); Serial.print("Contraseña: ");Serial.println(mqttpwd); Serial.print("ID: ");Serial.println(mqttid); //La nueva Configuración en SPIFFS guardar schreibeZugang("/zugang.txt"); //vamos a controlar que la Conexión WiFi se debe reiniciar //primero, pero el servidor web de la Página de HTML entregar restart = true; } //Salida de la página de Configuración //hacemos el Puntero a la memoria interna de la Zugangsstrings //para sprintf y para Iniciar la CONEXIÓN wi-fi y Cayenne enlace char* txtSSID = const_cast<char*>(wlanssid.c_str()); char* txtPassword = const_cast<char*>(wlanpwd.c_str()); char* txtUser = const_cast<char*>(mqttuser.c_str()); char* txtPwd = const_cast<char*>(mqttpwd.c_str()); char* txtId = const_cast<char*>(mqttid.c_str()); //Actual de la Página de HTML en el Navegador servidor.setContentLength(CONTENT_LENGTH_UNKNOWN); //Cabecera server.send(200, "text/html",HTML_HEADER); server.sendContent(HTML_HEADER_END); //El Formulario con los Campos de entrada con los Valores actuales llena sprintf(htmlbuf,HTML_CONFIG,txtSSID,txtPassword,txtUser,txtPwd,txtId); //y en el Browsewr enviado server.sendContent(htmlbuf); server.sendContent(HTML_END); if (restart) { //Era el restart bandera tiene el WiFi desconectado y conectado de nuevo //construir Serial.println("Reiniciar"); uint8_t tiempo de espera = 0; Serial.println("desconectar"); WiFi.disconnect(); while ((WiFi.estado() == WL_CONNECTED) && (tiempo de espera de < 10)) { retardo(1000); de tiempo de espera++; } Serial.println("Volver a conectar"); WiFi.begin(txtSSID,txtPassword); while ((WiFi.estado() != WL_CONNECTED) && (tiempo de espera de < 10)) { retardo(1000); de tiempo de espera++; } Serial.print("IP address: "); Serial.println(WiFi.localIP()); if (WiFi.estado() == WL_CONNECTED) { //la Neustrart éxito también se debe a que la Conexión Cayenne que ser reconstruido. Serial.println("Cayenne conectar"); Cayenne.begin(txtUser, txtPwd, txtId); //Reloj con un servidor de tiempo para sincronizar configTime(GMT_OFFSET_SEC, DAYLIGHT_OFFSET_SEC, NTP_SERVER); //Hora Actual gastar Serial.println(getLocalTime()); } } } //El reset Página fue solicitada desde el Servidor web void handleReset() { //ponemos los datos de Acceso de nuevo wlanssid= ""; wlanpwd = ""; mqttuser = ""; mqttpwd=""; mqttid=""; //y mostrar los datos de Configuración en //sólo si en la página de Configuración, el Botón //Guardar los datos de Acceso //también en SPIFFS eliminado. handleConfig(); } //La Página con la lista de Dispositivos del Servidor web para consultar void handleWLANRequest(){ char htmlbuf[512]; char tmp1[20]; char tmp2[20]; char tmp3[20]; int índice; //se ha Borrado Botón ? if (server.hasArg("delete")) { index = server.arg("delete").toInt(); #ifdef DEGUG Serial.printf("Borrar device %i = ",index); Serial.println(devices[índice].nombre); #endif devices[índice].activo=0; schreibeKonfiguration("/configuración.csv"); } //se ha de Registrar el Botón ? if (server.hasArg("registrar")) { geraetRegistrieren(); } //Actual de la Página de HTML en el Navegador servidor.setContentLength(CONTENT_LENGTH_UNKNOWN); //Cabecera server.send(200, "text/html",HTML_HEADER); //Dirección IP de recarga script WiFi.localIP().toString().toCharArray(tmp1,20); sprintf(htmlbuf,HTML_SCRIPT,tmp1); server.sendContent(htmlbuf); server.sendContent(HTML_HEADER_END); //Formulario Principio server.sendContent("<div class=\"nombre\">MQTT puerta de enlace</div><form method=\"post\">"); //Tabla de Dispositivos activos server.sendContent(HTML_TAB_GERAETE); for (uint8_t i = 0; i<MAXDEVICE; i++) { if (devices[i].activo == 1) { getId(devices[i].id).toCharArray(tmp1,20); devices[i].nombre.toCharArray(tmp2,20); devices[i].carga.toCharArray(tmp3,20); sprintf(htmlbuf,HTML_TAB_ZEILE,tmp1,i,i*8,i*8+7,tmp2,tmp3,i); servidor.sendContent(htmlbuf); } } server.sendContent(HTML_TAB_END); //Si se encuentra un nuevo Dispositivo, su ID y un Campo de entrada para el Nombre // y un Botón para Registrar el nuevo Aparato if (neuesGeraet) { getId(desconocido).toCharArray(tmp1,20); sprintf(htmlbuf,HTML_NEWDEVICE,tmp1,tmp1); server.sendContent(htmlbuf); } server.sendContent(HTML_END_RELOAD); } //Servicio de Función de Servidor Web para el Directorio Raíz void handleRoot() { if (WiFi.estado() != WL_CONNECTED) { //si no tiene Conexión a Routernetz tienen //si la página de Configuración muestra de modo que los datos se pueden introducir handleConfig(); } else { handleWLANRequest(); } } //Función para Buscar un Dispositivo en la lista de Dispositivos //Devolución Índice de la Unidad o -1 si no se encuentra int findDevice(uint8_t dev[6]) { uint8_t j; uint8_t i = 0; boolean found = false; do { j = 0; if (devices[i].activo == 0) { i++; } else { while ((j < 6) && (dev[j] == devices[i].id[j])) {j++;} found = (j == 6); if (!found) i++; } } while ((i<MAXDEVICE) && (!found)); if (found) {return i;} else {return -1;} } //Función para Mostrar el Estado de la Pantalla OLED void mostrar() { la pantalla.clear(); display.lazo(0,0,"MQTT puerta de enlace"); pantalla.de cordón(0,10,getLocalTime()); pantalla.cordón(0,20,WiFi.localIP().toString()); de la pantalla.de cordel(0,34,"MQTT: "); mostrar.el lazo(60,34,de la Cadena de(cayCnt)); pantalla.de cordel(0,44,"LoRa: "); mostrar.el lazo(60,44,de la Cadena de(loraCnt)); pantalla.de cordel(0,54,"AHORA: "); mostrar.el lazo(60,54,de la Cadena de(nowCnt)); de visualización.de la pantalla(); } //Eine que el mensaje von einem LoRa Cliente verarbeiten vacío readLoRa() { int devnr; uint8_t devid[6]; uint8_t canal; uint8_t typ; uint8_t len; uint8_t dat; booleano de salida; //Daten holen cae vorhanden int packetSize = LoRa.parsePacket(); //haben wir Daten erhalten ? si (packetSize > 5) { #ifdef DEBUG Serial.println(getLocalTime()); Serie.de impresión(" RX "); de Serie.impresión(packetSize); Serie.println(" Bytes"); de Serie.impresión("Device ID"); #endif //zuerst morir Geräte-Id lesen para (uint8_t i=0; i<6;i++){ devid[me]=LoRa.leer(); #ifdef DEBUG Serial.printf("-%02x",devid[i]); #endif } #ifdef DEBUG Serial.println(); #endif //Restpaket berechnen packetSize -= 6; //nachschauen ob das Gerät registriert ist devnr = findDevice(devid); si (devnr >= 0) { //wenn ja setzen wir den Zeitstempel für die letzte Meldung und //lesen morir Daten dispositivos[devnr].última = getLocalTime(); schreibeKonfiguration("/konfiguration.csv"); mientras (packetSize > 0) { //Kanalnummer = Gerätenummer * 16 + Gerätekanal canal = LoRa.leer() + devnr*16; #ifdef DEBUG Serial.printf("Kanal: %02x ",canal); #endif //typ des Kanals typ = LoRa.leer(); #ifdef DEBUG Serial.printf("Typ: %02x ",typ); #endif //ermitteln der Länge des Datenpakets und ob der Kanal ein Aktuator ist salida = falsa; interruptor de(tipo) { caso LPP_DIGITAL_INPUT : len = LPP_DIGITAL_INPUT_SIZE - 2; romper; caso LPP_DIGITAL_OUTPUT : len = LPP_DIGITAL_OUTPUT_SIZE - 2; salida = verdadero; salto; caso LPP_ANALOG_INPUT : len = LPP_ANALOG_INPUT_SIZE - 2; romper; caso LPP_ANALOG_OUTPUT : len = LPP_ANALOG_OUTPUT_SIZE - 2; salida = verdadero; salto; caso LPP_LUMINOSITY : len = LPP_LUMINOSITY_SIZE - 2; romper; caso LPP_PRESENCE : len = LPP_PRESENCE_SIZE - 2; romper; caso LPP_TEMPERATURE : len = LPP_TEMPERATURE_SIZE - 2; romper; caso LPP_RELATIVE_HUMIDITY : len = LPP_RELATIVE_HUMIDITY_SIZE - 2; romper; caso LPP_ACCELEROMETER : len = LPP_ACCELEROMETER_SIZE - 2; romper; caso LPP_BAROMETRIC_PRESSURE : len = LPP_BAROMETRIC_PRESSURE_SIZE - 2; romper; caso LPP_GYROMETER : len = LPP_GYROMETER_SIZE - 2; romper; caso LPP_GPS : len = LPP_GPS_SIZE - 2; romper; defecto: len = 0; } //ist der Kanal kein Aktuator, setzen wir im Nachrichtenbuffer neu auf 1 //damit morir Daten bei nächster Gelegenheit un den MQTT Servidor gesendet werden si (!la salida de) los mensajes de[canal de].neu =1; mensajes de[canal].tipo = typ; //Restpaket = 2 weniger da Kanal und Typ gelesen atacados packetSize -= 2; #ifdef DEBUG Serial.de impresión("Daten:"); #endif //monja lesen wir die empfangenen Daten mit der ermittelten Länge para (uint8_t i=0; i<len; me++) { dat = LoRa.leer(); //für Aktuatoren merken wir uns keine Daten si (! la salida de) los mensajes de[canal de].daten[me] = dat; #ifdef DEBUG Serial.printf("-%02x",dat); #endif //Restpaket um eins vermindern packetSize --; } #ifdef DEBUG Serial.println(); #endif } //Estado aktualisieren loraCnt++; loraLast = getLocalTime(); anzeige(); } else { //Das Gerät ist nicht registriert //wir merken uns die Geräte-Id um sie für die Registriuerung anzuzeigen para (uint8_t i = 0; i<6; i++) unbekannt[me] = devid[me]; neuesGeraet = verdadero; neuesGeraetTyp = 0; //LoRa Gerät } //Teil zwei Antwort un das LoRa Gerät senden retraso(100); LoRa.beginPacket(); //am Anfang morir Geräte-Id LoRa.escribir(devid,6); // wir prüfen ob wir Salida Daten für das aktuelle LoRa-Gerät haben int devbase = devnr*16; para (int i = devbase; me<devbase+8; yo++) { //je nach typ Digital oder Analogdaten interruptor de (mensajes[i].typ) { caso LPP_DIGITAL_OUTPUT : LoRa.escribir(me-devbase); LoRa.escribir(mensajes[me].typ); LoRa.escribir(mensajes[me].daten,1); #ifdef DEBUG Serial.println("Digital Ausgang"); #endif romper; caso LPP_ANALOG_OUTPUT : LoRa.escribir(me-devbase); LoRa.escribir(mensajes[me].typ); LoRa.escribir(mensajes[me].daten,2); #ifdef DEBUG Serial.println("Analógico Ausgang"); #endif romper; } } int lstatus = LoRa.endPacket(); #ifdef DEBUG Serial.de impresión("Sendestatus = "); Serie.println(lstatus); #endif } } //Funktion zum Lesen der Konfiguration vacío leseKonfiguration(const char *fn) { uint8_t i = 0; de la Cadena de tmp; char hex[3]; si (!SPIFFS.existe(fn)) { //existiert noch nicht dann erzeugen schreibeKonfiguration(fn); de retorno; } Archivo f = SPIFFS.abrir(fn, "r"); si (!f) { Serie.println(F("ERROR:: SPIFFS Kann Konfiguration nicht öffnen")); de regreso; } , mientras que (f.disponible() && (me<MAXDEVICE)) { tmp = f.readStringUntil(','); dispositivos[me].aktiv = (tmp == "1"); tmp = f.readStringUntil(','); dispositivos[me].dienst = tmp.toInt(); tmp = f.readStringUntil(','); para (uint8_t j=0; j<6; j++){ hex[0]=tmp[j*3]; hex[1]=tmp[j*3+1]; hex[2]=0; dispositivos[i].id[j]= (byte) strtol(hex,NULL,16); } tmp = f.readStringUntil(','); dispositivos[i].nombre = tmp; tmp = f.readStringUntil(','); dispositivos[me].últimos = tmp; i++; } } //Funktion zum Lesen der Zugangsdaten vacío leseZugang(const char *fn) { uint8_t me = 0; String clave; de la Cadena de val; char hex[3]; si (!SPIFFS.existe(fn)) { //existiert noch nicht dann erzeugen schreibeZugang(fn); de retorno; } Archivo f = SPIFFS.abrir(fn, "r"); si (!f) { Serie.println(F("ERROR:: SPIFFS Kann Zugangsdaten nicht öffnen")); retorno; } mientras que (f.disponible() && (me<MAXDEVICE)) { clave = f.readStringUntil('='); val = f.readStringUntil('\n'); si (la tecla == "WLANSSID") wlanssid = val; si (la clave == "WLANPWD") wlanpwd = val; si (la clave == "MQTTUSER") mqttuser = val; si (la clave == "MQTTPWD") mqttpwd = val; si (la clave == "MQTTID") mqttid = val; } } void setup() { //gerätespeicher initialisieren para (uint8_t yo =0; me<MAXDEVICE; yo++) dispositivos[me].aktiv = 0; // Pantalla OLED initialisieren pinMode(16,SALIDA); digitalWrite(16, de BAJO); retardo(50); digitalWrite(16, ALTA); de la pantalla.de inicialización(); de la pantalla.flipScreenVertically(); pantalla.setFont(ArialMT_Plain_10); pantalla.setTextAlignment(TEXT_ALIGN_LEFT); //Serielle Schnittstelle starten Serie.de comenzar(115200); mientras que el (!de Serie); de Serie.println("Inicio"); //Sistema de Archivos Flash si (SPIFFS.comenzar(FORMAT_SPIFFS_IF_FAILED)) Serie.println(F("SPIFFS geladen")); //Konfiguration und Zugangsdaten einlesen leseKonfiguration("/konfiguration.csv"); leseZugang("/zugang.txt"); initMessageBuffer(); //SPI und LoRa initialisieren SPI.comenzar(5,19,27,18); LoRa.setPins(SS,PRIMERA,DI0); Serie.println("LoRa TRX"); si (!LoRa.comenzar(BANDA)) { de Serie.println("a Partir de LoRa ha fallado!"); mientras que (1); } LoRa.enableCrc(); Serie.println("LoRa Inicial OK!"); retraso(2000); //Ausgabe der gelesenen Zugangsdaten zur Kontrolle Serie.de impresión("SSID: ");de Serie.println(wlanssid); Serie.de impresión("Contraseña: ");de Serie.println(wlanpwd); Serie.de impresión("Usuario: ");de Serie.println(mqttuser); Serie.de impresión("Contraseña: ");de Serie.println(mqttpwd); Serie.de impresión("ID.: ");De serie.println(mqttid); //Mit dem WLAN und MQTT Servidor verbinden Serie.println("WLAN verbinden"); //wir benutzen den ESP32 ela Access Poin aber auch als Cliente im Routernetz WiFi.en modo(WIFI_AP_STA); //wir benötigen Zeiger auf den Zeichenspeicher innerhalb der Cadenas char* txtSSID = const_cast<char*>(wlanssid.c_str()); char* txtPassword = const_cast<char*>(wlanpwd.c_str()); char* txtUser = const_cast<char*>(mqttuser.c_str()); char* txtPwd = const_cast<char*>(mqttpwd.c_str()); char* txtId = const_cast<char*>(mqttid.c_str()); WiFi.begin(txtSSID, txtPassword); //Conexión en Routernetz se establece uint8_t tiempo de espera = 0; while ((WiFi.estado() != WL_CONNECTED) && (tiempo de espera<10)) { tiempo de espera++; delay(1000); } //estamos a la espera de un máximo de 10 Segundos hasta que la Conexión está //Independientemente de la Conexión en la Routernetz comenzar el Punto de acceso //permite la Configuración a través de un Navegador, es que si //en el Punto de acceso para iniciar sesión WiFi.softAP("MQTTGateway"); if (WiFi.estado() == WL_CONNECTED) { //Fue la Conexión en Routernetz con éxito, vamos a empezar MQTT a Cayenne //y sincronizar el Reloj interno con el Time-Servidor Serial.print("IP address: "); Serial.println(WiFi.localIP()); Cayenne.begin(txtUser, txtPwd, txtId); Serial.println("Cayenne Conexión"); //el Reloj con un servidor de tiempo para sincronizar configTime(GMT_OFFSET_SEC, DAYLIGHT_OFFSET_SEC, NTP_SERVER); //Hora Actual gastar Serial.println(getLocalTime()); } //Web Server inicializar el servidor.on("/", handleRoot); server.on("/conf,handleConfig); server.on("/reset",handleReset); server.begin(); Serial.println("*********************************************"); } void loop() { pantalla(); if (WiFi.estado() == WL_CONNECTED) { //LoRa Interfaz de Datos para comprobar readLoRa(); //con Cayena MQTT comunicarse con un Servidor de Cayena.loop(1); } //Web Server usar el servidor de.handleClient(); } //Datos de la Nachrichtenbuffer en el MQTT Servidor enviar CAYENNE_OUT_DEFAULT() { boolean salida = false; boolean sentData = false; #ifdef DEBUG Serial.println(getLocalTime()); Serial.println("Cayenne send"); #endif for (int i = 0; i<MAXCHANNELS; i++) { //sólo enviar Mensajes nuevos if (messages[i].nuevo == 1) { #ifdef DEBUG Serial.printf("Enviar MQTT Tipo %i\n",messages[i].tipo); #endif //dependiendo del Tipo de envío de Datos conmutador de (mensajes[i].tipo) { case LPP_DIGITAL_INPUT : Cayenne.digitalSensorWrite(i,messages[i].datos[0]); break; case LPP_DIGITAL_OUTPUT : salida = true; break; //case LPP_ANALOG_INPUT : Cayenne.virtualWrite(i), (mensajes[i].datos[0]*256 + mensajes[i].datos[1])/100,"analog_sensor",UNIT_UNDEFINED); break; break; case LPP_ANALOG_OUTPUT : salida = true; break; case LPP_LUMINOSITY : Cayenne.luxWrite(i,messages[i].datos[0]*256 + messages[i].datos[1]); break; case LPP_PRESENCE : Cayenne.digitalSensorWrite(i,messages[i].datos[0]); break; case LPP_TEMPERATURE : Cayenne.celsiusWrite(i,(messages[i].datos[0]*256 + messages[i].datos[1])/10); break; case LPP_RELATIVE_HUMIDITY : Cayenne.virtualWrite(i,messages[i].datos[0]/2,TYPE_RELATIVE_HUMIDITY,UNIT_PERCENT); break; case LPP_ACCELEROMETER : Cayenne.virtualWrite(i,(messages[i].datos[0]*256 + messages[i].datos[1])/1000,"gx","g"); break; case LPP_BAROMETRIC_PRESSURE : Cayenne.hectoPascalWrite(i,(messages[i].datos[0]*256 + messages[i].datos[1])/10); break; //case LPP_GYROMETER : len = LPP_GYROMETER_SIZE - 2; break; //case LPP_GPS : len = LPP_GPS_SIZE - 2; break; } if (!salida) { messages[i].nuevo = 0; sentData = true; } } } if (sentData) { //actualizar el Estado cayCnt++; cayLast = getLocalTime(); pantalla(); } } CAYENNE_IN_DEFAULT() { uint8_t * pData; int val; , int ch = request.canal; #ifdef DEBUG Serial.println("Cayenne recive"); Serial.printf("MQTT Datos de Canal %i = %s\n",ch,getValue.asString()); #endif conmutador de (mensajes de[ch].tipo) { case LPP_DIGITAL_OUTPUT : mensajes de[ch].datos[0] = getValue.asInt(); mensajes de[ch].nuevo = 1; break; case LPP_ANALOG_OUTPUT : val = round(getValue.asDouble()*100); messages[ch].daten[0] = val / 256; mensajes de[ch].daten[1] = val % 256; mensajes de[ch].neu = 1; romper; } CAYENNE_LOG("de Canal %u, el valor %s", solicitud de.canal, getValue.asString()); //mensaje de Proceso aquí. Si hay un conjunto de error un mensaje de error usando getValue.setError(), e.g getValue.setError("mensaje de Error"); }
Viel Spaß beim Testen.