Después de otras Pruebas, he conseguido el MQTT puerta de enlace para ampliar, que los Dispositivos con ESP Now puede ayudar. Esto permite el Uso de precios de Placas Base de ESP8266. El Alcance es entonces, sin embargo, en el Área local INALÁMBRICA a Red de área limitada. Hay una Restricción adicional. ESPNow sólo funciona con WI-fi, el Canal 1. Por tanto, es necesario el Router de la Red local (por ejemplo, de Fritz) fix en el Canal 1.
Porque yo, hasta ahora, el ESP-Now Conexión del Dispositivo de puerta de enlace para trabajar trajo, el ESP-Now Dispositivo sólo los Datos de los Sensores de la puerta de enlace entregar pero no de Comandos, desde la puerta de obtener. Sin embargo voy a tratar de resolver este Problema y en este Blog para publicar.
El Código también contiene algunas Mejoras y la corrección de un Error al Guardar la lista de Dispositivos, que luego ocurrió cuando más de un Dispositivo registrado fue.
/* 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" #include <esp_now.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 //Pin de la Pantalla de Reinicio #define DISPLRESET 16 // #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 #define MAXKANAL 8 //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 APPWD "123456789" #define APCHANNEL 0 #define DEBUG 0 const String gwversion = "1.0"; //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%\">Canales</th><th style=\"width:20%\">Nombre</th>" "<th style>"ancho:20%">Datos recientes</th><th style>"ancho:10%">Acción</th></tr>"; Const PROGMEM Char HTML_TAB_END[] = "</tabla>"; Const PROGMEM Char HTML_NEWDEVICE[] = "<div style""margin-top:20px;">%s Nombre: <tipo de entrada-"texto" estilo""ancho:200px" nombre""devname"" maxlength""20" value""> <nombre del botón >"registrar" valor "%s">Registrar</botón>></div>"; Const PROGMEM Char HTML_TAB_ZEILE[] = "<tr><td>%s</td><td>%i</td><td>%i a %i</td><td>%s<;///td><td>%s</td><td><nombre del botón>"eliminar" valor"%i">Eliminar</botón></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>Contraseña WLAN</td><td><tipo de entrada"texto" nombre"pwd" valor "%s" tamaño-50 maxlen-30/></td></tr>" "<tr><td>Cayenne Username</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><nombre del botón>"guardar" valor>Guardar</botón></td></tr>" "</table></form></body></html>"; Estructuras Zona de influencia de noticias Estructura MSG_BUF { uint8_t Tipo; uint8_t Nuevo; uint8_t Datos[10]; }; Definición del dispositivo Estructura Dispositivo { uint8_t Activo = 0; uint8_t Servicio = 0; 0-LoRa, 1-ESP-Ahora uint8_t Id[6] = {0,0,0,0}; Cadena Nombre = ""; Cadena Última = ""; }; Variable global Los datos de acceso se pueden introducir a través del servidor web Cadena wlanssid = "Lechner LAN"; Cadena wlanpwd = "Guadalquivir2711"; Cadena mqttuser = ""; Cadena mqttpwd = ""; Cadena mqttid = ""; Instancia del servidor web Web Servidor(80); Pantalla OLED SSD1306 Monitor(0x3c, 4, 15); Zona de influencia para almacenar en caché mensajes por canal MSG_BUF Mensajes[MAXCHANNELS]; Lista de dispositivos definidos Dispositivo Dispositivos[MAXDEVICE]; Estado MQTT Int mqtt_con = 0; Id de un dispositivo no registrado uint8_t Desconocido[6]; Marcar siempre true cuando se detecta un nuevo dispositivo Booleana newGeraet = Falso; Tipo de dispositivo nuevo 0-L-Ra 1 -ESPNow uint8_t newGeraetType = 0; Contadores y actividades Estado de la visualización uint32_t loraCnt = 0; Número de mensajes de LoRa recibidos Cadena loraLast = ""; Fecha y hora del último mensaje recibido de LoRa uint32_t nowCnt = 0; Número de mensajes ESP Now recibidos Cadena nowLast = ""; Fecha y hora del último mensaje recibido de LoRa uint32_t cayCnt = 0; Número de mensajes MQTT enviados Cadena cayLast = ""; Fecha y hora del último mensaje MQTT enviado La función devuelve la fecha y la hora en el formato aaaa-mm-dd hh:mm:ss como una cadena Cadena getLocalTime() { Char sttime[20] = ""; Estructura Tm timeinfo; Si (Wifi.Estado() == WL_CONNECTED) { Si(!getLocalTime(&timeinfo)){ Serial.println("No se pudo obtener tiempo"); devolución sttime; } Strftime(sttime, Sizeof(sttime), "%Y-%m-%d %H:%M:%S", &timeinfo); } devolución sttime; } Funktion liefert eine 6-Byte Geräte-Id im format xx:xx:xx:xx:xx:xx als String Cadena Getid(uint8_t Id[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 ; } devolución stid; } La función devuelve parte de un búfer de datos en formato xx, xx, xx .... como cadena Cadena Getdata(uint8_t Buf[], uint8_t Empezar, uint8_t Final) { Cadena stdata; Char Tmp[4]; Sprintf(Tmp,"%02x",Buf[Empezar]); stdata=Tmp; Para (uint8_t J = Empezar+1; J<Final; J++) { Sprintf(Tmp,",%02x",Buf[J]); stdata = stdata += Tmp ; } devolución stdata; } prepara el búfer de mensajes establece todos los mensajes en hecho Vacío initMessageBuffer() { Para (Int Ⅰ. = 0;Ⅰ.<MAXCHANNELS;Ⅰ.++) { Mensajes[Ⅰ.].Nuevo = 0; } } Función para guardar la configuración Vacío writeConfiguration(Const Char *Fn) { Archivo Q = SPIFFS.Abierto(Fn, FILE_WRITE); Si (!Q) { Serial.println(Q("ERROR: SPIFFS No se puede guardar la configuración")); devolución; } Para (uint8_t Ⅰ. = 0; Ⅰ.<MAXDEVICE; Ⅰ.++) { Q.Impresión(Dispositivos[Ⅰ.].Activo);Q.Impresión('n'); Si (Dispositivos[Ⅰ.].Activo) { Q.Impresión(Dispositivos[Ⅰ.].Servicio);Q.Impresión('n'); Q.Impresión(Getid(Dispositivos[Ⅰ.].Id));Q.Impresión('n'); Q.Impresión(Dispositivos[Ⅰ.].Nombre);Q.Impresión('n'); Q.Impresión(Dispositivos[Ⅰ.].Última);Q.Impresión('n'); } Más { Q.Printf("0-n00:00:00:00:00:00-n-n-n"); } } } Función para almacenar los datos de acceso Vacío writingAccess(Const Char *Fn) { Archivo Q = SPIFFS.Abierto(Fn, FILE_WRITE); Si (!Q) { Serial.println(Q("ERROR: SPIFFS No se pueden almacenar credenciales")); devolución; } Q.Impresión("WLANSSID");Q.Impresión(wlanssid);Q.Impresión('n'); Q.Impresión("WLANPWD");Q.Impresión(wlanpwd);Q.Impresión('n'); Q.Impresión("MQTTUSER");Q.Impresión(mqttuser);Q.Impresión('n'); Q.Impresión("MQTTPWD");Q.Impresión(mqttpwd);Q.Impresión('n'); Q.Impresión("MQTTID");Q.Impresión(mqttid);Q.Impresión('n'); } Función para leer la configuración Vacío readConfiguration(Const Char *Fn) { uint8_t Ⅰ. = 0; Cadena Tmp; Char Hexagonal[3]; Si (!SPIFFS.Existe(Fn)) { todavía no existe y luego generar writeConfiguration(Fn); devolución; } Archivo Q = SPIFFS.Abierto(Fn, "R"); Si (!Q) { Serial.println(Q("ERROR:: SPIFFS No se puede abrir la configuración")); devolución; } #ifdef Depuración Serial.println("Leer lista de dispositivos"); #endif Mientras (Q.Disponible() && (Ⅰ.<MAXDEVICE)) { Serial.Printf("Leer dispositivo %i",Ⅰ.); Tmp = Q.readStringUntil('n'); Dispositivos[Ⅰ.].Activo = (Tmp == "1"); Tmp = Q.readStringUntil('n'); Dispositivos[Ⅰ.].Servicio = Tmp.toInt(); Tmp = Q.readStringUntil('n'); Para (uint8_t J=0; J<6; J++){ Hexagonal[0]=Tmp[J*3]; Hexagonal[1]=Tmp[J*3+1]; Hexagonal[2]=0; Dispositivos[Ⅰ.].Id[J]= (Byte) strtol(Hexagonal,Null,16); } Tmp = Q.readStringUntil('n'); Dispositivos[Ⅰ.].Nombre = Tmp; Tmp = Q.readStringUntil('n'); Dispositivos[Ⅰ.].Última = Tmp; #ifdef Depuración Serial.Impresión("Dispositivo"+Getid(Dispositivos[Ⅰ.].Id)+ " Nombre " + Dispositivos[Ⅰ.].Nombre); Serial.Printf(" Servicio %i Active %i'r'n',Dispositivos[Ⅰ.].Servicio,Dispositivos[Ⅰ.].Activo); #endif Ⅰ.++; } } Función para leer los datos de acceso Vacío readAccess(Const Char *Fn) { uint8_t Ⅰ. = 0; Cadena Clave; Cadena Val; Char Hexagonal[3]; Si (!SPIFFS.Existe(Fn)) { todavía no existe y luego generar writingAccess(Fn); devolución; } Archivo Q = SPIFFS.Abierto(Fn, "R"); Si (!Q) { Serial.println(Q("ERROR:: SPIFFS No se pueden abrir las credenciales")); devolución; } Mientras (Q.Disponible() && (Ⅰ.<MAXDEVICE)) { Clave = Q.readStringUntil('='); Val = Q.readStringUntil('n'); Si (Clave == "WLANSSID") wlanssid = Val; Si (Clave == "WLANPWD") wlanpwd = Val; Si (Clave == "MQTTUSER") mqttuser = Val; Si (Clave == "MQTTPWD") mqttpwd = Val; Si (Clave == "MQTTID") mqttid = Val; } } Función para registrar un nuevo dispositivo Vacío geraetRegister() { uint8_t Ⅰ. = 0; búsqueda de entrada libre Mientras ((Ⅰ.<MAXDEVICE) && Dispositivos[Ⅰ.].Activo) Ⅰ.++; no hay nueva entrada no hacemos nada Si (Ⅰ. < MAXDEVICE) { de lo contrario, registrar el nombre de geraet - nombre introducido o desconocido si no se ha introducido ninguno Si (Servidor.hasArg("devname")) { Dispositivos[Ⅰ.].Nombre = Servidor.Malo("devname"); } Más { Dispositivos[Ⅰ.].Nombre = "desconocido"; } Para (uint8_t J = 0; J<6; J++) Dispositivos[Ⅰ.].Id[J]=Desconocido[J]; Dispositivos[Ⅰ.].Activo = 1; Dispositivos[Ⅰ.].Servicio= newGeraetType; Dispositivos[Ⅰ.].Última = ""; writeConfiguration("/configuration.csv"); newGeraet = Falso; } } El servidor web muestra la página de configuración Vacío handleConfig(){ Char htmlbuf[1024]; Booleana Reiniciar = Falso; Int Índice; ¿Se ha pulsado el botón de memoria? Si (Servidor.hasArg("Guardar")) { Datos de la solicitud POST wlanssid = Servidor.Malo("ssid"); si el SSID contiene un espacio, recibiremos un "+" esto tiene que ser cambiado de nuevo en un espacio para el registro wlanssid.Reemplazar("+"," "); wlanpwd = Servidor.Malo("Buena"); mqttuser = Servidor.Malo("mquser"); mqttpwd = Servidor.Malo("Mqpwd"); mqttid = Servidor.Malo("mqid"); Serial.println("Nueva configuración:"); Serial.Impresión("SSID: ");Serial.println(wlanssid); Serial.Impresión("Contraseña: ");Serial.println(wlanpwd); Serial.Impresión("Usuario: ");Serial.println(mqttuser); Serial.Impresión("Contraseña: ");Serial.println(mqttpwd); Serial.Impresión("ID: ");Serial.println(mqttid); Guarde la nueva configuración en SPIFFS writingAccess("/access.txt"); recordamos que la conexión WiFi necesita ser reiniciada pero primero el servidor web tiene que entregar la página HTML Reiniciar = Verdad; } Salida de la página de configuración formamos punteros a la memoria interna de las cadenas de acceso utilizarlos para sprintf e iniciar la conexión Wi-Fi y Cayenne 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()); Enviar la página HTML actual al navegador Servidor.setContentLength(CONTENT_LENGTH_UNKNOWN); Rúbrica Servidor.Enviar(200, "texto/html",HTML_HEADER); Servidor.sendContent(HTML_HEADER_END); El formulario con los campos de entrada se rellena con los valores actuales Sprintf(htmlbuf,HTML_CONFIG,txtSSID,txtPassword,txtUser,txtPwd,txtId); y enviado a la Browsewr Servidor.sendContent(htmlbuf); Servidor.sendContent(HTML_END); Si (Reiniciar) { ¿El indicador de reinicio establecido debe desconectar la conexión WiFi y volver a conectar para ser construido mqtt_con = 0; Serial.println("Reiniciar"); uint8_t Timeout = 0; Serial.println("Desconectar"); Wifi.Desconecte(); Mientras ((Wifi.Estado() == WL_CONNECTED) && (Timeout < 10)) { Retraso(1000); Timeout++; } Serial.println("Reconectar"); Wifi.Comenzar(txtSSID,txtPassword); Mientras ((Wifi.Estado() != WL_CONNECTED) && (Timeout < 10)) { Retraso(1000); Timeout++; } Serial.Impresión("Dirección IP: "); Serial.println(Wifi.localIP()); Si (Wifi.Estado() == WL_CONNECTED) { el Neustrart tuvo éxito, la conexión con Cayenne también debe ser reconstruida. Si ((mqttuser != "")&&(mqttpwd != "") && (mqttid != "")) { Serial.println("Conectando Cayenne"); Cayena.Comenzar(txtUser, txtPwd, txtId); mqtt_con = 1; } Sincronizar reloj con el servidor de tiempo configTime(GMT_OFFSET_SEC, DAYLIGHT_OFFSET_SEC, NTP_SERVER); Tiempo de corriente de salida Serial.println(getLocalTime()); } } } El servidor web ha consultado la página de restablecimiento Vacío handleReset() { restablecemos los datos de acceso wlanssid= ""; wlanpwd = ""; mqttuser = ""; mqttpwd=""; mqttid=""; y mostrar los datos de configuración sólo cuando el botón de la página de configuración es guardar se hace clic, los datos de acceso son también se suprimen en SPIFFS. handleConfig(); } El servidor web ha consultado la página con la lista de dispositivos Vacío handleWLANRequest(){ Char htmlbuf[512]; Char tmp1[20]; Char tmp2[20]; Char tmp3[20]; Int Índice; fue el botón de borrar se hizo clic ? Si (Servidor.hasArg("eliminar")) { Índice = Servidor.Malo("eliminar").toInt(); #ifdef DEGUG Serial.Printf("Eliminar dispositivo %i ",Índice); Serial.println(Dispositivos[Índice].Nombre); #endif Dispositivos[Índice].Activo=0; writeConfiguration("/configuration.csv"); } ¿Se ha hecho clic en el botón Registrar? Si (Servidor.hasArg("registro")) { geraetRegister(); Serial.println("La configuración se guarda"); writeConfiguration("/configuration.csv"); } Enviar la página HTML actual al navegador Servidor.setContentLength(CONTENT_LENGTH_UNKNOWN); Rúbrica Servidor.Enviar(200, "texto/html",HTML_HEADER); Dirección IP para el script de recarga Wifi.localIP().Tostring().Tochararray(tmp1,20); Sprintf(htmlbuf,HTML_SCRIPT,tmp1); Servidor.sendContent(htmlbuf); Servidor.sendContent(HTML_HEADER_END); Formulario comienzo Servidor.sendContent("<div class>"title">MQTT - Gateway</div><form method>"); Tabla de dispositivos activos Servidor.sendContent(HTML_TAB_GERAETE); Para (uint8_t Ⅰ. = 0; Ⅰ.<MAXDEVICE; Ⅰ.++) { Si (Dispositivos[Ⅰ.].Activo == 1) { Getid(Dispositivos[Ⅰ.].Id).Tochararray(tmp1,20); Dispositivos[Ⅰ.].Nombre.Tochararray(tmp2,20); Dispositivos[Ⅰ.].Última.Tochararray(tmp3,20); Sprintf(htmlbuf,HTML_TAB_ZEILE,tmp1,Ⅰ.,Ⅰ.*8,Ⅰ.*8+7,tmp2,tmp3,Ⅰ.); Servidor.sendContent(htmlbuf); } } Servidor.sendContent(HTML_TAB_END); Si se encuentra un nuevo dispositivo, su ID y un campo de entrada para el nombre de la y se muestra un botón para registrar el nuevo dispositivo Si (newGeraet) { Getid(Desconocido).Tochararray(tmp1,20); Sprintf(htmlbuf,HTML_NEWDEVICE,tmp1,tmp1); Servidor.sendContent(htmlbuf); } Servidor.sendContent(HTML_END_RELOAD); } Función de servicio de servidor web para el directorio raíz Vacío handleRoot() { Si (Wifi.Estado() != WL_CONNECTED) { si no tenemos una conexión a la red del router se muestra la página de configuración para que se puedan introducir los datos de acceso handleConfig(); } Más { handleWLANRequest(); } } Función para encontrar un dispositivo en la lista de dispositivos Devolver índice de dispositivo o -1 si no se ha encontrado Int findDevice(uint8_t Dev[6]) { uint8_t J; uint8_t Ⅰ. = 0; Booleana Encontrado = Falso; Jue { J = 0; Si (Dispositivos[Ⅰ.].Activo == 0) { Ⅰ.++; } Más { Mientras ((J < 6) && (Dev[J] == Dispositivos[Ⅰ.].Id[J])) {J++;} Encontrado = (J == 6); Si (!Encontrado) Ⅰ.++; } } Mientras ((Ⅰ.<MAXDEVICE) && (!Encontrado)); Si (Encontrado) {devolución Ⅰ.;} Más {devolución -1;} } Función para mostrar el estado en la pantalla OLED Vacío Monitor() { Monitor.Claro(); Monitor.Lazo(0,0,"Puerta de enlace MQTT"+gwversion); Monitor.Lazo(0,10,getLocalTime()); Monitor.Lazo(0,20,Wifi.localIP().Tostring()); Monitor.Lazo(0,34,"MQTT: "); Monitor.Lazo(60,34,Cadena(cayCnt)); Monitor.Lazo(0,44,"LoRa: "); Monitor.Lazo(60,44,Cadena(loraCnt)); Monitor.Lazo(0,54,"AHORA: "); Monitor.Lazo(60,54,Cadena(nowCnt)); Monitor.Monitor(); } Almacenar los datos recibidos en el búfer de mensajes Devolver el valor del número de dispositivo o -1 si no está registrado uint8_t processData(uint8_t Buf[], Int buflen) { Int devnr; Int Índice; uint8_t Daniel[6]; uint8_t Canal; uint8_t Tipo; uint8_t Len; uint8_t Ⅰ.; Booleana Salida; Índice = 0; Mientras ((índice < 6) && (índice < buflen)) { devid[índice] = buf[índice]; índice++; } #ifdef DEBUG Serial.print("Dispositivos Id = ");Serial.println(getId(devid)); #endif //comprobar si el Dispositivo está registrado devnr = findDevice(devid); if (devnr >= 0) { #ifdef DEBUG Serial.println(getLocalTime()); Serial.print("Número de Dispositivos = ");Serial.println(devnr); #endif //si sí debemos poner la marca de tiempo de la última Notificación y //leer los Datos de dispositivos de[devnr].carga = getLocalTime(); //schreibeKonfiguration("/konfiguration.csv"); //nun morir Daten lesen mientras que (el índice de < buflen) { canal = buf[índice++]+devnr*MAXKANAL; si (el índice de == buflen) romper; typ = buf[índice++]; de 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].typ = tipo; i = 0; , mientras que ((yo<len) && (índice < buflen)) { si (!la salida de) los mensajes de[canal de].daten[me] = buf[índice]; i++; índice++; } #ifdef DEBUG Serial.printf("Kanal %i I %i Daten: ",el canal de,tipo);de Serie.println(getData(mensajes de[canal de].daten,0,len)); #endif } return devnr; } más { para (uint8_t i = 0; i<6; i++) unbekannt[me] = devid[me]; neuesGeraet = verdadero; retorno -1; } } uint8_t antwortBilden(uint8_t buf[], uint8_t devnr) { // wir prüfen ob wir Salida Daten für das aktuelle LoRa-Gerät haben int índice = 6; //erste sechs bytes pecado morir Geräte Id int devbase = devnr*MAXKANAL; #ifdef DEBUG Serial.printf("Aktivatoren für Gerät %i Kanal %i bis %i\r\n",devnr,devbase,devbase+8); #endif para (int i = devbase; me<devbase+8; i++) { //je nach typ Digital oder Analogdaten interruptor de (mensajes[i].typ) { caso LPP_DIGITAL_OUTPUT : buf[índice++]= i-devbase; buf[índice de++]=mensajes[i].typ; buf[índice de++]=mensajes[me].daten[0]; #ifdef DEBUG Serial.println("Digital Ausgang"); #endif romper; caso LPP_ANALOG_OUTPUT : buf[índice++]= i-devbase; buf[índice de++]=mensajes[i].typ; buf[índice de++]=mensajes[me].daten[0]; buf[índice de++]=mensajes[me].daten[1]; #ifdef DEBUG Serial.println("Analógico Ausgang"); #endif romper; } } regresar índice; } //Eine que el mensaje von einem LoRa Cliente verarbeiten vacío readLoRa() { uint8_t buf[256]; int ix; int devnr; uint8_t len; uint8_t byt; //Daten holen cae vorhanden int packetSize = LoRa.parsePacket(); //haben wir Daten erhalten ? si (packetSize > 0) { #ifdef DEBUG Serial.printf("%i Bytes von LoRa empfangen\r\n",packetSize); #endif mientras ((ix < packetSize) && (ix < 256)) { byt= LoRa.leer(); // Serial.printf("%2x ",byt); buf[ix++] = byt; } // Serial.println(); #ifdef DEBUG Serial.println(getData(buf,0,packetSize)); #endif devnr = processData(buf, packetSize); si (devnr >=0) { //Estado aktualisieren loraCnt++; loraLast = getLocalTime(); } más { neuesGeraetTyp = 0; //LoRa Gerät } //Teil zwei Antwort un das LoRa Gerät senden //delay(500); //en la guarida ertsen sechs bytes des Búferes steht ya morir GeräteId len = 6; //caídas wir ein registriertes Gerät haben senden wir auch Daten mit si (devnr >= 0) len = antwortBilden(buf, devnr); #ifdef DEBUG Serial.printf("Sende un Gerät %i %i bytes\r\n",devnr,len); Serie.println(getData(buf,0,len)); #endif LoRa.beginPacket(); LoRa.escribir(buf,len); int lstatus = LoRa.endPacket(); #ifdef DEBUG Serial.print("Estado = "); Serial.println(lstatus); #endif } } // callback para ESP Now void readESPNow(const uint8_t *mac_addr, const uint8_t *r_data, int data_len) { uint8_t data[70]; uint8_t devnr; uint8_t len; #ifdef DEBUG Serial.printf("%i Bytes de ESP-Now recibir\r\n",data_len); #endif memcpy(&data, r_data, sizeof(data)); devnr = processData(data,data_len); if (devnr >=0) { //actualizar el Estado nowCnt++; nowLast = getLocalTime(); } else { neuesGeraetTyp = 1; //ESP Now Dispositivo } de retardo(100); //Parte dos en Respuesta al ESP-Now Dispositivo para enviar //en el primer seis bytes del Buffer ya está el Deviceid len = 6; //si tenemos un Dispositivo registrado estaremos enviando Datos con if (devnr >= 0) len = antwortBilden(data, devnr); #ifdef DEBUG Serial.printf("Enviar a Dispositivo, %i %i bytes\r\n",devnr,len); Serial.println(getData(data,0,len)); #endif esp_now_send(data, data, len); #ifdef DEBUG Serial.println("Final"); #endif } void setup() { //inicializar la memoria del dispositivo for (uint8_t i =0; i<MAXDEVICE; i++) devices[i].activo = 0; // Pantalla OLED de inicializar pinMode(DISPLRESET,SALIDA); digitalWrite(DISPLRESET, LOW); delay(50); digitalWrite(DISPLRESET, ALTA); pantalla.init(); display.flipScreenVertically(); pantalla.setFont(ArialMT_Plain_10); pantalla.setTextAlignment(TEXT_ALIGN_LEFT); //Serie iniciar un puerto Serial.begin(115200); while (!Serial); Serial.println("Inicio"); //Flash File system if (SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED)) Serial.println(F("SPIFFS carga")); //Configuración y los datos de Acceso de lectura para leseKonfiguration("/configuración.csv"); leseZugang("/zugang.txt"); initMessageBuffer(); //SPI y LoRa inicializar SPI.begin(5,19,27,18); LoRa.setPins(SS,RST,DI0); Serial.println("LoRa TRX"); if (!LoRa.begin(BANDA)) { Serial.println("Starting LoRa failed!"); while (1); } LoRa.enableCrc(); Serial.println("LoRa Initial OK!"); delay(2000); //Salida de los datos de Acceso para el Control 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); //Con el WI-fi y MQTT conectarse a un Servidor Serial.println("red INALÁMBRICA"); //usamos el ESP32 como Access Poin pero también como Cliente en Routernetz WiFi.moda(WIFI_AP_STA); //necesitamos un Puntero al Zeichenspeicher dentro de la Cadena 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()); //Independientemente de la Conexión en la Routernetz comenzar el Punto de acceso //permite la Configuración a través de un Navegador, si ese es el //en el Punto de acceso para iniciar sesión WiFi.softAP("MQTTGateway",APPWD,APCHANNEL,0); //Conexión en Routernetz de conexión WiFi.begin(txtSSID, txtPassword); 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á 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()); if ((mqttid != "") && (mqttuser != "") && (mqttpwd != "")) { Serial.println("State MQTT"); Cayenne.begin(txtUser, txtPwd, txtId); Serial.println("Cayenne Conexión"); mqtt_con = 1; } //Uhr mit Zeitserver synchronisieren configTime(GMT_OFFSET_SEC, DAYLIGHT_OFFSET_SEC, NTP_SERVER); //Aktuelle Uhrzeit ausgeben Serie.println(getLocalTime()); } //Servidor Web initialisieren servidor.en("/", handleRoot); servidor.en("/conf",handleConfig); servidor.en("/reset",handleReset); servidor de.comenzar(); si (esp_now_init() == ESP_OK) Serie.println("ESP-Ahora initialisiert!"); esp_now_register_recv_cb(readESPNow); Serie.println("*********************************************"); } void loop() { anzeige(); si (WiFi.de estado() == WL_CONNECTED) { //LoRa Interfaz auf Daten prüfen readLoRa(); //mit Cayenne MQTT Servidor kommunizieren si (mqtt_con == 1) Cayenne.bucle(1); } //Servidor Web bedienen servidor.handleClient(); retraso(100); } //Daten aus dem Nachrichtenbuffer un den MQTT Servidor senden CAYENNE_OUT_DEFAULT() { booleano salida = falsa; booleano sentData = falso; float val; #ifdef DEBUG Serial.println(getLocalTime()); Serie.println("Cayenne enviar"); #endif para (int i = 0; i<MAXCHANNELS; i++) { //nur neue Nachrichten senden si (los mensajes[que me].neu == 1) { #ifdef DEBUG Serial.printf("Sende MQTT Kanal %i Typ %i\n",i,de los mensajes de la[i].typ); #endif //je nach Typ Daten senden interruptor de (mensajes[i].typ) { caso LPP_DIGITAL_INPUT : Cayenne.digitalSensorWrite(me,los mensajes[que me].daten[0]); romper; caso LPP_DIGITAL_OUTPUT : salida = verdadero; salto; caso LPP_ANALOG_INPUT : val = (mensajes[me].daten[0]*256 + mensajes[me].daten[1]);de Cayena.virtualWrite(me,val/100,"analog_sensor",UNIT_UNDEFINED); romper; romper; caso LPP_ANALOG_OUTPUT : salida = verdadero; salto; caso LPP_LUMINOSITY : Cayenne.luxWrite(me,los mensajes[que me].daten[0]*256 + mensajes[me].daten[1]); romper; caso LPP_PRESENCE : Cayenne.digitalSensorWrite(me,los mensajes[que me].daten[0]); romper; caso LPP_TEMPERATURE : val = (mensajes[me].daten[0]*256 + mensajes[me].daten[1]); de Cayena.celsiusWrite(me,val/10); romper; caso LPP_RELATIVE_HUMIDITY : val=mensajes[me].daten[0];de pimienta de Cayena.virtualWrite(me,val/2,TYPE_RELATIVE_HUMIDITY,UNIT_PERCENT); romper; caso LPP_ACCELEROMETER : val = (mensajes[me].daten[0]*256 + mensajes[me].daten[1]);de Cayena.virtualWrite(me,val/1000,"gx","g"); romper; caso LPP_BAROMETRIC_PRESSURE : val = (mensajes[me].daten[0]*256 + mensajes[me].daten[1]);de Cayena.hectoPascalWrite(me,val/10); break; //caso LPP_GYROMETER : len = LPP_GYROMETER_SIZE - 2; break; //caso LPP_GPS : len = LPP_GPS_SIZE - 2; break; } si (!la salida de) { los mensajes de[i].neu = 0; sentData = verdadero; } } } si (sentData) { //Estado aktualisieren cayCnt++; cayLast = getLocalTime(); } } CAYENNE_IN_DEFAULT() { uint8_t * pData; int val; int ch = solicitud de.canal de; #ifdef DEBUG Serial.println("Cayenne de recepción"); de Serie.printf("MQTT Daten für Kanal %i = %s\n",ch,getValue.asString()); #endif interruptor de (mensajes de[ch].typ) { caso LPP_DIGITAL_OUTPUT : mensajes de[ch].daten[0] = getValue.asInt(); mensajes de[ch].neu = 1; romper; caso LPP_ANALOG_OUTPUT : val = ronda(getValue.asDouble()*100); mensajes de[ch].daten[0] = val / 256; mensajes de[ch].daten[1] = val % 256; mensajes de[ch].neu = 1; romper; } CAYENNE_LOG("de Canal %u, %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"); }
Das Pantalla zeigt jetzt auch eine Versionsnummer una. Weiter Informationen zu diesem de la Puerta de enlace de findet Ihr en den anderen Teilen dieser Serie.
2 comentarios
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?