Ten poradnik jest częścią: Samouczki WiFi LoRa 32
Wszystkie filmy dotyczące Heltec WiFi LoRa 32 są powiązane w tej grupie. Linki do innych filmów znajdują się poniżej tego artykułu.
Używając Heltec WiFi LoRa 32 V3 do przesyłania temperatury za pomocą DHT22 na odległość 1,4 km
W tym samouczku dowiemy się, jak używać modułu Heltec WiFi LoRa 32 V3 do przesyłania danych temperatury z czujnika DHT22 na duże odległości, osiągając zasięg do 1,4 kilometra. Ta możliwość jest możliwa dzięki technologii LoRa, która umożliwia komunikację o niskim poborze mocy i dużym zasięgu. Po ukończeniu tego przewodnika będziesz mieć działający system, który może bezprzewodowo wysyłać odczyty temperatury.
Zaczniemy od przeglądu elementów sprzętowych zaangażowanych w ten projekt, w tym modułu Heltec WiFi LoRa 32 V3 i czujnika DHT22. Następnie przejdziemy do instrukcji okablowania, gdzie dowiesz się, jak połączyć te elementy. Na koniec omówimy kod wymagany do uruchomienia tego systemu. Aby uzyskać wskazówki wizualne, zapoznaj się z filmem w różnych znacznikach czasu (na filmie o 00:00).
Omówienie sprzętu
Głównymi elementami tego projektu są moduł Heltec WiFi LoRa 32 V3 oraz czujnik temperatury i wilgotności DHT22. Moduł Heltec wyposażony jest w mikrokontroler ESP32, który zapewnia możliwości Wi-Fi i Bluetooth wraz z komunikacją LoRa. Pozwala to na elastyczne opcje przesyłania danych.
Czujnik DHT22 to czujnik cyfrowy, który zapewnia dokładne odczyty temperatury i wilgotności. Komunikuje się z ESP32 przez pojedynczy cyfrowy pin wyjściowy, co ułatwia podłączenie i użycie w projektach. Razem te elementy tworzą solidny system do bezprzewodowego monitorowania temperatury.
Szczegóły z karty katalogowej
| Producent | Heltec Automation |
|---|---|
| Numer części | WiFi LoRa 32 V3 |
| Napięcie logiczne/IO | 3,3 V |
| Napięcie zasilania | 3,7–4,2 V |
| Prąd wyjściowy (na kanał) | ~1 A |
| Prąd szczytowy (na kanał) | ~2 A |
| Zalecana częstotliwość PWM | 1 kHz (typ.) |
| Progi logiczne wejścia | 0,7 V (wysoki), 0,3 V (niski) |
| Spadek napięcia / RDS(on) / nasycenie | 0,3 V (maks.) |
| Limity termiczne | 85 °C (maks.) |
| Obudowa | Moduł PCB |
| Uwagi / warianty | Dostępne różne opcje częstotliwości (np. 433 MHz, 868 MHz, 915 MHz) |
- Zasilaj DHT22 napięciem 3,3 V, a nie 5 V.
- Używaj odpowiednich poziomów logicznych do komunikacji między ESP32 a DHT22.
- Rozważ zastosowanie radiatora, jeśli urządzenie pracuje z wysokimi prądami przez dłuższy czas.
- Sprawdź połączenie anteny LoRa, aby zmaksymalizować zasięg.
- Zwracaj uwagę na przepisy dotyczące częstotliwości LoRa w swoim regionie.
Instrukcje okablowania

Aby podłączyć Heltec WiFi LoRa 32 V3 z czujnikiem DHT22, zacznij od podłączenia pinu VCC czujnika do pinu 3,3 V na module Heltec. Następnie podłącz pin GND czujnika DHT22 do jednego z pinów GND na module Heltec. Pin danych czujnika DHT22 należy podłączyć do pinu GPIO 3 na module Heltec.
Upewnij się, że używasz rezystora podciągającego (około 10kΩ) między pinem danych a VCC, aby uzyskać stabilne odczyty. Dodatkowo upewnij się, że antena LoRa jest bezpiecznie podłączona, aby zwiększyć zasięg transmisji. Jeśli używasz zewnętrznego zasilania, upewnij się, że moduł Heltec jest prawidłowo zasilany, aby uniknąć problemów operacyjnych.
Instalacja płytek Heltec ESP32
Dodaj tę ścieżkę do preferencji swojego Arduino IDE, jak pokazano na filmie:https://resource.heltec.cn/download/package_heltec_esp32_index.json
Instalacja bibliotek Heltec ESP32
W Arduino IDE po otwarciu kliknij ikonę Biblioteki (1), następnie wpisz "Heltec" w polu wyszukiwania (2) i kliknij Zainstaluj (3) — patrz obrazek.
Przykłady kodu i omówienie
Poniższe fragmenty kodu ilustrują, jak skonfigurować moduł Heltec do odczytu danych temperatury z czujnika DHT22 i przesyłania ich przez LoRa. Kod inicjalizuje wyświetlacz i konfiguruje czujnik DHT.
#include
#define DHTPIN 3 // Pin GPIO dla DHT22
#define DHTTYPE DHT22 // Zdefiniuj typ DHT
DHT dht(DHTPIN, DHTTYPE);
void setup() {
Serial.begin(115200);
dht.begin(); // Inicjalizacja czujnika DHT
}
W tym fragmencie definiujemy pin, do którego podłączony jest czujnik DHT22, i inicjalizujemy go w funkcji setup(). Linia Serial.begin(115200) służy do wypisywania danych debugowania.
void loop() {
float tempC = dht.readTemperature(); // Odczyt temperatury w stopniach Celsjusza
float tempF = dht.convertCtoF(tempC); // Konwersja na stopnie Fahrenheita
sendData(tempC, tempF); // Funkcja do wysyłania danych temperatury
}
Ten fragment pokazuje, jak odczytać dane temperatury w funkcji loop(). Funkcja sendData() jest wywoływana w celu przesłania odczytów temperatury przez LoRa.
void sendData(float tempC, float tempF) {
String data = "Temperatura: " + String(tempC) + "°C"; // Utwórz ciąg danych
Radio.Send(data.c_str(), data.length()); // Wyślij dane
}
Tutaj tworzymy ciąg danych zawierający temperaturę i wysyłamy go za pomocą metody Radio.Send(). Spowoduje to bezprzewodowe przesłanie danych do modułu odbiorczego.
Pełny kod znajduje się poniżej artykułu — zapoznaj się z nim, aby uzyskać szczegółową implementację.
Demonstracja / Czego się spodziewać
Po skonfigurowaniu wszystkiego i wgraniu kodu do modułu Heltec na ekranie OLED powinieneś zobaczyć odczyty temperatury. System będzie przesyłał dane temperatury, które mogą zostać odebrane przez inny moduł Heltec skonfigurowany do odczytu danych. Możesz przetestować zasięg, oddalając odbiornik od nadajnika, potwierdzając maksymalną osiągniętą odległość (na filmie w czasie 1:30).
Uważaj na typowe błędy, takie jak nieprawidłowe podłączenie, niewystarczające zasilanie lub użycie niewłaściwej częstotliwości LoRa. Upewnij się, że DHT22 działa poprawnie i że antena jest podłączona, aby zmaksymalizować zasięg.
Znaczniki czasu w filmie
- 00:00 Start
- 3:51 Specyfikacje
- 8:32 Strona dokumentacji
- 9:52 Zestaw i bateria
- 12:58 Pierwsze uruchomienie
- 16:37 Instalacja biblioteki
- 18:19 Podstawowy kod nadajnika
- 19:43 Podstawowy kod odbiornika
- 20:39 Demonstracja wysyłania i odbierania tekstu
- 23:02 Kod demonstracyjny OLED
- 24:06 Podstawowy kod tekstu na ekranie OLED
- 26:26 Podstawowa demonstracja tekstu na OLED
- 26:58 Odczyt temperatury za pomocą DHT22
- 28:49 Nadajnik LoRa — temperatura i wyświetlacz
- 30:07 Odbiornik LoRa — temperatura i wyświetlacz
- 32:13 Wyzwalanie diody LED przy wzroście temperatury
- 22:26 Test zasięgu transmisji LoRa
- 35:01 dBm i miliwaty
Ten poradnik jest częścią: Samouczki WiFi LoRa 32
- 13 Mil 20 km bez WiFi? Jak LoRa przesłało napięcie na szalone odległości! (Heltec WiFi LoRa 32 V3)
- Włącz urządzenie z odległości 13 mil (21 km) – Najlepszy projekt LoRa off-grid z WiFi LoRa 32!
- System zdalnego ostrzegania o otwarciu drzwi z odległości 13 mil (21 km) za pomocą LoRa – poza siecią! (Heltec WiFi LoRa 32 V3)
- Steruj serwomotorem z odległości kilometrów! Heltec WiFi LoRa 32 V3 Arduino Tutorial (TX)
- Projekt zdalnego przekaźnika DIY: Moduł Heltec LoRa 32 o zasięgu 13 mil bez Wi-Fi/bez 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);
}
/*
written on March 27, 2025
written by Ahmad Shamshiri for www.Robojax.com
Transmits Temperature and Humidity over LoRa RF using ESP32 LoRA 32 V3 module.
and displays the information on the screen.
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
#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, Humidity //only for display not for transmission
//4=F, Humidity //only for display not for transmission
//5=Humidity only
int dataType = 2;
String labelTemp = "Temperature";
String labelHumidity = "Humidity";
const int TX_POWER = 2;//dBm from 2 to 20. when powered via battery 2 to 14dBm is the best option
#include "mbedtls/aes.h"
#include <cstring> // For memset, memcpy
mbedtls_aes_context aes;
const char *userKey = "hyhT676#h~_876s"; //Security key.
#include "LoRaWan_APP.h"
#include "Arduino.h"
#define RF_FREQUENCY 915000000 // Hz
#define TX_OUTPUT_POWER TX_POWER // dBm from 2 to 20. when powered via battery 2 to 14dBm
#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];
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);
// Initialising the UI will init the display too.
display.init();
display.setFont(ArialMT_Plain_10);
dht.begin();
//LoRa stuff
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(); // Clear display before new content
// Line 1: "Temperature:" in 16pt font
display.setTextAlignment(TEXT_ALIGN_LEFT);
// Line 2: Temperature value in 24pt font
display.setFont(ArialMT_Plain_24);
// Format temperature with correct unit symbol
String tempStringC = String(tempC, 1) + "°C"; // 1 decimal place
String tempStringF = String(tempF, 1)+ "°F"; // 1 decimal place
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;; // default
}
display.display(); // Update 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 default OFF
{
pinMode(Vext,OUTPUT);
digitalWrite(Vext, HIGH);
}
void sendData()
{
String tempStringC = String(tempC, 1) + " °C"; // 1 decimal place
String tempStringF = String(tempF, 1)+ " °F"; // 1 decimal place
String tempStringHumidity = String(humidity)+ " % RH";
String txData;
//1=C
//2=F
//3=C, Humidity
//4=F, Humidity
//5=Humidity only
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)); // Zero-padding
strncpy((char*)data, txData.c_str(), sizeof(data) - 1); // Copy string safely
encryptAES(data, userKey); // Encrypt before sending
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();//read the data
// clear the display
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;
}
/**
* 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);
}
/*
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
Zasoby i odniesienia
-
Zewnętrzny
-
Zewnętrzny
-
Zewnętrzny
-
Zewnętrzny
-
ZewnętrznyPurchase a WiFi LoRa 32 V3 from AliExpresss.click.aliexpress.com
-
ZewnętrznyPurchase a WiFi LoRa 32 V3 from AliExpress-2s.click.aliexpress.com
-
Zewnętrzny
-
ZewnętrznyPurchase Wi-Fi LoRa 32 from Meshnologymeshnology.com
Pliki📁
Biblioteki Arduino (zip)
-
Heltec ESP32 libraries 2.1.5Libraries for all Heltec ESP32 boards. This is version 2.1.5.
Heltec_ESP32-master.zip3.86 MB
Inne pliki
-
Heltec WiFi LoRa 32 V3 Schematic Diagram (V3.1)
Heltec_WiFiLoRAV3_Schematic_Diagram.pdf0.18 MB