Este tutorial es parte de: Tutoriales de WiFi LoRa 32
Todos los videos relacionados con Heltec WiFi LoRa 32 se encuentran en este grupo. Los enlaces a otros videos se encuentran debajo de este artículo.
Usando Heltec WiFi LoRa 32 V3 para transmitir temperatura utilizando DHT22 hasta 1.4 km
En este tutorial, exploraremos cómo usar el módulo Heltec WiFi LoRa 32 V3 para transmitir datos de temperatura desde un sensor DHT22 a largas distancias, logrando alcances de hasta 1.4 kilómetros. Esta capacidad es posible gracias al uso de la tecnología LoRa, que permite una comunicación de bajo consumo y largo alcance. Al final de esta guía, tendrás un sistema operativo que puede enviar lecturas de temperatura de forma inalámbrica.
Comenzaremos con una visión general de los componentes de hardware involucrados en este proyecto, incluyendo el módulo Heltec WiFi LoRa 32 V3 y el sensor DHT22. Después de eso, procederemos a las instrucciones de cableado, donde aprenderás cómo conectar estos componentes. Por último, recorreremos el código necesario para hacer que este sistema sea operativo. Para orientación visual, consulta el video en varias marcas de tiempo (en video a las 00:00).
Hardware Explicado
Los componentes principales de este proyecto son el módulo Heltec WiFi LoRa 32 V3 y el sensor de temperatura y humedad DHT22. El módulo Heltec cuenta con un microcontrolador ESP32, que proporciona capacidades de Wi-Fi y Bluetooth, además de comunicación LoRa. Esto permite opciones flexibles de transmisión de datos.
El sensor DHT22 es un sensor digital que proporciona lecturas precisas de temperatura y humedad. Se comunica con el ESP32 a través de un solo pin de salida digital, lo que facilita su conexión y uso en tus proyectos. Juntos, estos componentes forman un sistema robusto para la monitorización inalámbrica de temperatura.
Detalles de la hoja de datos
| Fabricante | Heltec Automation |
|---|---|
| Número de pieza | WiFi LoRa 32 V3 |
| Voltaje de lógica/entrada/salida | 3.3 V |
| Tensión de suministro | 3.7-4.2 V |
| Corriente de salida (por canal) | ~1 A |
| Corriente pico (por canal) | ~2 A |
| Guía de frecuencia PWM | 1 kHz (típ.) |
| Umbrales de lógica de entrada | 0.7 V (alto), 0.3 V (bajo) |
| Caída de tensión / RDS(on)/ saturación | 0.3 V (máx) |
| Límites térmicos | 85 °C (máx) |
| Paquete | módulo PCB |
| Notas / variantes | Opciones de frecuencia disponibles (por ejemplo, 433 MHz, 868 MHz, 915 MHz) |
- Asegúrate de alimentar el DHT22 con 3.3V, no con 5V.
- Use niveles de lógica apropiados para la comunicación entre el ESP32 y el DHT22.
- Considere la disipación de calor si está funcionando a corrientes altas durante períodos prolongados.
- Verifique la conexión de la antena para LoRa para maximizar el alcance.
- Ten en cuenta las regulaciones de frecuencia de LoRa en tu región.
Instrucciones de cableado

Para conectar el Heltec WiFi LoRa 32 V3 con el sensor DHT22, comienza conectando el pin VCC del sensor al pin de 3.3V en el módulo Heltec. A continuación, conecta el pin GND del DHT22 a uno de los pines GND en el Heltec. El pin de datos del DHT22 debe estar conectado al pin GPIO 3 en el Heltec.
Asegúrate de usar una resistencia de pull-up (alrededor de 10kΩ) entre el pin de datos y VCC para obtener lecturas estables. Además, asegúrate de que la antena LoRa esté conectada de forma segura para mejorar el alcance de transmisión. Si estás utilizando energía externa, asegúrate de que el módulo Heltec esté alimentado correctamente para evitar problemas operativos.
Instalando placas Heltec ESP32
Agrega esta ruta en las preferencias de tu IDE de Arduino como se muestra en el video:https://resource.heltec.cn/download/package_heltec_esp32_index.json
Ejemplos de código y guía paso a paso
Los siguientes fragmentos de código ilustran cómo configurar el módulo Heltec para leer datos de temperatura del sensor DHT22 y transmitirlos a través de LoRa. El código inicializa la pantalla y configura el sensor DHT.
#include
#define DHTPIN 3 // GPIO pin for DHT22
#define DHTTYPE DHT22 // Define DHT type
DHT dht(DHTPIN, DHTTYPE);
void setup() {
Serial.begin(115200);
dht.begin(); // Initialize DHT sensor
}En este fragmento, definimos el pin al que está conectado el sensor DHT22 y lo inicializamos en elsetup()función. ElSerial.begin(115200)la línea es para la salida de depuración.
void loop() {
float tempC = dht.readTemperature(); // Read temperature in Celsius
float tempF = dht.convertCtoF(tempC); // Convert to Fahrenheit
sendData(tempC, tempF); // Function to send temperature data
}Este extracto muestra cómo leer datos de temperatura en elloop()función. ElsendData()se llama a la función para transmitir las lecturas de temperatura a través de LoRa.
void sendData(float tempC, float tempF) {
String data = "Temperature: " + String(tempC) + "°C"; // Create data string
Radio.Send(data.c_str(), data.length()); // Send data
}Aquí, creamos la cadena de datos que contiene la temperatura y la enviamos usando elRadio.Send()método. Esto transmitirá los datos de forma inalámbrica al módulo receptor.
Por favor, consulta el código completo cargado debajo del artículo para la implementación detallada.
Demostración / Qué Esperar
Una vez que todo esté configurado y el código esté cargado en el módulo Heltec, deberías ver las lecturas de temperatura mostradas en la pantalla OLED. El sistema transmitirá los datos de temperatura, que pueden ser recibidos por otro módulo Heltec configurado para leer los datos. Puedes probar el alcance moviendo el receptor más lejos del transmisor, confirmando la distancia máxima alcanzada (en el video a las 1:30).
Ten cuidado con los errores comunes como el cableado incorrecto, la fuente de alimentación insuficiente o el uso de la frecuencia LoRa equivocada. Asegúrate de que el DHT22 esté funcionando correctamente y de que la antena esté conectada para maximizar el alcance.
Tiempos de video
- 00:00 Comienzo
- 3:51 Especificaciones
- 8:32 Página de documentación
- 9:52 Paquete y batería
- 12:58 Encendiéndolo por primera vez
- 16:37 Instalando la biblioteca
- 18:19 Código básico del transmisor
- 19:43 Código Básico del Receptor
- 20:39 Demostración de envío y recepción de texto
- 23:02 Código de demostración OLED
- 24:06 Texto básico sobre el código de pantalla OLED
- 26:26 Texto básico sobre la demostración de OLED
- 26:58 Lectura de temperatura con DHT22
- 28:49 Temperatura del transmisor LoRa y pantalla
- 30:07 Temperatura y Pantalla del Receptor LoRa
- 32:13 Activar LED cuando la temperatura aumenta
- 22:26 Prueba de Rango de Transmisión LoRa
- 35:01 dBm y miliwatio
Este tutorial es parte de: Tutoriales de WiFi LoRa 32
- ¿13 millas 20 km sin WiFi? ¡Cómo LoRa envió voltaje a través de distancias locas! (Heltec WiFi LoRa 32 V3)
- Enciende un dispositivo a 13 millas (21 km) de distancia - ¡El proyecto off-grid definitivo de LoRa con WiFi LoRa 32!
- Sistema de Alerta de Puerta Remota desde 13 millas 21 km de distancia con LoRa - ¡Fuera de la Red! (Heltec WiFi LoRa 32 V3)
- ¡Controla un motor servo desde lejos! Tutorial de Arduino Heltec WiFi LoRa 32 V3 (TX)
- Proyecto de relé remoto DIY: módulo Heltec LoRa 32 de 13 millas sin Wi-Fi/sin SIM
- How to Use the Heltec LoRa CubeCell Development Board HTCC-AB01
/*
This is a simple code to display text on the OLED display
WiFi LoRa 32 V3 ESP32 module
Written by Ahmad Shamshiri 02 April 2025
Watch full video explanation https://youtu.be/WkyQMXkQhE8
Resources page https://robojax.com/tutorial_view.php?id=387
*/
#include <Wire.h>
#include "HT_SSD1306Wire.h"
static SSD1306Wire display(0x3c, 500000, SDA_OLED, SCL_OLED, GEOMETRY_128_64, RST_OLED); // addr , freq , i2c group , resolution , rst
void setup() {
Serial.begin(115200);
Serial.println();
Serial.println();
VextON();
delay(100);
// Initialising the UI will init the display too.
display.init();
display.setFont(ArialMT_Plain_10);
}
void displayTemperature(double temperature, int unit) {
display.clear(); // Clear display before new content
// Line 1: "Temperature:" in 16pt font
display.setTextAlignment(TEXT_ALIGN_LEFT);
display.setFont(ArialMT_Plain_16);
display.drawString(0, 0, "Temperature:");
// Line 2: Temperature value in 24pt font
display.setFont(ArialMT_Plain_24);
// Format temperature with correct unit symbol
String tempString = String(temperature, 1); // 1 decimal place
switch(unit) {
case 1: tempString += "�C"; break; // Celsius
case 2: tempString += "�F"; break; // Fahrenheit
default: tempString += "�U"; break; // Unknown unit
}
display.drawString(0, 20, tempString); // Display at Y=20 (below label)
display.display(); // Update OLED
}
void VextON(void)
{
pinMode(Vext,OUTPUT);
digitalWrite(Vext, LOW);
}
void VextOFF(void) //Vext default OFF
{
pinMode(Vext,OUTPUT);
digitalWrite(Vext, HIGH);
}
void loop() {
// clear the display
display.clear();
displayTemperature(23.5, 1); // Displays "23.5�C" /1
delay(2000);
}
/*
* escrito el 27 de marzo de 2025
* escrito por Ahmad Shamshiri para www.Robojax.com
* Transmite temperatura y humedad a través de LoRa RF utilizando el módulo ESP32 LoRA 32 V3.
* y muestra la información en la pantalla.
* Mira la explicación completa en video https://youtu.be/WkyQMXkQhE8
* Página de recursos: https://robojax.com/tutorial_view.php?id=387
*/
#include <Wire.h>
#include "HT_SSD1306Wire.h"
static SSD1306Wire display(0x3c, 500000, SDA_OLED, SCL_OLED, GEOMETRY_128_64, RST_OLED); // addr, frecuencia, grupo i2c, resolución, rst
#include <DHT.h>
#define DHTPIN 3 // GPIO21
#define DHTTYPE DHT22 // DHT22 (AM2302)
DHT dht(DHTPIN, DHTTYPE);
float tempC, tempF;
int humidity ;
// 1=C
// 2=F
// 3=C, Humedad //solo para visualización, no para transmisión
// 4=F, Humedad //solo para visualización, no para transmisión
// 5=Humedad solamente
int dataType = 2;
String labelTemp = "Temperature";
String labelHumidity = "Humidity";
const int TX_POWER = 2; // dBm de 2 a 20. cuando se alimenta por batería, de 2 a 14 dBm es la mejor opción.
#include "mbedtls/aes.h"
#include <cstring> // Para memset, memcpy
mbedtls_aes_context aes;
const char *userKey = "hyhT676#h~_876s"; // Clave de seguridad.
#include "LoRaWan_APP.h"
#include "Arduino.h"
#define RF_FREQUENCY 915000000 // Hz
#define TX_OUTPUT_POWER TX_POWER // dBm de 2 a 20. cuando se alimenta a través de batería de 2 a 14dBm
#define LORA_BANDWIDTH 0 // 125 kHz
// 250 kHz,
// 2: 500 kHz,
// 3: Reservado
#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 // Lo mismo para Tx y Rx.
#define LORA_SYMBOL_TIMEOUT 0 // Símbolos
#define LORA_FIX_LENGTH_PAYLOAD_ON false
#define LORA_IQ_INVERSION_ON false
#define RX_TIMEOUT_VALUE 1000
#define BUFFER_SIZE 30 // Define el tamaño de la carga aquí.
char txpacket[BUFFER_SIZE];
char rxpacket[BUFFER_SIZE];
double txNumber;
bool lora_idle=true;
static RadioEvents_t RadioEvents;
unsigned long lastTxTime = 0;
void OnTxDone( void );
void OnTxTimeout( void );
void decryptAES(uint8_t *data, const char *key);
void encryptAES(uint8_t *data, const char *key);
void processKey(const char *userKey, uint8_t *processedKey, size_t keySize);
void setup() {
Serial.begin(115200);
Serial.println();
VextON();
delay(100);
// Inicializar la interfaz de usuario también inicializará la pantalla.
display.init();
display.setFont(ArialMT_Plain_10);
dht.begin();
// Cosas de LoRa
Mcu.begin(HELTEC_BOARD,SLOW_CLK_TPYE);
txNumber=0;
RadioEvents.TxDone = OnTxDone;
RadioEvents.TxTimeout = OnTxTimeout;
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 displayTemperature(int unit) {
display.clear(); // Borrar la pantalla antes de nuevo contenido
// Línea 1: "Temperatura:" en fuente de 16 pt
display.setTextAlignment(TEXT_ALIGN_LEFT);
// Línea 2: Valor de temperatura en fuente de 24pt
display.setFont(ArialMT_Plain_24);
// Formatear la temperatura con el símbolo de unidad correcto
String tempStringC = String(tempC, 1) + "°C"; // 1 decimal lugar
String tempStringF = String(tempF, 1)+ "°F"; // 1 decimal lugar
String tempStringHumidity = String(humidity)+ "% RH";
String tempString;
switch(unit) {
case 1:
tempString =tempStringC;
display.setFont(ArialMT_Plain_16);
display.drawString(0, 0, "Temperature:");
display.setFont(ArialMT_Plain_24);
display.drawString(0, 15, tempString);
break; // Celsius
case 2: tempString =tempStringF;
display.setFont(ArialMT_Plain_16);
display.drawString(0, 0, "Temperature:");
display.setFont(ArialMT_Plain_24);
display.drawString(0, 15, tempString);
break; // Fahrenheit
case 3: tempString =tempStringC;
display.setFont(ArialMT_Plain_16);
display.drawString(0, 0, "Temperature:");
display.setFont(ArialMT_Plain_24);
display.drawString(0, 15, tempString);
display.setFont(ArialMT_Plain_16);
display.drawString(0, 40, "Humidity:");
display.drawString(70, 40, tempStringHumidity);
break; // Celsius
case 4: tempString =tempStringF;
display.setFont(ArialMT_Plain_16);
display.drawString(0, 0, "Temperature:");
display.setFont(ArialMT_Plain_24);
display.drawString(0, 15, tempString);
display.setFont(ArialMT_Plain_16);
display.drawString(0, 40, "Humidity:");
display.drawString(70, 40, tempStringHumidity );
break; // Celsius
case 5:
display.setFont(ArialMT_Plain_16);
display.drawString(0, 0, "Humidity:");
display.setFont(ArialMT_Plain_24);
display.drawString(0, 20, tempStringHumidity);
break; // Celsius
default: tempString =tempStringC + "°C"; break;; // predeterminado
}
display.display(); // Actualizar OLED
}
void readSensor()
{
tempC = dht.readTemperature();
humidity = dht.readHumidity();
tempF = dht.convertCtoF(tempC);
}
void VextON(void)
{
pinMode(Vext,OUTPUT);
digitalWrite(Vext, LOW);
}
void VextOFF(void) // Vext por defecto DESACTIVADO
{
pinMode(Vext,OUTPUT);
digitalWrite(Vext, HIGH);
}
void sendData()
{
String tempStringC = String(tempC, 1) + " °C"; // 1 decimal lugar
String tempStringF = String(tempF, 1)+ " °F"; // 1 decimal lugar
String tempStringHumidity = String(humidity)+ " % RH";
String txData;
// 1=C
// 2=F
// 3=C, Humedad
// 4=F, Humedad
// 5=Humedad solamente
switch(dataType) {
case 1:
txData = labelTemp + " " + tempStringC;
break;
case 2:
txData = labelTemp + " " + tempStringF;
break;
case 3:
txData = labelHumidity + " " + tempStringHumidity;
break;
default:
txData = labelTemp + " " + tempStringC;
break;
}
uint8_t data[32];
memset(data, 0, sizeof(data)); // Relleno con ceros
strncpy((char*)data, txData.c_str(), sizeof(data) - 1); // Copiar cadena de forma segura
encryptAES(data, userKey); // Cifre antes de enviar
if(lora_idle == true)
{
delay(1000);
Radio.Send(data, sizeof(data));
Serial.print("Sending: ");
Serial.println((char *)data);
lora_idle = false;
}
Radio.IrqProcess( );
}
void loop() {
readSensor(); // lee los datos
// borrar la pantalla
display.clear();
displayTemperature(dataType);
sendData();
delay(100);
}
void OnTxDone( void )
{
Serial.println("TX done......");
lora_idle = true;
}
void OnTxTimeout( void )
{
Radio.Sleep( );
Serial.println("TX Timeout......");
lora_idle = true;
}
/*
* Convierte una clave en texto plano proporcionada por el usuario en una clave de longitud fija de 16 bytes (128 bits) o 32 bytes (256 bits).
*/
void processKey(const char *userKey, uint8_t *processedKey, size_t keySize) {
memset(processedKey, 0, keySize); // Rellenar con ceros
size_t len = strlen(userKey);
if (len > keySize) len = keySize; // Truncar si es demasiado largo
memcpy(processedKey, userKey, len); // Copiar parte de la clave válida
}
/*
* Cifra un mensaje de 16 bytes (un bloque) utilizando AES-128.
*/
void encryptAES(uint8_t *data, const char *key) {
uint8_t processedKey[16]; // clave de 128 bits
processKey(key, processedKey, 16);
mbedtls_aes_init(&aes);
mbedtls_aes_setkey_enc(&aes, processedKey, 128);
mbedtls_aes_crypt_ecb(&aes, MBEDTLS_AES_ENCRYPT, data, data);
mbedtls_aes_free(&aes);
}
/*
* Descifra un mensaje de 16 bytes (un bloque) utilizando AES-128.
*/
void decryptAES(uint8_t *data, const char *key) {
uint8_t processedKey[16]; // clave de 128 bits
processKey(key, processedKey, 16);
mbedtls_aes_init(&aes);
mbedtls_aes_setkey_dec(&aes, processedKey, 128);
mbedtls_aes_crypt_ecb(&aes, MBEDTLS_AES_DECRYPT, data, data);
mbedtls_aes_free(&aes);
}
/*
Written on April 01, 2025
written by Ahmad Shamshiri for www.Robojax.com
this sktech receives the secure temperature or humidity from WiFi LoRa 32 and decrypts it
and displays it on the OLED. There is action feature to triggerd if the temperature is below triggerdValue
Watch full video explaination https://youtu.be/WkyQMXkQhE8
Resources page: https://robojax.com/tutorial_view.php?id=387
*/
#include <Arduino.h>
// Alert configuration
const String triggerdText = "Too High"; // Correct String type
const float triggerdValue = 90.0f; // exclusive (this value is not included)
const int triggerdYpos = 45;
const bool triggerdType = true;//true is > (greter than triggerdValue) and false is < (less than triggerdValue)
const int triggerdOutputPin = 7;//GPIO07 goes HIGH when triggered
const bool triggerdBlink4Me= true;//should blink or not
#include "mbedtls/aes.h"
#include <cstring> // For memset, memcpy
mbedtls_aes_context aes;
const char *userKey = "hyhT676#h~_876s"; //Security key
#define MIN_RSSI -120 // Worst possible signal
#define MAX_RSSI -50 // Best possible signal
// For a connection via I2C using the Arduino Wire include:
#include <Wire.h>
#include "HT_SSD1306Wire.h"
static SSD1306Wire display(0x3c, 500000, SDA_OLED, SCL_OLED, GEOMETRY_128_64, RST_OLED); // addr , freq , i2c group , resolution , rst
#include "LoRaWan_APP.h"
#include "Arduino.h"
#define RF_FREQUENCY 915000000 // 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];
char rxpacket[BUFFER_SIZE];
static RadioEvents_t RadioEvents;
int16_t txNumber;
int16_t rssi,rxSize;
bool lora_idle = true;
unsigned long lastRxTime = 0;
const unsigned long SIGNAL_TIMEOUT = 5000; // 5 seconds
void decryptAES(uint8_t *data, const char *key);
void encryptAES(uint8_t *data, const char *key);
void processKey(const char *userKey, uint8_t *processedKey, size_t keySize);
void setup() {
Serial.begin(115200);
Serial.println();
Serial.println();
VextON();
delay(100);
// Initialising the UI will init the display too.
display.init();
display.setFont(ArialMT_Plain_10);
pinMode(triggerdOutputPin, OUTPUT);
//LoRa stuff blow this line
Mcu.begin(HELTEC_BOARD,SLOW_CLK_TPYE);
txNumber=0;
rssi=0;
RadioEvents.RxDone = OnRxDone;
Radio.Init( &RadioEvents );
Radio.SetChannel( RF_FREQUENCY );
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 );
}
void displayTemperature(String data1, String data2) {
display.clear(); // Clear display before new content
// Line 1: "Temperature:" in 16pt font
display.setTextAlignment(TEXT_ALIGN_LEFT);
display.setFont(ArialMT_Plain_16);
display.drawString(0, 0, data1);
// Line 2: Temperature value in 24pt font
display.setFont(ArialMT_Plain_24);
display.drawString(0, 20, data2); //
displaySignalStrength(rssi);
// display.display(); // Update OLED
}
void displayLine(String data, int y) {
// Line 1: "Temperature:" in 16pt font
display.setTextAlignment(TEXT_ALIGN_LEFT);
display.setFont(ArialMT_Plain_10);
if (triggerdBlink4Me) {
// Blink effect: Display text, wait, clear text, wait, then return
display.drawString(0, y, data);
display.display();
delay(500); // Keep text visible for 500ms
display.clear(); // Clear the screen
display.display();
delay(500); // Keep screen blank for 500ms
}
else {
// Normal display without blinking
display.drawString(0, y, data);
display.display();
}
}
void VextON(void)
{
pinMode(Vext,OUTPUT);
digitalWrite(Vext, LOW);
}
void VextOFF(void) //Vext default OFF
{
pinMode(Vext,OUTPUT);
digitalWrite(Vext, HIGH);
}
void loop() {
RaIrqProcessdio( );
if(lora_idle)
{
lora_idle = false;
Serial.println("into RX mode");
Radio.Rx(0);
}
noSignalCheck();
delay(100);
}
void displaySignalStrength(int16_t rssi) {
// Convert RSSI to percentage (0-100%)
int percent = map(constrain(rssi, MIN_RSSI, MAX_RSSI), MIN_RSSI, MAX_RSSI, 0, 100);
// Display at bottom right corner
display.setTextAlignment(TEXT_ALIGN_RIGHT);
display.setFont(ArialMT_Plain_16);
// Create signal strength indicator
String strength = String(percent) + "% [";
for (int i = 0; i < 5; i++) {
strength += (percent > (i * 20)) ? "|" : " ";
}
strength += "]";
display.drawString(128, 45, strength); // Position at bottom-right
}
void noSignalCheck()
{
// Automatic "No Signal" after timeout
if (millis() - lastRxTime > SIGNAL_TIMEOUT) {
display.clear();
display.setTextAlignment(TEXT_ALIGN_CENTER);
display.setFont(ArialMT_Plain_16);
display.drawString(64, 20, "No Signal");
display.display();
}
}
/**
* Triggers an action based on a threshold comparison.
*
* @param type - If true, triggers when floatValue **exceeds** triggerdValue.
* If false, triggers when floatValue **falls below** triggerdValue.
* @param floatValue - The current measured value to compare.
* @param triggerdValue - The threshold value that determines the trigger condition.
*/
void triggerAction(float floatValue)
{
if(triggerdType)
{
if (floatValue > triggerdValue) {
displayLine(triggerdText, triggerdYpos);
Serial.println(triggerdText);
digitalWrite(triggerdOutputPin, HIGH);//turns triggerdOutputPin to HIGH
}else{
digitalWrite(triggerdOutputPin, LOW);
}
}else{
if (floatValue < triggerdValue) {
displayLine(triggerdText, triggerdYpos);
Serial.println(triggerdText);
digitalWrite(triggerdOutputPin, HIGH);//turns triggerdOutputPin to HIGH
} else{
digitalWrite(triggerdOutputPin, LOW);//turns triggerdOutputPin to LOW
}
}
}
void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr )
{
lastRxTime = millis(); // Reset timer on new data
rssi=rssi;
rxSize=size;
memcpy(rxpacket, payload, size );
rxpacket[size]='\0';
Radio.Sleep( );
Serial.printf("\r\nreceived packet \"%s\" with rssi %d , length %d\r\n",rxpacket,rssi,rxSize);
// Serial.println("Encrypted Data (Hex):");
// for (int i = 0; i < 16; i++) {
// Serial.printf("%02X ", rxpacket[i]);
// }
// Serial.println();
decryptAES((uint8_t *)rxpacket, userKey);
// Split the received packet into parts
String receivedStr = String((char*)rxpacket);
int firstSpacePos = receivedStr.indexOf(' ');
if (firstSpacePos != -1) {
// First part (before first space)
String part1 = receivedStr.substring(0, firstSpacePos); // "Temperature"
// Find second space (after the number)
int secondSpacePos = receivedStr.indexOf(' ', firstSpacePos + 1);
if (secondSpacePos != -1) {
// Second part (numeric value)
String part2 = receivedStr.substring(firstSpacePos + 1, secondSpacePos); // "34.5"
float floatValue = part2.toFloat(); // Convert to float 34.5
// Third part (unit)
String part3 = receivedStr.substring(secondSpacePos + 1); // "°C"
displayTemperature(part1, part2+part3);
display.display();
Serial.print("part1: " + part1);
Serial.print(" part2: " + part2);
Serial.println(" part3: " + part3);
Serial.println("floatValue " + String(floatValue));
//to trigger an action.
triggerAction(floatValue);
} else {
Serial.println("No second space found for unit");
}
}else {
Serial.println("No space found in packet - can't split");
}
lora_idle = true;
}
/**
* Converts a user-provided plaintext key into a fixed-length 16-byte (128-bit)
* or 32-byte (256-bit) key.
*/
void processKey(const char *userKey, uint8_t *processedKey, size_t keySize) {
memset(processedKey, 0, keySize); // Fill with zeros
size_t len = strlen(userKey);
if (len > keySize) len = keySize; // Truncate if too long
memcpy(processedKey, userKey, len); // Copy valid key part
}
/**
* Encrypts a 16-byte (one block) message using AES-128.
*/
void encryptAES(uint8_t *data, const char *key) {
uint8_t processedKey[16]; // 128-bit key
processKey(key, processedKey, 16);
mbedtls_aes_init(&aes);
mbedtls_aes_setkey_enc(&aes, processedKey, 128);
mbedtls_aes_crypt_ecb(&aes, MBEDTLS_AES_ENCRYPT, data, data);
mbedtls_aes_free(&aes);
}
/**
* Decrypts a 16-byte (one block) message using AES-128.
*/
void decryptAES(uint8_t *data, const char *key) {
uint8_t processedKey[16]; // 128-bit key
processKey(key, processedKey, 16);
mbedtls_aes_init(&aes);
mbedtls_aes_setkey_dec(&aes, processedKey, 128);
mbedtls_aes_crypt_ecb(&aes, MBEDTLS_AES_DECRYPT, data, data);
mbedtls_aes_free(&aes);
}
Common Course Links
Common Course Files
Recursos y referencias
-
Externo
-
Externo
-
Externo
-
Externo
-
ExternoCompra Wi-Fi LoRa 32 de Meshnologymeshnology.com
Archivos📁
Otros archivos
-
Diagrama esquemático de Heltec WiFi LoRa 32 V3 (V3.1)
Heltec_WiFiLoRAV3_Schematic_Diagram.pdf0.18 MB