Arbeiten mit dem Cayenne Dashboard - LoRa zu MQTT Gateway (Teil 3) - AZ-Delivery

Después de algunos intentos fallidos de construir una puerta de enlace universal LoRa con el ESP32, se creó la siguiente puerta de enlace patentada, que permite que los dispositivos IoT basados ​​en LoRa se conecten al Tablero Cayenne a través de MQTT. En una versión ampliada, la puerta de enlace también administrará dispositivos IoT basados ​​en el protocolo ESP-Now.

Solo necesitamos uno para la puerta de enlace ESP32 con pantalla LoRa y OLEDNo se requieren más componentes. La fuente de alimentación se puede hacer con cualquier fuente de alimentación USB.

Descripción de la función:

La puerta de enlace puede administrar 32 dispositivos con hasta 8 canales cada uno. La transmisión de datos es asíncrona. Cuando la puerta de enlace recibe un paquete de datos LoRa, los primeros seis bytes se interpretan como ID del dispositivo (generalmente la dirección MAC). La puerta de enlace comprueba en una lista de dispositivos si este dispositivo ya está registrado. Si este no es el caso, la ID del dispositivo se guarda y se muestra a través de la interfaz web para el registro.

Si el dispositivo ya está registrado, los datos se leen y se guardan en un búfer de mensajes para cada canal. El número de canal se determina a partir del número de dispositivo (índice en la lista de dispositivos) * 8 + número de canal de los datos recibidos. El dispositivo 0 tiene los canales 0 a 7, el dispositivo 1 tiene los canales 8 a 15, etc.

Un registro de datos comienza con un byte para el número de canal seguido de un byte con el tipo y luego de 1 a 6 bytes de datos según el tipo. Después de que todos los datos se hayan guardado en el búfer de mensajes y se hayan marcado como nuevos, el paquete de respuesta se agrupa en el dispositivo Lora. Comienza de nuevo con los seis bytes de ID del dispositivo. Los canales para este dispositivo se verifican en el búfer de mensajes para determinar si hay un paquete de datos salientes de Cayenne al dispositivo que está marcado con Nuevo. Si se encuentra dicho paquete de datos, se agrega al paquete de respuesta, y el número de canal relativo 0 a 7 se usa nuevamente. Como último paso, el paquete de respuesta se transfiere al dispositivo LoRa.

La función Cayenne.loop (1) se hace cargo de la comunicación con el servidor IoT. En la función de devolución de llamada CAYENNE_OUT_DEFAULT (), se buscan todos los canales en el búfer de mensajes que están marcados con Nuevo y que contienen un paquete de datos de entrada para Cayenne del tipo. Estos paquetes ahora se convierten según el tipo y se envían al servidor IoT. Después de una transferencia exitosa, la nueva bandera se reinicia.

Se llama a una segunda función de devolución de llamada CAYENNE_IN_DEFAULT () siempre que haya datos de Cayenne para un canal de acción. Los datos del servidor IoT se convierten según el tipo y se almacenan en el búfer de mensajes. Están marcados con Nuevo para que se envíen al dispositivo la próxima vez que LoRa se comunique con el paquete de respuesta.

Pantalla:

Además del nombre, la pantalla muestra la fecha y hora actuales. Debajo de eso la dirección IP.
La línea MQTT: muestra el número de transferencias exitosas al servidor IoT, LoRa las transferencias exitosas a dispositivos LoRa y AHORA el número de transferencias exitosas a dispositivos ESP-Now. Actualmente, este último siempre es 0 porque esta función aún no se ha implementado.

Lista de dispositivos y registro:

La lista de dispositivos se guarda como un archivo CSV en el sistema de archivos flash (SPIFFS) para que se conserve incluso si no hay una fuente de alimentación. Esta lista se puede mantener a través del servidor web integrado en la puerta de enlace. Se pueden eliminar dispositivos y registrar nuevos dispositivos.

Paquetes de datos:

Para el tipo, los códigos están de acuerdo con las pautas de IPSO Alliance Smart Objects, pero se resta 3200.

Tipo IPSO TypNr. Bytes Disolución
Entrada digital 3200 0 1 1
Salida digital 3201 1 1 1
Entrada analógica 3202 2 2 0.01 con signo
Salida analógica 3203 3 2 0.01 con signo
Sensor de iluminación 3301 101 2 1 lux
Sensor de presencia 3302 102 1 1
Sensor de temperatura 3303 103 2 0.1°C con el signo
Sensor húmedo 3304 104 1 0.5%
Beschleunigungs el sensor 3313 113 6 0.001 gr con el signo
para eje X, Y y Z
Presión el sensor 3315 115 2 0.1 hPa
Gyrometer 3334 134 6 0.01% / s con el signo
para eje X, Y y Z
GPS Posición 3336 136 9 Grado de latitud 0.0001 °
con el signo
Grado de longitud 0.0001 °
con el signo
Altura 0.01 m
con el signo

 

Sketch:

El registro de la esclusa en Cayenne sucede a la manera misma como en la parte 1 este Blog la serie describían. Luego los datos de acceso tienen que ser dados en el sketch (la señalización amarilla) igualmente los datos de acceso para anunciar en WLAN local. Cayenne Dashboard no indicará ningunos Widgets, dado que todavía ningún utensilio era conectado con la esclusa.

Board para Arduino IDE = TTGO LoRa32-OLED V1

/* La esclusa MQTT forma una interfaz entre LoRa a utensilios y respectivamente utensilios ESP Nowe 
 * y Cayenne MQTT Dashboards. Esto corre en ESP32 con LoRa y display OLED
 * La configuración sucede del navegador
 */
#include <SPI.h>
#include <LoRa.h>
#include "SSD1306.h"
#include<Arduino.h>
#include <CayenneMQTTESP32.h>
#include <CayenneLPP.h>
#include <WiFi.h>
#include <Servidor de Web.h>
#include <time.h>
#include "FS.h"
#include "SPIFFS.h"


//Recibimos los datos para este ajuste de Cayenne Dashboard
#define MQTT_USER ""
#define MQTT_PASSWORD ""
#define MQTT_CLIENTID ""

//Datos de acceso para WLAN local
#define WIFI_SSID ""
#define WIFI_PASSWORD ""

//Servidor NTP a la sincronización de tiempo
#define NTP_SERVER "de.pool.ntp.org"
#define GMT_OFFSET_SEC 3600
#define DAYLIGHT_OFFSET_SEC 0

//Pins para LoRa el chip
#define SS      18
#define RST     14
#define DI0     26
//Frecuencia para LoRa el chip
#define CINTA    433175000

//
#define MAXCHANNELS 256 //número máximo de los canales administrados
#define MAXDEVICE 32 //el número máximo de los utensilios administrados MAXCHANNELS/MAXDEVICE = 8 revela el número máximo canales por utensilio

//El formato Flash el sistema de file si aún no ocurren
#define FORMAT_SPIFFS_IF_FAILED true

#define DEBUG 1

//Piedras de construcción para el servidor de Web
const char HTML_HEADER[] =
"<!DOCTYPE HTML>"
"<html>"
"<head>"
"<meta el nombre = \"viewport \" content = \"width = device-width, inicial scale = 1.0, maximum-scale = 1.0, user-scalable=0> \">"
"<meta http-equiv = \"content-type \" content = \"el texto / html; charset=UTF-8 \">"
"<title>MQTT Gateway</title>"
"<script language = \"javascript \">"
"function reload () {"
"document.location = \"http://%s \";}"
"</script>"
"<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 px solid black;}"
".titel {font-size:18pt;font-weight:bold;text-align:center;}"
"</style>"
"</head>"
"<body><div da estilo ='margin-left:30px; '>";
const char HTML_END[] =
"</div><script language = \"javascript \">setTimeout (reload, 10000) ;</script></body>"
"</html>";
const char HTML_TAB_GERAETE[] =
"<table da estilo = \"width:100 % \"><tr><th da estilo = \"width:20 % \">ID</th><th da estilo = \"width:10 % \">Nr.</th>"
"<th da estilo = \"width:20 % \">Kanäle</th><th da estilo = \"width:20 % \">Name</th>"
"<th da estilo = \"width:20 % \">Letzte Daten</th><th da estilo = \"width:10 % \">Aktion</th></tr>";
const char HTML_TAB_END[] =
"</table>";
const char HTML_NEWDEVICE[] =
"<div da estilo = \"margin-top:20px; \">%s el nombre: <input type = \"el texto \"" el nombre = \"devname \" maxlength = \"da estilo = \"width:200px \a 10 \" value = \"\" > <button el nombre = \"registra \" value = \"% s \">Registrieren</button></div>";
const char HTML_TAB_ZEILE[] =
"<tr><td>%s</td><td>%i</td><td>%i hasta %i</td><td>%s</td><td>%s</td><td><button el nombre = \"delete \" value = \"% i \">Löschen</button></td></tr>";

//Estructuras de datos
//Noticias el tope
struct MSG_BUF {   uint8_t tipo;   uint8_t de nuevo;   uint8_t datos[10];
};

//Definición de utensilios
struct DEVICE {   uint8_t activamente;   uint8_t sirves; //0=LoRa, 1=ESP-Now   uint8_t id[6];   Bramante nombre;   Bramante leía;
};

//Variables globales
//Servidor de Web la instancia
Servidor de Web servidor(80);

//Display OLED
SSD1306  display(0x3c, 4, 15);

//Tope al interalmacén de las noticias para canal
MSG_BUF mensajes[MAXCHANNELS];

//Lista de los utensilios definidos
DEVICE devices[MAXDEVICE];

//Id de un utensilio no registrado
uint8_t desconocido[6];
//Flag siempre luego verdadero cuando un nuevo utensilio era descubierto
boolean un nuevo utensilio = false;
//Tipo del nuevo utensilio 0=LöRa 1 =ESPNow
uint8_t neuesGeraetTyp = 0;

//Contador y Aktivitaets el estatus para el display
uint32_t loraCnt = 0; //Número de LoRa recibidos noticias
Bramante loraLast = ""; //Fecha y tiempo de últimos LoRa recibidos la noticia
uint32_t nowCnt = 0; //Número de las noticias ESP Now recibidas
Bramante nowLast = ""; //Fecha y tiempo de últimos LoRa recibidos la noticia
uint32_t cayCnt = 0; //Número de las noticias MQTT enviadas
Bramante cayLast = ""; //Fecha y tiempo de la última noticia MQTT enviada


//La función entrega la fecha y hora en el formato el yyyy el mm dd hh:mm:ss como bramante
Bramante getLocalTime()
{   char sttime[20] = "";   struct tm timeinfo;   if(!getLocalTime(&timeinfo)){     Serial.println("Failed to obtain time");     return sttime;   }   strftime(sttime, sizeof(sttime), "%Y-%m-%d %H:%M:%S", &timeinfo);   return sttime;
}

//La función entrega 6 bytes de Geräte-Id en el formato xx:xx:xx:xx:xx:xx como bramante
Bramante getId(uint8_t id[6])
{   Bramante stid;   char tmp[4];   sprintf(tmp,"x",id[0]);   stid=tmp;   for (uint8_t j = 1; j<6; j++) {     sprintf(tmp,": x",id[j]);     stid = stid += tmp ;   }   return stid;
}

//prepara el tope de noticias
//pone todas las noticias en acaba
void initMessageBuffer() {   for (int i = 0;i<MAXCHANNELS;i++) mensajes[i].de nuevo = 0;
}

//Función al almacén de la configuración
void schreibeKonfiguration(const char *fn) {   File f = SPIFFS.open(fn, FILE_WRITE);   if (!f) {     Serial.println(F("ERROR: SPIFFS los puede la configuración no guardan"));     return;   }   for (uint8_t i = 0; i<MAXDEVICE; i++) {     f.print(devices[i].activamente);f.print(",");     f.print(devices[i].sirves);f.print(",");     f.print(getId(devices[i].id));f.print(",");     f.print(devices[i].nombre);f.print(",");     f.println(devices[i].leía);   }
}

//Función para registrar un nuevo utensilio
void geraetRegistrieren() {   uint8_t i = 0;   //busca la inscripción libre   while ((i<MAXDEVICE) && devices[i].activamente) i++;   //si no hay ninguna nueva inscripción no hacemos nada   if (i < MAXDEVICE) {     //además el utensilio registran el nombre = el nombre dado      //o desconocido si nadie era dado     if (servidor.hasArg("devname")) {       devices[i].nombre = servidor.mucho("devname");     } else {       devices[i].nombre = "desconocido";     }     for (uint8_t j = 0; j<6; j++) devices[i].id[j]=desconocido[j];     devices[i].activamente = 1;     devices[i].sirves= neuesGeraetTyp;     devices[i].leía = "";     schreibeKonfiguration("/konfiguration.csv");     un nuevo utensilio = false;   }
}

//El servicio la función de la Web del servidor
void handleRoot() {   char htmlbuf[1024];   char tmp1[20];   char tmp2[20];   char tmp3[20];   int índice;   //¿el apaga el botón era hecho clic?   if (servidor.hasArg("delete")) {     índice = servidor.mucho("delete").toInt();
#ifdef DEGUG     Serial.printf("Lösche device %i =",índice);     Serial.println(devices[índice].nombre);
#endif     devices[índice].activamente=0;     schreibeKonfiguration("/konfiguration.csv");   }   //¿el registrar el botón era hecho clic?   if (servidor.hasArg("registrar")) {     geraetRegistrieren();   }   //Envían el HTML actual al lado al navegador   servidor.setContentLength(CONTENT_LENGTH_UNKNOWN);   //Header   WiFi.localIP().toString().toCharArray(tmp1,20);   sprintf(htmlbuf,HTML_HEADER,tmp1);   servidor.envía(200, "texto / html",htmlbuf);   //Formulario el principio   servidor.sendContent("<div class = \"el título \">MQTT - Gateway</div><form>");   //Tabla de los utensilios activos   servidor.sendContent(HTML_TAB_GERAETE);   for (uint8_t i = 0; i<MAXDEVICE; i++) {      if (devices[i].activamente == 1) {        getId(devices[i].id).toCharArray(tmp1,20);       devices[i].nombre.toCharArray(tmp2,20);       devices[i].leía.toCharArray(tmp3,20);       sprintf(htmlbuf,HTML_TAB_ZEILE,tmp1,i,i*8,i*8+7,tmp2,tmp3,i);       servidor.sendContent(htmlbuf);     }   }   servidor.sendContent(HTML_TAB_END);   //En caso de que un nuevo utensilio fuera encontrado sus ID así como un campo de entrada se hacen para el nombre   //y un botón para registrar el nuevo utensilio indicado   if (un nuevo utensilio) {     getId(desconocido).toCharArray(tmp1,20);     sprintf(htmlbuf,HTML_NEWDEVICE,tmp1,tmp1);     servidor.sendContent(htmlbuf);   }   servidor.sendContent(HTML_END);
}

//Función a la busca de un utensilio en la lista de utensilios
//La devolución el índice del utensilio o-1 si no era encontrado
int findDevice(uint8_t dev[6]) {   uint8_t j;   uint8_t i = 0;   boolean found = false;   do {     j = 0;     if (devices[i].activamente == 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 al anuncio del estatus en el display OLED
void indica() {   display.clear();   display.drawString(0,0,"La esclusa MQTT");   display.drawString(0,10,getLocalTime());   display.drawString(0,20,WiFi.localIP().toString());   display.drawString(0,34,"MQTT:");   display.drawString(60,34,Bramante(cayCnt));   display.drawString(0,44,"LoRa:");   display.drawString(60,44,Bramante(loraCnt));   display.drawString(0,54,"NOW:");   display.drawString(60,54,Bramante(nowCnt));   display.display();
}


//Tratan una noticia de LoRa el cliente
void readLoRa() {   int devnr;   uint8_t devid[6];   uint8_t canal;   uint8_t tipo;   uint8_t len;   uint8_t dat;   boolean producción total;   //Datos van a buscar disponible en caso de que   int packetSize = LoRa.parsePacket();   //¿hemos recibido datos?   if (packetSize > 5) {
#ifdef DEBUG         Serial.println(getLocalTime());     Serial.print("RX");     Serial.print(packetSize);     Serial.println("Bytes");     Serial.print("Device ID");
#endif      //al principio Geräte-Id leen     for (uint8_t i=0; i<6;i++){       devid[i]=LoRa.read();
#ifdef DEBUG       Serial.printf("- x",devid[i]);
#endif     }
#ifdef DEBUG     Serial.println();
#endif     //Calculan el paquete de resto     packetSize -= 6;     //revisan si el utensilio está registrado     devnr = findDevice(devid);     if (devnr >= 0)  {       //si ponemos el sello de tiempo para el último mensaje y       //si leen los datos       devices[devnr].leía = getLocalTime();       schreibeKonfiguration("/konfiguration.csv");       while (packetSize > 0) {         //Número de canal = el número de utensilios * 16 canales de utensilios         canal = LoRa.read() + devnr*16;
#ifdef DEBUG         Serial.printf("El canal: x",canal);
#endif         //tipo del canal         tipo = LoRa.read();
#ifdef DEBUG         Serial.printf("El tipo: x",tipo);
#endif         //instruyen a la longitud del paquete de datos y si el canal es Aktuator         producción total = false;         switch(tipo) {           case LPP_DIGITAL_INPUT : len = LPP_DIGITAL_INPUT_SIZE - 2; break;           case LPP_DIGITAL_OUTPUT : len = LPP_DIGITAL_OUTPUT_SIZE - 2; salida = cierto; descanso;           caso LPP_ANALOG_INPUT : Len = LPP_ANALOG_INPUT_SIZE - 2; descanso;           caso LPP_ANALOG_OUTPUT : Len = LPP_ANALOG_OUTPUT_SIZE - 2; salida = cierto; descanso;           caso LPP_LUMINOSITY : Len = LPP_LUMINOSITY_SIZE - 2; descanso;           caso LPP_PRESENCE : Len = LPP_PRESENCE_SIZE - 2; descanso;           caso LPP_TEMPERATURE : Len = LPP_TEMPERATURE_SIZE - 2; descanso;           caso LPP_HUMIDIDAD_RELATIVA : Len = LPP_RELATIVE_HUMIDITY_SIZE - 2; descanso;           caso LPP_ACCELEROMETER : Len = LPP_ACCELEROMETER_SIZE - 2; descanso;           caso LPP_BAROMETRIC_PRESSURE : Len = LPP_BAROMETRIC_PRESSURE_SIZE - 2; descanso;           caso LPP_GYROMETER : Len = LPP_GYROMETER_SIZE - 2; descanso;           caso LPP_GPS : Len = LPP_GPS_SIZE - 2; descanso;           defecto: Len =  0;         }         // ist der Kanal kein Aktuator, setzen wir im Nachrichtenbuffer neu auf 1         // damit die Daten bei nächster Gelegenheit an den MQTT Server gesendet werden         Si (!salida) mensajes[canal].neu =1;         mensajes[canal].Typ = Typ;         // Restpaket = 2 weniger da Kanal und Typ gelesen wurden         tamaño del paquete -= 2;
#ifdef DEPURAR         De serie.impresión("Daten:");
#terminara si         // nun lesen wir die empfangenen Daten mit der ermittelten Länge         para (uint8_t yo=0; yo<Len; yo++) {           dat = LoRa.leer();           // für Aktuatoren merken wir uns keine Daten           Si (! salida) mensajes[canal].daten[yo] = dat;
#ifdef DEPURAR           De serie.printf("-% 02x",dat);
#terminara si           // Restpaket um eins vermindern           tamaño del paquete --;         }
#ifdef DEPURAR         De serie.println();
#terminara si       }       // Status aktualisieren       loraCnt++;       loraÚltimo = getLocalTime();       anzeige();     } más {       // Das Gerät ist nicht registriert        // wir merken uns die Geräte-Id um sie für die Registriuerung anzuzeigen       para (uint8_t yo = 0; yo<6; yo++) unbekannt[yo] = devid[yo];       neuesGeraet = cierto;       neuesGeraetTyp = 0; // LoRa Gerät     }     // Teil zwei Antwort an das LoRa Gerät senden     retrasar(100);     LoRa.beginPacket();     // soy Anfang die Geräte-Id     LoRa.escribir(devid,6);     // wir prüfen ob wir Salida Daten für das aktuelle LoRa-Gerät haben     En t devbase = devnr*16;     para (En t yo = devbase; yo<devbase+8; yo++) {       // je nach typ Digital oder Analogdaten       cambiar (mensajes[yo].Typ) {           caso LPP_DIGITAL_OUTPUT : LoRa.escribir(yo-devbase);             LoRa.escribir(mensajes[yo].Typ);             LoRa.escribir(mensajes[yo].daten,1);
#ifdef DEPURAR             De serie.println("Ausgang digital");
#terminara si             descanso;           caso LPP_ANALOG_OUTPUT :  LoRa.escribir(yo-devbase);             LoRa.escribir(mensajes[yo].Typ);             LoRa.escribir(mensajes[yo].daten,2);
#ifdef DEPURAR             De serie.println("Ausgang analógico");
#terminara si             descanso;       }     }          En t lstatus = LoRa.endPacket();
#ifdef DEPURAR     De serie.impresión("Sendestatus =");     De serie.println(lstatus);
#terminara si   }
}

// Funktion zum lesen der Konfiguration
vacío leseKonfiguration(const carbonizarse *fn) {   uint8_t yo = 0;   Cuerda tmp;   carbonizarse maleficio[3];   Si (!SPIFFS.existe(fn)) {     // existiert noch nicht dann erzeugen     schreibeKonfiguration(fn);     regreso;   }   Archivo F = SPIFFS.abierto(fn, "r");   Si (!F) {     De serie.println(F("ERROR :: SPIFFS Kann Konfiguration nicht öffnen"));     regreso;   }   mientras (F.disponible() && (yo<MAXDEVICE)) {     tmp = F.readStringUntil(',');     dispositivos[yo].aktiv = (tmp == "1");     tmp = F.readStringUntil(',');     dispositivos[yo].dienst = tmp.toInt();     tmp = F.readStringUntil(',');     para (uint8_t j=0; j<6; j++){       maleficio[0]=tmp[j*3];       maleficio[1]=tmp[j*3+1];       maleficio[2]=0;       dispositivos[yo].carné de identidad[j]= (byte) strtol(maleficio,NULO,16);     }     tmp = F.readStringUntil(',');     dispositivos[yo].nombre = tmp;     tmp = F.readStringUntil(',');     dispositivos[yo].último = tmp;     yo++;   }    }

vacío preparar() {   // gerätespeicher initialisieren   para (uint8_t yo =0; yo<MAXDEVICE; yo++) dispositivos[yo].aktiv = 0;   // Pantalla OLED initialisieren   pinMode(16,SALIDA);   digitalWrite(16, BAJO);   retrasar(50);    digitalWrite(16, ALTO);   monitor.en eso();   monitor.flipScreenVertically();   monitor.setFont(ArialMT_Plain_10);   monitor.setTextAlignment(TEXT_ALIGN_LEFT);   //Lanzan la interface en serie   Serial.begin(115200);   while (!Serial);    Serial.println("Salida");   //Flash el file syastem   if (SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED)) Serial.println(F("SPIFFS de modo cargado"));   //Configuración einlesen   configuración de vendimia("/konfiguration.csv");     initMessageBuffer();   //SPI y LoRa inicializan   SPI.begin(5,19,27,18);   LoRa.setPins(SS,RST,DI0);   Serial.println("LoRa TRX");   if (!LoRa.begin(CINTA)) {     Serial.println("¡Starting LoRa failed!");     while (1);   }   LoRa.enableCrc();   Serial.println("¡LoRa Inicialmente el OKEY!");   delay(2000);   //Ligan con WLAN y servidor MQTT   Serial.println("WLAN ligan");   Cayenne.begin(MQTT_USER, MQTT_PASSWORD, MQTT_CLIENTID, WIFI_SSID, WIFI_PASSWORD);   Serial.print("IP address:");   Serial.println(WiFi.localIP());   //La Web servidores inicializan   servidor.on("/", handleRoot);   servidor.begin();   //La hora sincronizan el servidor de tiempo   configTime(GMT_OFFSET_SEC, DAYLIGHT_OFFSET_SEC, NTP_SERVER);   //Distribuyen hora actual   Serial.println(getLocalTime());


}


void loop() {   indica();   //Examinan LoRa la interfaz en datos   readLoRa();   //con Cayenne MQTT servidores comunican   Cayenne.loop(1);   //La Web servidores sirven   servidor.handleClient();

}

//Datos del tope de noticias envían al servidor MQTT
CAYENNE_OUT_DEFAULT()
{   boolean producción total = false;   boolean sentData = false;
#ifdef DEBUG   Serial.println(getLocalTime());   Serial.println("Cayenne envía");
#endif   for (int i = 0; i<MAXCHANNELS; i++) {     //noticias sólo nuevas envían     if (mensajes[i].de nuevo == 1) {
#ifdef DEBUG       Serial.printf("Sende MQTT Typ %i\n",mensajes[i].tipo);
#endif       //según el tipo Datos envían       switch (mensajes[i].tipo) {           case LPP_DIGITAL_INPUT : Cayenne.digitalSensorWrite(i,mensajes[i].datos[0]); break;           case LPP_DIGITAL_OUTPUT : producción total = true; break;           //case LPP_ANALOG_INPUT: Cayenne.virtualWrite (i, (mensajes [i].daten [0] *256 mensajes [i].daten [1])/100, "analog_sensor", UNIT_UNDEFINED); break; break;           case LPP_ANALOG_OUTPUT : producción total = true; break;           case LPP_LUMINOSITY : Cayenne.luxWrite(i,mensajes[i].datos[0]*256 + mensajes[i].datos[1]); break;           case LPP_PRESENCE : Cayenne.digitalSensorWrite(i,mensajes[i].datos[0]); break;           case LPP_TEMPERATURE : Cayenne.celsiusWrite(i,(mensajes[i].datos[0]*256 + mensajes[i].datos[1])/10); break;           case LPP_RELATIVE_HUMIDITY : Cayenne.virtualWrite(i,mensajes[i].datos[0]/2,TYPE_RELATIVE_HUMIDITY,UNIT_PERCENT); break;           case LPP_ACCELEROMETER : Cayenne.virtualWrite(i,(mensajes[i].datos[0]*256 + mensajes[i].datos[1])/1000,"gx","g"); break;           case LPP_BAROMETRIC_PRESSURE : Cayenne.hectoPascalWrite(i,(mensajes[i].datos[0]*256 + mensajes[i].datos[1])/10); break;           //case LPP_GYROMETER: len = LPP_GYROMETER_SIZE - 2; break;           //case LPP_GPS: len = LPP_GPS_SIZE - 2; break;       }       if (!producción total) {         mensajes[i].de nuevo = 0;         sentData = true;       }            }   }   if (sentData) {     //Actualizan el estatus     cayCnt++;     cayLast = getLocalTime();     indica();   }

}

CAYENNE_IN_DEFAULT()
{   uint8_t * pData;   int val;   int ch = request.canal;
#ifdef DEBUG   Serial.println("Cayenne recive");   Serial.printf("Datos MQTT para el canal %i = %s\n",ch,getValue.asString());
#endif   switch (mensajes[ch].tipo) {       case LPP_DIGITAL_OUTPUT : mensajes[ch].datos[0] = getValue.asInt();         mensajes[ch].de nuevo = 1;         break;       case LPP_ANALOG_OUTPUT :  val = round(getValue.asDouble()*100);         mensajes[ch].datos[0] = val / 256;         mensajes[ch].datos[1] = val % 256;         mensajes[ch].de nuevo = 1;         break;   }    }

 

 

DisplaysEsp-32Projekte für fortgeschrittene

3 comentarios

moi

moi

für was genau ist der cayenne server zuständig?

kann ich auch einfach eine lokale ip eines mqtt servers eingeben und die pakete werden an diesen weiter geleitet?

Gerald Lechner

Gerald Lechner

Hallo Marco
Ja du brauchst dafür einen zweiter ESP32 mit LoRa und im nächsten Teil folgt der notwendige Code.
Gruß Gerald

Marco

Marco

Hallo,
toller Artikel der Lust aufs Ausprobieren macht. Noch eine Frage. Ihr beschreibt hier das Gateway. Das “spricht” auf der einen Seite LoRa und auf der anderen Seite (via WLan) mit einem Netzwerk.
Ich bräuchte dann für die Kommunikation mittels LoRa dann noch einen zweiten ESP als Client, richtig? Könnt Ihr darüber vielleicht einen 4. Teil machen und erklären wie man dann damit ein Ende-Ende Szenario aufbaut?

Viele Grüße
Marco

Deja un comentario

Todos los comentarios son moderados antes de ser publicados