1. Instrucciones en Arduino IDE
Para el envío de los mensajes hacia el broker MQTT y Home Assistant se usa un dispositivo configurado como gateway.
Se usa un dispositivo en lugar de un concentrador en la etapa de prototipo considerando los costos involucrados. La próxima tarea es desarrollar el gateway usando un concentrador, cuyo valor es más alto.
/* Gateway LoRa
Lora/Wifi/MQTT/Home-Assistant
Envia información por red Lora/Gateway WiFi
hacia un broker MQTT y gestionar datos en Home-Assistant
edelros@espol.edu.ec
http://blog.espol.edu.ec/edelros/
Referencia: Aaron.Lee www.heltec.cn
https://github.com/Heltec-Aaron-Lee/WiFi_Kit_series
*/
#include "heltec.h"
#include <WiFi.h>
#include <PubSubClient.h>
// DISPOSITIVO LORA Banda ISM en Región 915Mhz
#define BAND 915E6 //433E6,868E6,915E6
// ranges from 6-12,default 7 see API docs
byte spread_factor = 8;
// LoRa Mensaje a enviar por direcciones
String paqueteEnv = "";
byte dir_local = 0xC1; // Concentrador 1
byte dir_destino = 0xD1; // Dispositivo 1
byte msjContador = 0; // identificador de mensaje
// tiempo entre lecturas
long t_anterior = 0;
int t_intervalo = 4000;
// LoRa Mensaje Recibido
byte dir_envio = 0xC1; // Concentrador 1
int dir_remite = 0xD0; // Inicia Remitente
String paqueteRcb = "";
byte paqrcbID = 0;
byte paqrcbEstado = 0;
// 0:vacio, 1: nuevo, 2:incompleto
// 3:otro destinatario, 4:Broadcast
// Mensajes por Puerto Serial
volatile boolean serial_msj = true;
// WIFI: conexión a Router
char* ssid = "giotirni20";
char* password = "Anera2020@";
// MQTT: Servidor
char* MQTT_IP = "192.168.10.50";
uint16_t MQTT_puerto = 1883;
char* MQTT_usuario = "usuarioprueba";
char* MQTT_contrasena = "usuarioclave";
// MQTT: Dispositivo Sensor
char* MQTT_ID = "LoraGatewayC1";
char MQTT_TOPIC_T[50] = "invernadero/loraD1/temperatura";
char MQTT_TOPIC_H[50] = "invernadero/loraD1/humedad";
char MQTT_TOPIC_V[50] = "invernadero/loraD1/voltaje";
char MQTT_SensorEstado[10] = "OFF";
volatile boolean mqtt_desconectado = true;
// MQTT: Dispositivo Actuador
char* MQTT_COMMAND = "invernadero/loraD1/cambia";
char MQTT_ActuadorEstado[10] = "OFF";
volatile boolean actuador_estado = false;
volatile boolean actuador_bandera = false;
char temperatura[10] = "00.00";
char humedad[10] = "00.00";
char voltaje[10] = "00.00";
// Clientes WiFi y MQTT
WiFiClient wificlient;
PubSubClient mqttclient(wificlient);
void setup(){
Heltec.begin(false /*DisplayEnable Enable*/,
true /*Heltec.Heltec.Heltec.LoRa Disable*/,
serial_msj /*Serial Enable*/,
true /*PABOOST Enable*/,
BAND /*long BAND*/);
// ranges from 6-12,default 7 see API docs
LoRa.setSpreadingFactor(spread_factor);
//LoRa.onReceive(cbk);
LoRa.receive();
// conexión WIFI y MQTT
inicia_wifi();
if (WiFi.status() == WL_CONNECTED){
inicia_mqtt();
}
}
void loop(){
// parametros de recepción
int rssi_lora = 0;
int snr_lora = 0;
// Revisa mensajes LoRa entrantes
int msjRcbLoRa = LoRa.parsePacket();
if (msjRcbLoRa !=0){
recibirlora(msjRcbLoRa);
rssi_lora = LoRa.packetRssi();
snr_lora = LoRa.packetSnr();
if (serial_msj==true){
Serial.println("remite,msjID,mensaje,estado,Rssi,Snr");
Serial.print(String(dir_remite, HEX)); Serial.print(",");
Serial.print(paqrcbID); Serial.print(",");
Serial.print(paqueteRcb); Serial.print(",");
Serial.print(paqrcbEstado); Serial.print(",");
Serial.print(rssi_lora); Serial.print(",");
Serial.println(snr_lora);
}
yield(); // procesa wifi
// LED parpadea Rebibido Lora
digitalWrite(LED, HIGH); delay(50);
digitalWrite(LED, LOW); delay(50);
digitalWrite(LED, HIGH); delay(50);
digitalWrite(LED, LOW);
yield(); // procesa wifi
delay(100);
}
// Procesa a MQTT mensaje completo
if (msjRcbLoRa !=0 && paqrcbEstado == 1){
// Separa parámetros
String t = paqueteRcb.substring(1,6);
String h = paqueteRcb.substring(8,10);
String v = paqueteRcb.substring(12);
// procesa tópico MQTT
// añade dispositivo
String topico = "invernadero/lora";
String remite = String(dir_remite, HEX);
remite.toUpperCase();
topico = topico + remite;
// procesa topico
String topicot = topico + "/temperatura";
String topicoh = topico + "/humedad";
String topicov = topico + "/voltaje";
topicot.toCharArray(MQTT_TOPIC_T,topicot.length()+1);
topicoh.toCharArray(MQTT_TOPIC_H,topicoh.length()+1);
topicov.toCharArray(MQTT_TOPIC_V,topicov.length()+1);
t.toCharArray(temperatura,t.length()+1);
h.toCharArray(humedad,h.length()+1);
v.toCharArray(voltaje,v.length()+1);
Serial.println(topicov);
publica_estado();
}
yield(); // procesa wifi
delay(20);
// reenviar a dispositivo
if (actuador_bandera == true){
msjContador = msjContador +1;
enviarlora(dir_destino, dir_local,
msjContador, paqueteEnv);
actuador_bandera = false;
}
yield(); // procesa wifi
delay(20);
if (WiFi.status() != WL_CONNECTED){
inicia_wifi();
}else{
if (mqttclient.connected()==false){
mqtt_desconectado = true;
inicia_mqtt(); // reintento
}
if (mqttclient.connected()==true){
if (mqtt_desconectado==true){
publica_estado();
mqtt_desconectado=false;
}
mqttclient.loop();
}
}
yield(); // procesa wifi
}
void enviarlora(byte destino, byte remite,
byte paqueteID, String paquete){
// espera que el radio esté listo
// para enviar un paquete
while(LoRa.beginPacket() == 0){
if (serial_msj==true){
Serial.println("Esperando radio disponible...");
}
yield(); // procesa wifi
delay(100);
}
// envio del mensaje LoRa
LoRa.beginPacket();
LoRa.write(destino);
LoRa.write(remite);
LoRa.write(paqueteID);
LoRa.write(paquete.length());
LoRa.print(paquete);
LoRa.endPacket();
}
void recibirlora(int tamano){
if (tamano == 0){
paqrcbEstado = 0; //vacio
return;
}
// lectura de paquete
paqueteRcb = "";
dir_envio = LoRa.read();
dir_remite = LoRa.read();
paqrcbID = LoRa.read();
byte paqrcbTamano = LoRa.read();
while(LoRa.available()){
paqueteRcb += (char)LoRa.read();
}
if (paqrcbTamano != paqueteRcb.length()){
paqrcbEstado = 2; // Tamaño incompleto
return;
}
if (dir_envio != dir_local){
paqrcbEstado = 3; // otro destino
return;
}
if (dir_envio == 0xFF) {
paqrcbEstado = 4; // Broadcast
return;
}
paqrcbEstado = 1; // mensaje Nuevo
}
void inicia_mqtt(void){
int intentosmqtt = 5;
int cuentamqtt = 0;
if (serial_msj){
Serial.print(" MQTT Conectando a ");
Serial.println(MQTT_IP);
}
mqttclient.setServer(MQTT_IP, MQTT_puerto);
mqttclient.connect(MQTT_ID, MQTT_usuario, MQTT_contrasena);
mqttclient.setCallback(recibirmqtt);
while (!mqttclient.connected() && (cuentamqtt<=intentosmqtt)){
if (serial_msj){
Serial.print(".");
}
cuentamqtt = cuentamqtt + 1;
// LED Monitor parpadeo MQTT
digitalWrite(LED, HIGH); delay(200);
digitalWrite(LED, LOW); delay(200);
}
if (mqttclient.connected()){
publica_estado();
}
if (serial_msj){
//Fin de "...."
Serial.println();
Serial.print(" MQTT Conectado: ");
Serial.print(mqttclient.connected());
Serial.print("\t MQTT Estado: ");
Serial.println(mqttclient.state());
}
}
void publica_estado() {
if (mqttclient.connected()==true){
mqttclient.publish(MQTT_TOPIC_T,temperatura,true);
mqttclient.publish(MQTT_TOPIC_H,humedad,true);
mqttclient.publish(MQTT_TOPIC_V,voltaje,true);
mqttclient.subscribe(MQTT_COMMAND);
}else{
mqtt_desconectado = true;
}
}
// llega mensaje MQTT, callback mqtt
void recibirmqtt(char* p_topic, byte* p_payload,
unsigned int p_length) {
Serial.println("un mensaje mqtt");
Serial.println(p_topic);
// convierte a texto
String payload;
for (uint8_t i = 0; i < p_length; i++) {
payload.concat((char)p_payload[i]);
}
// String dispositivo = p_topic[16] + String(p_topic[17]);
char dispositivo[3] = "D0";
dispositivo[1]=p_topic[17];
dir_destino = (int) strtol(dispositivo,NULL,16);
paqueteEnv = payload;
actuador_bandera = true;
if (mqttclient.connected()==true){
mqttclient.subscribe(MQTT_COMMAND);
}else{
mqtt_desconectado = true;
}
}
void inicia_wifi(void) {
int intentoswifi = 10;
int cuentawifi = 0;
if (serial_msj){
Serial.print(" WiFi Conectando a ");
Serial.println(ssid);
}
WiFi.disconnect(true);
delay(1000);
WiFi.mode(WIFI_STA);
WiFi.setAutoConnect(true);
WiFi.begin(ssid,password);
delay(100);
while(WiFi.status() != WL_CONNECTED &&
cuentawifi < intentoswifi){
if (serial_msj){
Serial.print(".");
}
cuentawifi = cuentawifi + 1;
// Parpadeo de Monitor Wifi
digitalWrite(LED, HIGH);delay(300);
digitalWrite(LED, LOW);delay(200);
}
if (serial_msj){
// mensaje a serial
Serial.println();
if (WiFi.status() == WL_CONNECTED){
Serial.print(" Estado: ");
Serial.println(WiFi.status());
Serial.print(" MAC: ");
Serial.println(WiFi.macAddress());
Serial.print(" IP: ");
Serial.println(WiFi.localIP());
Serial.print(" RSSI: ");
Serial.println(WiFi.RSSI());
Serial.println();
}
if (WiFi.status() != WL_CONNECTED){
WiFi.printDiag(Serial);
Serial.println();
}
}
}