Trabajando con el Tablero de Cayenne - Gateway mejorado con ESP-Now (Parte 6)

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>&nbsp;</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.

 

Software básico

2 comentarios

Roland

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

Roland

Jetzt spiele ich mich mit den Projekten von 1 bis 7
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!

Wie in der Beschreibung erwähnt startet aber der Access-Point „MQTTGateway“ nicht.
Was mache ich da falsch?

Deja un comentario

Todos los comentarios son moderados antes de ser publicados

Artículos de blog

  1. Ahora instalamos el esp32 a través de la administración.
  2. Lüftersteuerung Raspberry Pi
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1
  4. ESP32 - das Multitalent
  5. Transporte Aéreo - programación de ESP mediante redes locales inalámbricas