Referencia: https://github.com/Heltec-Aaron-Lee/WiFi_Kit_series
Para prueba del concepto, se implementa un dispositivo simplificado, un dispositivo que emite un «parpadeo» binario como estado de sensor.
Estado del sensor
El estado del sensor se indica con los valores "ON"
encendido y "OFF"
para apagado. El parpadeo se realiza a intervalos de tiempo de duración aleatoria entre 1 a 3 segundos.
Direccionamiento
El direccionamiento se realiza usando un numero hexadecimal almacenado en un byte. Por facilidad de identificación, se usa como dirección :
- Dispositivo usa
"D1"
por la inicial, los otros dispositivos serán "D2"
,"D3"
, etc.
- gateway usa la dirección
"C1"
cuya inicial es de Concentrador o coordinador, nombre también usado en otras tecnologías.
El algoritmo esta realizado para una placa de desarrollo LoRa, la disponible es de marca Heltec LoRa ESP32 que ofrece librerías simplificadas. Un siguiente paso de desarrollo consiste en usar un módulo LoRa y un Arduino Uno por ejemplo, realizado con librerías más generales.
Instrucciones
Las instrucciones de dividen en el bloque principal, el procedimiento de sensor, y los procedimientos LoRa para envío y recepcion, separados en cada pestaña.
Bloque principal
Declara las librerias para el módulo o placa de desarrollo Heltec, se indica los parámetros LoRa como la Banda ISM que para Ecuador es US915, también se establecen las variables para el manejo de los mensajes de envío y recepción, tiempo de lecturas del sensor «simulado» para la prueba.
El bucle de configuración setup()
inicializa el módulo y el de operación loop()
revisa los tiempos en los que se debe realizar la lectura del sensor y el envío del mensaje LoRa. Luego revisa si se ha recibido un mensaje LoRa para mostrarlo en la ventana del «monitor serie».
/* Dispositivo Sensor Blink Parpadeo ON/OFF
* http://blog.espol.edu.ec/girni/lora-multipunto-esquema/
* Referencia: Ejemplos de Aaron.Lee www.heltec.cn
*/
#include "heltec.h"
// LoRa Banda ISM en Región 915Mhz
#define BAND 915E6 // 433E6,868E6,915E6
byte spread_factor = 8; // rango 6-12,default 7
// Mensaje LoRa a enviar por direcciones
byte dir_local = 0xD1; // Dispositivo 1
byte dir_destino = 0xC1; // Dispositivo 2
byte id_msjLoRa = 0; // cuenta mensaje
String paqueteEnv= ""; // mensaje
// Mensaje LoRa recibido
byte dir_envio = 0xD1; // receptor
byte dir_remite = 0xC1; // emisor
String paqueteRcb = ""; // mensaje LoRa
byte paqRcb_ID = 0;
byte paqRcb_Estado = 0;
// 0:vacio, 1: nuevo, 2:incompleto
// 3:otro destinatario, 4:Broadcast
// Mensajes por Puerto Serial activa
boolean serial_msj = true;
// SENSOR Parpadeo
String sensorEstado = "ON"; // ON/OFF: 1/0
// tiempo entre lecturas
long tiempo_antes = 0;
long tiempo_intervalo = 6000;
long tiempo_espera = tiempo_intervalo + random(3000);
void setup(){
Heltec.begin(false /*DisplayEnable Enable*/,
true /*Heltec.Heltec.Heltec.LoRa Disable*/,
serial_msj /*Serial Enable*/,
true /*PABOOST Enable*/,
BAND /*long BAND*/);
LoRa.setSpreadingFactor(spread_factor);
//LoRa.onReceive(cbk);
LoRa.receive();
}
void loop(){
int rssi_lora = 0; // nivel de señal
int snr_lora = 0;
// Enviar mensajes entre intervalos
long tiempo_ahora = millis();
long t_transcurrido = tiempo_ahora - tiempo_antes;
if (t_transcurrido >= tiempo_espera){
sensor_revisa(); //actualiza sensor
paqueteEnv = String(sensorEstado).c_str() ;
envia_lora(dir_destino, dir_local,
id_msjLoRa, paqueteEnv);
id_msjLoRa = id_msjLoRa + 1;
// mensaje a serial monitor
if (serial_msj == true){
Serial.print("Enviado: ");
Serial.print(String(dir_local,HEX));
Serial.print(",");
Serial.print(String(dir_destino,HEX));
Serial.print(",");
Serial.print(id_msjLoRa-1);
Serial.print(",");
Serial.println(paqueteEnv);
}
tiempo_antes = millis();
tiempo_espera = tiempo_intervalo + random(3000);
// LED parpadea. Envio LoRa
digitalWrite(LED, HIGH); delay(100);
digitalWrite(LED, LOW ); delay(100);
}
// Revisar mensajes LoRa entrantes
int msjRcbLoRa = LoRa.parsePacket();
if (msjRcbLoRa !=0){
recibe_lora(msjRcbLoRa);
rssi_lora = LoRa.packetRssi();
snr_lora = LoRa.packetSnr();
if (serial_msj == true){
if (paqRcb_Estado == 1){
Serial.print("Recibido: ");
Serial.print(String(dir_remite,HEX));
Serial.print(",");
Serial.print(String(dir_envio,HEX));
Serial.print(",");
Serial.print(paqRcb_ID); Serial.print(",");
Serial.print(paqueteRcb); Serial.print(",");
Serial.print(rssi_lora); Serial.print(",");
Serial.print(snr_lora); Serial.print(",");
Serial.println();
}else{
Serial.print("Paquete recibido Estado: ");
Serial.println(paqRcb_Estado);
}
}
// LED parpadea Rebibido Lora
digitalWrite(LED, HIGH); delay(50);
digitalWrite(LED, LOW ); delay(50);
digitalWrite(LED, HIGH); delay(50);
digitalWrite(LED, LOW );
}
delay(100);
}
Procedimiento de envío de paquete LoRa
Se toman los valores para destino, remitente, identificador de paquete y el mensaje o paquete a enviar, para realizar el paso de envio del mensaje con la instrucción LoRa.write()
.
void envia_lora(byte destino, byte remite,
byte paqueteID, String paquete){
// espera radio para enviar un paquete
while(LoRa.beginPacket() == 0){
if (serial_msj==true){
Serial.println("Esperando radio disponible...");
}
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();
}
Procedimiento de recepción de paquete LoRa
Para recibir un paquete LoRa se procede en el mismo orden realizado para el envío, es decir primero se recibe la dirección de envío, la dirección del remitente, el identificador del mensaje, tamaño del mensaje en bytes, todo lo que viene luego es el mensaje transmitido.
Luego se revisa el tamaño del paquete recibido y se compara con el valor de la variable de tamaño del mensaje. Esto permite validar si el mensaje se ha recibido completo o requiere alguna retransmisión.
void recibe_lora(int tamano){
if (tamano == 0){
paqRcb_Estado = 0; //vacio
return;
}
// lectura de paquete
paqueteRcb = "";
dir_envio = LoRa.read();
dir_remite = LoRa.read();
paqRcb_ID = LoRa.read();
byte paqRcb_Tamano = LoRa.read();
while(LoRa.available()){
paqueteRcb += (char)LoRa.read();
}
if (paqRcb_Tamano != paqueteRcb.length()){
paqRcb_Estado = 2; // Tamaño incompleto
return;
}
if (dir_envio != dir_local){
paqRcb_Estado = 3; // otro destino
return;
}
if (dir_envio == 0xFF) {
paqRcb_Estado = 4; //Broadcast, difusion
return;
}
paqRcb_Estado = 1; // mensaje Nuevo
}
Procedimiento para el sensor
En el ejercicio el procedimiento para el sensor consiste en altenar los valores entre encendido y apagado, el valor cambia cada vez que se use el procedimiento sensor_revisa()
// Sensor Simulado
void sensor_revisa(){
if (sensorEstado == "ON"){
sensorEstado = "OFF";
}else{
sensorEstado = "ON";
}
}
Para subir todas las instrucciones recuerde primero seleccionar la placa de desarrollo correspondiente y verificar el puerto com
al que se conecta
Resultados en monitor serie
El resultado observable en monitor serie es semejante al mostrado:
Serial initial done
LoRa Initial success!
Enviado: d1,c1,0,OFF
Enviado: d1,c1,1,ON
Enviado: d1,c1,2,OFF
Enviado: d1,c1,3,ON
Pruebas punto a punto
Para realizar pruebas punto a punto, es necesario usar todas las instrucciones anteriores y cambiar solamente la dirección local y destino del mensaje y en el bloque principal siguiendo el esquema:
// LoRa envia paquete, direccion, contador
byte dir_local = 0xC1; // Dispositivo 1
byte dir_destino = 0xD1; // Dispositivo 2
En el caso de recepción, los valores se actualizan en el procedimiento, dado que las direcciones son parte de la trama de datos, por lo que los valores declarados son solo referenciales.
// LoRa recibe paquete
byte dir_envio = 0xC1; // receptor
byte dir_remite = 0xD1; // emisor
Con lo que se pueden intercambiar mensajes entre dispositivos, modalidad punto a punto, obteniendo el siguiente resultado si están conectados las dos placas de desarrollo.