Pluviometro LoRaWan con open hardware y open software
Protegido: LoRaWan – Pluviometro
Protegido: LoRaWan – Pluviometro y Decodificador en Chirpstack y HA
Protegido: LoRaWan – Pluviometro Archivo.ino
LoRaWan – Probador con OLED en Chirpstack y HomeAssistant
ChirpStack
DECODER
function Decode(fPort, bytes, variables) { var Down_rssi = -1*parseInt(bytes[0]); var Down_snr = bytes[1]; var Down_datarate = bytes[2]; // usando entero var unalectura = (bytes[4] << 8) |(bytes[3]); unalectura = (unalectura/1000); unalectura = +unalectura.toFixed(2); var appData = {'Down_rssi':Down_rssi,'Down_snr':Down_snr, 'Down_datarate':Down_datarate, 'bateria_V': unalectura} return appData; }
ENCODER
function Encode(fPort, obj, variables) { var UP_rssi = obj["UP_rssi"]; // var Up_snr = obj["UP_snr"]; var mensaje = [UP_rssi]; return mensaje; }
Home Assistant
configuration.yaml
mqtt: sensor: - name: "rssi_up_cc50" unique_id: cc27rssiup state_topic: "application/1/device/a53ec615aede3f50/event/up" unit_of_measurement: "dBm" value_template: "{{ value_json.rxInfo[0].rssi}}" #availability: # - topic: "home/sensor1/status" payload_available: "online" payload_not_available: "offline" json_attributes_topic: "application/1/device/a53ec615aede3f50/event/up"
Automation
Desencadenante
platform: mqtt topic: application/1/device/a53ec615aede3f50/event/up
Accion
service: mqtt.publish data: qos: 0 retain: false topic: application/1/device/a53ec615aede3f50/command/down payload: '{"confirmed":false,"fPort":4,"object":{"UP_rssi":{{(states("sensor.rssi_up_cc50") | int)*(-1)}}}}'
LoRaWan – Probador de campo con OLED Archivo.ino
Pantalla OLED con parametros RSSI UP/DOWN
Probador de Rssi de subida y bajada
Hardware: Heltec cubecell AB02, con pantalla OLED incorporada.
OLED_pantalla.ino
void displayconectando(){ display2.setFont(ArialMT_Plain_16); display2.setTextAlignment(TEXT_ALIGN_CENTER); display2.clear(); display2.drawString(58, 22, "Joining..."); display2.display(); } void displayConectado(){ display2.clear(); display2.drawString(64, 22, "Conectado_OK"); display2.display(); delay(500); } void displayTransmitiendo(){ digitalWrite(Vext,LOW); display2.init(); display2.setFont(ArialMT_Plain_16); display2.setTextAlignment(TEXT_ALIGN_CENTER); display2.clear(); display2.drawString(58, 22, "Tx..."); display2.display(); delay(500); } void displayPaqRecibido(){ char temp[25]; display2.clear(); display2.setFont(ArialMT_Plain_16); display2.setTextAlignment(TEXT_ALIGN_LEFT); sprintf(temp,"Rx snr:%d,dr:%d",Down_snr, Down_datarate); display2.drawString(0, 0, temp); //22 sprintf(temp,"rssiDw: -%d",Down_rssi); display2.setFont(ArialMT_Plain_24); display2.setTextAlignment(TEXT_ALIGN_RIGHT); display2.drawString(128, 16, temp); sprintf(temp,"rssiUp: -%d",Up_rssi); display2.setFont(ArialMT_Plain_24); display2.setTextAlignment(TEXT_ALIGN_RIGHT); display2.drawString(128, 40, temp); display2.drawString(0,0, temp); if(loraWanClass==CLASS_A) { display2.setFont(ArialMT_Plain_10); display2.setTextAlignment(TEXT_ALIGN_LEFT); display2.drawString(28, 50, "Into deep sleep in 2S"); } display2.display(); delay(10000); display2.clear(); if(loraWanClass==CLASS_A){ digitalWrite(Vext,HIGH); display2.stop(); } } void displayAckRecibido(){ char temp[25]; display2.clear(); display2.setFont(ArialMT_Plain_16); display2.setTextAlignment(TEXT_ALIGN_LEFT); sprintf(temp,"ACK snr:%d,dr:%d",confirmaSnr, confirmaDatarate); display2.drawString(0, 0, temp); //22 sprintf(temp,"rssiDw: -%d",confirmaRssi); display2.setFont(ArialMT_Plain_24); display2.setTextAlignment(TEXT_ALIGN_RIGHT); display2.drawString(128, 16, temp); if(loraWanClass==CLASS_A) { display2.setFont(ArialMT_Plain_10); display2.setTextAlignment(TEXT_ALIGN_LEFT); display2.drawString(28, 50, "Into deep sleep in 2S"); } display2.display(); delay(10000); if(loraWanClass==CLASS_A) { digitalWrite(Vext,HIGH); display2.stop(); } }
CubeCell_Practicas2023OLED.ino
// Lectura de Rssi Snr, datarate Up/Downlink // Datos Downlink de la trama de confirmación anterior // http://blog.espol.edu.ec/girni/lorawan-enlaces-up-down-archivo-ino/ #include "LoRaWan_APP.h" #include "Arduino.h" #include <Wire.h> #include "HT_SH1107Wire.h" SH1107Wire display2(0x3c, 500000, SDA, SCL ,GEOMETRY_128_64,GPIO10); // addr, freq, sda, scl, resolution, rst /* set LoraWan_RGB to Active,the RGB active in loraWan * red |sending; purple | joined done; * blue |RxWindow1; yellow | means RxWindow2; * green | received done; */ /* Conexión LoRa: OTAA parametros*/ uint8_t devEui[] = { 0xa5, 0x3e, 0xc6, 0x15, 0xae, 0xde, 0x3f, 0x50 }; uint8_t appEui[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t appKey[] = { 0x88, 0xbe, 0x25, 0xca, 0x2c, 0xcf, 0x31, 0x85, 0x51, 0x2d, 0xee, 0xe2, 0x80, 0x31, 0x8e, 0x01 }; /* ABP parametros*/ uint8_t nwkSKey[] = { 0x15, 0xb1, 0xd0, 0xef, 0xa4, 0x63, 0xdf, 0xbe, 0x3d, 0x11, 0x18, 0x1e, 0x1e, 0xc7, 0xda,0x85 }; uint8_t appSKey[] = { 0x47, 0xdc, 0xac, 0x5f, 0xc2, 0x32, 0x24, 0x31, 0xdf, 0xf1, 0xff, 0xf9, 0x46, 0xe5, 0x2e, 0x17 }; uint32_t devAddr = ( uint32_t )0x007bc4150; /*LoraWan channelsmask, default channels 0-7*/ uint16_t userChannelsMask[6]={ 0x00FF,0x0000,0x0000,0x0000,0x0000,0x0000 }; /*Select in arduino IDE tools*/ LoRaMacRegion_t loraWanRegion = ACTIVE_REGION; DeviceClass_t loraWanClass = LORAWAN_CLASS; bool overTheAirActivation = LORAWAN_NETMODE; bool loraWanAdr = LORAWAN_ADR; bool keepNet = LORAWAN_NET_RESERVE; bool isTxConfirmed = LORAWAN_UPLINKMODE; uint8_t duermemin = 0; //15 uint8_t duermeseg = 300; //0 uint32_t appTxDutyCycle = (duermemin*60 + duermeseg)*1000; // min*seg*ms uint8_t appPort = 4; /* Application port */ /* trials to transmit frame, if didn't receive ack. * The MAC performs a datarate adaptation, * Tx nb|Data Rate * -----|---------- * 1 |DR * 5 | max(DR-2,0) * 2 |DR * 6 | max(DR-2,0) * 3 |max(DR-1,0) * 7 | max(DR-3,0) * 4 |max(DR-1,0) * 8 | max(DR-3,0) */ uint8_t confirmedNbTrials = 4; // Ack parametros de recepción uint8_t confirmaRssi = 0; uint8_t confirmaSnr = 0; uint8_t confirmaDatarate = 0; // Ack parametros de recepción uint8_t Down_rssi = 0; uint8_t Down_snr = 0; uint8_t Down_datarate = 0; uint8_t Up_rssi = 0; uint8_t itera = 0; uint8_t estado = 0; //0x00, 0x01,"OFF","ON" void setup() { Serial.begin(115200); #if(AT_SUPPORT) enableAt(); #endif // OLED display status //LoRaWAN.displayMcuInit(); deviceState = DEVICE_STATE_INIT; //LoRaWAN.ifskipjoin(); //if joinned,skip display2.init(); display2.setFont(ArialMT_Plain_10); } void loop() { Serial.print("."); itera = itera + 1; if (itera>6){ itera = 0; Serial.println(" "); } switch( deviceState ) { case DEVICE_STATE_INIT: { #if(LORAWAN_DEVEUI_AUTO) LoRaWAN.generateDeveuiByChipID(); #endif #if(AT_SUPPORT) getDevParam(); #endif printDevParam(); LoRaWAN.init(loraWanClass,loraWanRegion); deviceState = DEVICE_STATE_JOIN; break; } case DEVICE_STATE_JOIN: { //LoRaWAN.displayJoining(); displayconectando(); LoRaWAN.join(); break; } case DEVICE_STATE_SEND: { //LoRaWAN.displaySending(); displayTransmitiendo(); prepareTxFrame( appPort ); LoRaWAN.send(); deviceState = DEVICE_STATE_CYCLE; break; } case DEVICE_STATE_CYCLE: { // Schedule next packet transmission txDutyCycleTime = appTxDutyCycle + randr( 0, APP_TX_DUTYCYCLE_RND ); LoRaWAN.cycle(txDutyCycleTime); deviceState = DEVICE_STATE_SLEEP; break; } case DEVICE_STATE_SLEEP: { //LoRaWAN.displayAck(); LoRaWAN.sleep(); break; } default: { deviceState = DEVICE_STATE_INIT; break; } } }
LoRaWanEnvia.ino
/* Prepares the payload of the frame */ static void prepareTxFrame( uint8_t port ) { // enciende sensor pinMode(Vext, OUTPUT); digitalWrite(Vext, LOW); //Lectura de Sensor //apaga sensor digitalWrite(Vext, HIGH); // lectura de bateria uint16_t batteryVoltage = getBatteryVoltage(); unsigned char *puc; // trama appDataSize = 5; appData[0] = confirmaRssi; //Ack leido en dispositivo appData[1] = confirmaSnr; appData[2] = confirmaDatarate; appData[3] = (uint8_t)batteryVoltage; appData[4] = (uint8_t)(batteryVoltage>>8); Serial.print("%, Bateria = "); Serial.println(batteryVoltage); }
LoRaWanRecibe.ino
//downlink data handle function example void downLinkDataHandle(McpsIndication_t *mcpsIndication){ // parametros de recepcion Down_rssi = uint8_t(abs(mcpsIndication->Rssi)); Down_snr = uint8_t(mcpsIndication->Snr); Down_datarate = uint8_t(mcpsIndication->RxDoneDatarate); // recibido de trama Up_rssi = uint8_t(mcpsIndication->Buffer[0]); // Serial.print("Rx Down_rssi:-"); Serial.print(Down_rssi); Serial.print(", Down_snr:");Serial.print(Down_snr); Serial.print(", Down_datarate: ");Serial.println(Down_datarate); Serial.print(" UP_rssi:"); Serial.print(-1*Up_rssi); Serial.printf(" +REV DATA:%s,RXSIZE %d,PORT %d\r",mcpsIndication->RxSlot?"RXWIN2":"RXWIN1",mcpsIndication->BufferSize,mcpsIndication->Port); Serial.println(); displayPaqRecibido(); }
LoRaWanRecibeConfirma.ino
void downLinkAckHandle(McpsIndication_t *mcpsIndication){ // ACK parametros de recepcion confirmaRssi = uint8_t(abs(mcpsIndication->Rssi)); confirmaSnr = uint8_t(mcpsIndication->Snr); confirmaDatarate = uint8_t(mcpsIndication->RxDoneDatarate); Serial.println(""); Serial.print(" ack received(rssi,snd,datarate): -"); Serial.print(confirmaRssi);Serial.print(" ,"); Serial.print(confirmaSnr);Serial.print(" ,"); Serial.println(confirmaDatarate); displayAckRecibido(); }
5. LoRaWan – HELTEC CubeCell Rssi PracticaLab.ino
Ejercicio de conexión a LoRaWan con ChirpStack y HomeAssistant
Bloque principal
// Lectura de Rssi Snr, datarate Up/Downlink // Datos Downlink de la trama de confirmación anterior // http://blog.espol.edu.ec/girni/lorawan-enlaces-up-down-archivo-ino/ #include "LoRaWan_APP.h" #include "Arduino.h" /* set LoraWan_RGB to Active,the RGB active in loraWan * red |sending; purple | joined done; * blue |RxWindow1; yellow | means RxWindow2; * green | received done; */ /* Conexión LoRa: OTAA parametros*/ uint8_t devEui[] = { 0xa5, 0x3e, 0xc6, 0x15, 0xae, 0xde, 0x3f, 0x00 }; uint8_t appEui[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t appKey[] = { 0x88, 0xbe, 0x25, 0xca, 0x2c, 0xcf, 0x31, 0x85, 0x51, 0x2d, 0xee, 0xe2, 0x80, 0x31, 0x8e, 0x01 }; /* ABP parametros*/ uint8_t nwkSKey[] = { 0x15, 0xb1, 0xd0, 0xef, 0xa4, 0x63, 0xdf, 0xbe, 0x3d, 0x11, 0x18, 0x1e, 0x1e, 0xc7, 0xda,0x85 }; uint8_t appSKey[] = { 0x47, 0xdc, 0xac, 0x5f, 0xc2, 0x32, 0x24, 0x31, 0xdf, 0xf1, 0xff, 0xf9, 0x46, 0xe5, 0x2e, 0x17 }; uint32_t devAddr = ( uint32_t )0x007bc4200; /*LoraWan channelsmask, default channels 0-7*/ uint16_t userChannelsMask[6]={ 0x00FF,0x0000,0x0000,0x0000,0x0000,0x0000 }; /*Select in arduino IDE tools*/ LoRaMacRegion_t loraWanRegion = ACTIVE_REGION; DeviceClass_t loraWanClass = LORAWAN_CLASS; bool overTheAirActivation = LORAWAN_NETMODE; bool loraWanAdr = LORAWAN_ADR; bool keepNet = LORAWAN_NET_RESERVE; bool isTxConfirmed = LORAWAN_UPLINKMODE; uint8_t duermemin = 0; //15 uint8_t duermeseg = 30; //0 uint32_t appTxDutyCycle = (duermemin*60 + duermeseg)*1000; // min*seg*ms uint8_t appPort = 4; /* Application port */ /* trials to transmit frame, if didn't receive ack. * The MAC performs a datarate adaptation, * Tx nb|Data Rate * -----|---------- * 1 |DR * 5 | max(DR-2,0) * 2 |DR * 6 | max(DR-2,0) * 3 |max(DR-1,0) * 7 | max(DR-3,0) * 4 |max(DR-1,0) * 8 | max(DR-3,0) */ uint8_t confirmedNbTrials = 4; // Ack parametros de recepción uint8_t confirmaRssi = 0; uint8_t confirmaSnr = 0; uint8_t confirmaDatarate = 0; uint8_t itera = 0; uint8_t estado = 0x00; //0x00, 0x01,"OFF","ON" void setup() { Serial.begin(115200); #if(AT_SUPPORT) enableAt(); #endif // OLED display status //LoRaWAN.displayMcuInit(); deviceState = DEVICE_STATE_INIT; //LoRaWAN.ifskipjoin(); //if joinned,skip } void loop() { Serial.print("."); itera = itera + 1; if (itera>6){ itera = 0; Serial.println(" "); } switch( deviceState ) { case DEVICE_STATE_INIT: { #if(LORAWAN_DEVEUI_AUTO) LoRaWAN.generateDeveuiByChipID(); #endif #if(AT_SUPPORT) getDevParam(); #endif printDevParam(); LoRaWAN.init(loraWanClass,loraWanRegion); deviceState = DEVICE_STATE_JOIN; break; } case DEVICE_STATE_JOIN: { //LoRaWAN.displayJoining(); LoRaWAN.join(); break; } case DEVICE_STATE_SEND: { //LoRaWAN.displaySending(); prepareTxFrame( appPort ); LoRaWAN.send(); deviceState = DEVICE_STATE_CYCLE; break; } case DEVICE_STATE_CYCLE: { // Schedule next packet transmission txDutyCycleTime = appTxDutyCycle + randr( 0, APP_TX_DUTYCYCLE_RND ); LoRaWAN.cycle(txDutyCycleTime); deviceState = DEVICE_STATE_SLEEP; break; } case DEVICE_STATE_SLEEP: { //LoRaWAN.displayAck(); LoRaWAN.sleep(); break; } default: { deviceState = DEVICE_STATE_INIT; break; } } }
LoraWan transmite
/* Prepares the payload of the frame */ static void prepareTxFrame( uint8_t port ) { // enciende sensor pinMode(Vext, OUTPUT); digitalWrite(Vext, LOW); //Lectura de Sensor // apaga sensor digitalWrite(Vext, HIGH); // lectura de bateria uint16_t batteryVoltage = getBatteryVoltage(); unsigned char *puc; // trama appDataSize = 5; appData[0] = confirmaRssi; //Ack leido en dispositivo appData[1] = confirmaSnr; appData[2] = confirmaDatarate; appData[3] = (uint8_t)batteryVoltage; appData[4] = (uint8_t)(batteryVoltage>>8); Serial.print("%, Bateria = "); Serial.println(batteryVoltage); }
LoRWan Recibe
//downlink data handle function example void downLinkDataHandle(McpsIndication_t *mcpsIndication) { // revisa parametros // Serial.print("\nLlegó un mensaje para dispositivo..."); // Serial.print("Rssi: "); // Serial.println(mcpsIndication->Rssi); // Serial.printf("+REV DATA:%s,RXSIZE %d,PORT %d\r\n", // mcpsIndication->RxSlot ? "RXWIN2" : "RXWIN1", // mcpsIndication->BufferSize, mcpsIndication->Port); // Serial.print("+REV DATA:"); // for (uint8_t i = 0; i < mcpsIndication->BufferSize; i++) { // Serial.printf("%02X", mcpsIndication->Buffer[i]); // } estado = uint8_t(mcpsIndication->Buffer[0]); Serial.print("uplink: rssi = -"); Serial.println(estado); Serial.println(); // uint32_t color = mcpsIndication->Buffer[0] << 16 | mcpsIndication->Buffer[1] << 8 | mcpsIndication->Buffer[2]; //#if (LoraWan_RGB == 1) // turnOnRGB(color, 5000); // turnOffRGB(); //#endif }
LoRaWan recibe confirma (Ack)
void downLinkAckHandle(McpsIndication_t *mcpsIndication){ confirmaRssi = uint8_t(abs(mcpsIndication->Rssi)); confirmaSnr = uint8_t(mcpsIndication->Snr); confirmaDatarate = uint8_t(mcpsIndication->RxDoneDatarate); //Serial.println(' '); //Serial.print(" ack received(rssi,snd,datarate): -"); //Serial.print(confirmaRssi);Serial.print(" ,"); //Serial.print(confirmaSnr);Serial.print(" ,"); //Serial.println(confirmaDatarate); }
4. LoRa Multipunto – HELTEC CubeCell SemiDuplex.ino con direcciones
Aunque se reciben todos los mensajes en el radio, se requiere discriminar los mensajes que son dirigidos hacia el dispositivo local.
Se modifica las intrucciones de recepción añadiendo un bloque para discriminar si el mensaje es para el dispositivo local. Esto implica descomponer la trama enviada en sus partes y convertir al tipo de dato a usar.
Las operaciones se realizan por caracter o byte con el objetivo de establecer el mecanismo a usar cuando se usa LoRaWan
Resultados obtenidos en puerto serial
TX Paquete "312159" , tamano 6 bytes , proximo en 9341 ms RX Paquete "213169" , tamanio 6, Rssi -20 Lee mensaje enviado por: 21 valor mensaje: 69 TX Paquete "312160" , tamano 6 bytes , proximo en 8062 ms RX Paquete "213170" , tamanio 6, Rssi -20 Lee mensaje enviado por: 21 valor mensaje: 70
Procedimiento de recepción de paquete LoRa
void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ) { turnOnRGB(COLOR_RECEIVED,0); Rssi = rssi; // nivel de recepcion rxSize = size; memcpy(rxpacket, payload, size ); rxpacket[size]='\0'; //añade fin de cadena Radio.Sleep( ); Serial.printf("\r RX Paquete \"%s\" , tamanio %d, Rssi %d \r\n", rxpacket,rxSize,Rssi); //revisa direcciones char envia[4]; byte dir_envia; char recibe[4]; byte dir_recibe; char msj[4]; byte msj_valor; envia[0] = rxpacket[0]; envia[1] = rxpacket[1]; envia[2] = '\0'; //añade fin de cadena recibe[0] = rxpacket[2]; recibe[1] = rxpacket[3]; recibe[2] = '\0'; //añade fin de cadena msj[0] = rxpacket[4]; msj[1] = rxpacket[5]; msj[2] = '\0'; //añade fin de cadena //convierte a tipo de datos dir_envia = byte(atoi(envia)); dir_recibe = byte(atoi(recibe)); msj_valor = byte(atoi(msj)); // Muestra o discrimina mensaje en Serial-USB/Pantalla if (dir_recibe = dir_local){ Serial.print(" -- Lee mensaje enviado por: "); Serial.print(dir_envia); Serial.print(" valor mensaje: "); Serial.println(msj_valor); } }
3. LoRa Multipunto – HELTEC CubeCell SemiDuplex.ino
Como cada dispositivo contiene solo un radio, la comunicación en dos sentidos puede habilitarse en modo SemiDuplex. Las funciones de transmisión y recepción se alternan.
Resultados
TX Paquete "213110" , tamano 6 bytes , proximo en 8118 ms RX Paquete "312139" , tamanio 6, Rssi -22 TX Paquete "213111" , tamano 6 bytes , proximo en 8429 ms RX Paquete "312140" , tamanio 6, Rssi -23 TX Paquete "213112" , tamano 6 bytes , proximo en 9397 ms
Instrucciones
/* LoRa TRANSMITE/RECIBE Semi Duplex / Half-Duplex * Referencia: https://github.com/HelTecAutomation/ASR650x-Arduino */ #include "LoRaWan_APP.h" #include "Arduino.h" #ifndef LoraWan_RGB // LED placa #define LoraWan_RGB 0 #endif // LoRa Parametros #define RF_FREQUENCY 915E6 // Hz #define TX_OUTPUT_POWER 14 // dBm #define LORA_BANDWIDTH 0 // [0: 125 kHz, 1: 250 kHz, // 2: 500 kHz, 3: Reserved] #define LORA_SPREADING_FACTOR 7 // [SF7..SF12] #define LORA_CODINGRATE 1 // [1: 4/5, 2: 4/6, // 3: 4/7, 4: 4/8] #define LORA_PREAMBLE_LENGTH 8 // Same for Tx and Rx #define LORA_SYMBOL_TIMEOUT 0 // Symbols #define LORA_FIX_LENGTH_PAYLOAD_ON false #define LORA_IQ_INVERSION_ON false #define RX_TIMEOUT_VALUE 1000 #define BUFFER_SIZE 30 // Define the payload size here char txpacket[BUFFER_SIZE]; // cadena de caracteres char rxpacket[BUFFER_SIZE]; static RadioEvents_t RadioEvents; void OnTxDone( void ); // Tx completada void OnTxTimeout( void ); // Tx fuera de tiempo void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ); byte modoOperacion = 0; // 0:RX 1:TX bool sleepMode = false; int16_t txNumero; int16_t Rssi,rxSize; // Direcciones por dispositivo byte dir_local = 21; // Dispositivo envia byte dir_destino = 31; // Dispositivo recibe // tiempo entre Tx de datos o lecturas de sensor long tiempo_antes = 0; long tiempo_intervalo = 7000; long tiempo_espera = tiempo_intervalo + random(3000); void setup() { Serial.begin(115200); txNumero=10; Rssi=0; RadioEvents.TxDone = OnTxDone; RadioEvents.TxTimeout = OnTxTimeout; RadioEvents.RxDone = OnRxDone; Radio.Init( &RadioEvents ); Radio.SetChannel( RF_FREQUENCY ); Radio.SetTxConfig( MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH, LORA_SPREADING_FACTOR, LORA_CODINGRATE, LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON, true, 0, 0, LORA_IQ_INVERSION_ON, 3000 ); Radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR, LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH, LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON, 0, true, 0, 0, LORA_IQ_INVERSION_ON, true ); modoOperacion=0; // 0:RX 1:TX 2:LOWPOWER } void loop(){ // Intervalos entre mensajes long tiempo_ahora = millis(); long t_transcurrido = tiempo_ahora - tiempo_antes; if (t_transcurrido >= tiempo_espera){ tiempo_antes = millis(); tiempo_espera = tiempo_intervalo + random(3000); modoOperacion=1; // 0:RX 1:TX }else{ modoOperacion=0; // 0:RX 1:TX } switch(modoOperacion) { // 0:RX 1:TX 2:LOWPOWER case 0: Radio.Rx( 0 ); modoOperacion=2; //LOWPOWER; break; case 1: delay(500); transmiteMsg(); modoOperacion=0; break; case 2: lowPowerHandler(); modoOperacion=0; break; default: break; } turnOnRGB(0,0); // LED apaga delay(100); Radio.IrqProcess( ); }
Procedimiento de transmisión de paquete LoRa
void transmiteMsg( void ) { turnOnRGB(COLOR_SEND,0); // LED de placa // Paquete a transmitir sprintf(txpacket,"%d",dir_local); sprintf(txpacket+strlen(txpacket),"%d",dir_destino); sprintf(txpacket+strlen(txpacket),"%d",txNumero); //añade número paquete a txpacket // Mensaje a pantalla Serial.printf("\rTX Paquete \"%s\" , tamano %d bytes\r", txpacket, strlen(txpacket)); Serial.printf("\r , proximo en %d ms \r\n", tiempo_espera); // Transmite paquete LoRa Radio.Send( (uint8_t *)txpacket, strlen(txpacket) ); txNumero = txNumero + 1; // cuenta paquete if (txNumero>=99){ txNumero = 0; // reinicia contador } modoOperacion=2;//LOWPOWER; } void OnTxDone( void ) { turnOnRGB(0,0); modoOperacion=0; } void OnTxTimeout( void ) { Radio.Sleep( ); Serial.println("TX Timeout......"); modoOperacion=1; }
Procedimiento de recepción de paquete LoRa
void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ) { turnOnRGB(COLOR_RECEIVED,0); Rssi = rssi; // nivel de recepcion rxSize = size; memcpy(rxpacket, payload, size ); rxpacket[size]='\0'; //añade fin de cadena Radio.Sleep( ); Serial.printf("\r RX Paquete \"%s\" , tamanio %d, Rssi %d \r\n", rxpacket,rxSize,Rssi); }
2.2 LoRa Multipunto – HELTEC CubeCell Transmisor.ino
Resultados
TX Paquete "213110" , tamano 6 bytes , proximo en 8118 ms TX Paquete "213111" , tamano 6 bytes , proximo en 8429 ms TX Paquete "213112" , tamano 6 bytes , proximo en 9397 ms
Instrucciones
/* TRANSMITE de Mensajes Heltec Automation send communication test example * Referencia: https://github.com/HelTecAutomation/ASR650x-Arduino */ #include "LoRaWan_APP.h" #include "Arduino.h" #ifndef LoraWan_RGB // LED placa #define LoraWan_RGB 0 #endif // LoRa Parametros #define RF_FREQUENCY 915E6 // Hz #define TX_OUTPUT_POWER 14 // dBm #define LORA_BANDWIDTH 0 // [0: 125 kHz, 1: 250 kHz, // 2: 500 kHz, 3: Reserved] #define LORA_SPREADING_FACTOR 7 // [SF7..SF12] #define LORA_CODINGRATE 1 // [1: 4/5, 2: 4/6, // 3: 4/7, 4: 4/8] #define LORA_PREAMBLE_LENGTH 8 // Same for Tx and Rx #define LORA_SYMBOL_TIMEOUT 0 // Symbols #define LORA_FIX_LENGTH_PAYLOAD_ON false #define LORA_IQ_INVERSION_ON false #define RX_TIMEOUT_VALUE 1000 #define BUFFER_SIZE 30 // Tamaño de paquete char txpacket[BUFFER_SIZE]; // cadena de caracteres char rxpacket[BUFFER_SIZE]; static RadioEvents_t RadioEvents; byte txNumero; int16_t Rssi,rxSize; // Direcciones por dispositivo byte dir_local = 31; // Dispositivo envia byte dir_destino = 21; // Dispositivo recibe // tiempo entre Tx de datos o lecturas de sensor long tiempo_antes = 0; long tiempo_intervalo = 7000; long tiempo_espera = tiempo_intervalo + random(3000); void setup() { Serial.begin(115200); txNumero=10; Rssi=0; Radio.Init( &RadioEvents ); Radio.SetChannel( RF_FREQUENCY ); Radio.SetTxConfig( MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH, LORA_SPREADING_FACTOR, LORA_CODINGRATE, LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON, true, 0, 0, LORA_IQ_INVERSION_ON, 3000 ); } void loop(){ // Intervalos entre mensajes long tiempo_ahora = millis(); long t_transcurrido = tiempo_ahora - tiempo_antes; if (t_transcurrido >= tiempo_espera){ transmiteMsg(); tiempo_antes = millis(); //actualiza tiempos tiempo_espera = tiempo_intervalo + random(3000); } }
Procedimiento de transmisión de paquete LoRa
void transmiteMsg( void ) { turnOnRGB(COLOR_SEND,0); // LED de placa // Paquete a transmitir sprintf(txpacket,"%d",dir_local); sprintf(txpacket+strlen(txpacket),"%d",dir_destino); sprintf(txpacket+strlen(txpacket),"%d",txNumero); //añade número paquete a txpacket // Mensaje a pantalla Serial.printf("\rTX Paquete \"%s\" , tamano %d bytes\r", txpacket, strlen(txpacket)); Serial.printf("\r , proximo en %d ms \r\n", tiempo_espera); // Transmite paquete LoRa Radio.Send( (uint8_t *)txpacket, strlen(txpacket) ); txNumero = txNumero + 1; // cuenta paquete if (txNumero>=99){ txNumero = 0; // reinicia contador } } void OnTxDone( void ) { turnOnRGB(0,0); } void OnTxTimeout( void ) { Radio.Sleep( ); Serial.println("TX Timeout......"); }