This tutorial is part of: WiFi LoRa 32 Tutorials
All videos related to Heltec WiFi LoRa 32 are related using this group. Links to other videos are below this article.
د هیلټیک WiFi LoRa 32 V3 په کارولو سره د تودوخې لیږدول د DHT22 په مرسته تر 1.4 کیلومتره پورې
په دې ټیوټوریل کې به موږ وپلټو چې څنګه د Heltec WiFi LoRa 32 V3 ماډل وکاروو ترڅو د DHT22 سینسر څخه د تودوخې معلومات په اوږدو واټنونو کې انتقال کړو، چې تر 1.4 کیلومترو پورې واټن ترلاسه کړو. دا وړتیا د LoRa ټیکنالوژۍ په کارولو سره ممکنه شوې ده، کوم چې د ټیټ بریښنا او اوږد واټن اړیکو ته اجازه ورکوي. د دې لارښود په پای کې به تاسو یو فعال سیسټم ولرئ چې کولی شي د تودوخې لوستل په بېسیم ډول واستوي.
موږ به د دې پروژې په اړوند هارډویر اجزاوو عمومي کتنې سره پیل وکړو، پشمول د Heltec WiFi LoRa 32 V3 ماډل او DHT22 سینسر. له هغې وروسته به موږ د تارونو د نښلولو لارښوونو ته لاړ شو، چیرې چې تاسو به زده کړئ چې دا اجزا څنګه وصل کړئ. په پای کې به موږ د دې سیسټم د فعالولو لپاره اړین کوډ ته ګام په ګام وګورو. د بصري لارښوونې لپاره، مهرباني وکړئ په مختلفو وختونو کې ویډیو ته مراجعه وکړئ (په ویډیو کې په 00:00).
هارډویر تشریح شوی
د دې پروژې اصلي اجزا د Heltec WiFi LoRa 32 V3 ماډل او د DHT22 تودوخې او رطوبت سینسر دي. د Heltec ماډل د ESP32 مایکروکنټرولر لري، کوم چې د LoRa اړیکو ترڅنګ د Wi-Fi او بلوتوث وړتیاوې چمتو کوي. دا د معلوماتو د لیږد لپاره انعطاف منونکي اختیارونه برابروي.
د DHT22 سینسر یو ډیجیټل سینسر دی چې د تودوخې او رطوبت دقیق لوستل چمتو کوي. دا د یو واحد ډیجیټل آوټ پټ پن له لارې له ESP32 سره اړیکه نیسي، چې دا ستاسو په پروژو کې د نښلولو او کارولو لپاره اسانه کوي. دا اجزا یوځای د بېسیم تودوخې څارنې لپاره یو پیاوړی سیسټم جوړوي.
ډیټاشیټ تفصیلات
| جوړونکی | Heltec Automation |
|---|---|
| د پرزې شمېره | WiFi LoRa 32 V3 |
| د منطق/IO ولټاژ | 3.3 V |
| د بریښنا رسولو ولټاژ | 3.7–4.2 V |
| د آوټ پټ جریان (په هر چینل) | ~1 A |
| د لوړ جریان (په هر چینل) | ~2 A |
| د PWM فریکونسي لارښود | 1 kHz (معمولي) |
| د منطق داخلیدو حدونه | 0.7 V (لوړ)، 0.3 V (ټیټ) |
| د ولټاژ کمښت / RDS(on) / سنتریشن | 0.3 V (اعظمي) |
| حرارتي حدونه | 85 °C (اعظمي) |
| بسته بندي | PCB ماډل |
| یادښتونه / ډولونه | مختلف فریکونسي اختیارونه شتون لري (د بیلګې په توګه، 433 MHz، 868 MHz، 915 MHz) |
- ډاډ ترلاسه کړئ چې DHT22 په 3.3V بریښنا سره چل کړئ، نه 5V.
- د ESP32 او DHT22 ترمنځ د اړیکو لپاره مناسب منطق کچې وکاروئ.
- که په لوړ جریان کې د اوږدې مودې لپاره چلئ، د تودوخې د خپرولو (heat-sinking) په اړه فکر وکړئ.
- د LoRa انټینا اړیکه وګورئ ترڅو واټن اعظمي کړئ.
- ستاسو په سیمه کې د LoRa فریکونسي مقرراتو ته پام وکړئ.
د تارونو د نښلولو لارښوونې

د Heltec WiFi LoRa 32 V3 د DHT22 سینسر سره د نښلولو لپاره، لومړی د سینسر VCC پن د Heltec ماډل په 3.3V پن سره وصل کړئ. بیا د DHT22 GND پن د Heltec په یو GND پن سره وصل کړئ. د DHT22 ډیټا پن باید د Heltec په GPIO پن 3 سره وصل شي.
ډاډ ترلاسه کړئ چې د ډیټا پن او VCC ترمنځ د پل-اپ ریزسټر (شاوخوا 10kΩ) وکاروئ ترڅو مستحکم لوستل ترلاسه شي. برسیره پردې، ډاډ ترلاسه کړئ چې د LoRa انټینا په خوندي ډول وصل ده ترڅو د لیږد واټن ښه کړي. که تاسو بهرنۍ بریښنا کاروئ، ډاډ ترلاسه کړئ چې د Heltec ماډل په سمه توګه بریښنا شوی ترڅو د عملیاتي ستونزو څخه مخنیوی وشي.
د Heltec ESP32 بورډونو نصبول
دا لاره د خپل Arduino IDE په غوره توبونو کې اضافه کړئ لکه څنګه چې په ویډیو کې ښودل شوې:https://resource.heltec.cn/download/package_heltec_esp32_index.json
د Heltec ESP32 کتابتونونو نصبول
کله چې Arduino IDE خلاص شي، مهرباني وکړئ د کتابتون آیکون (1) باندې کلیک وکړئ، بیا په لټون کې "Heltec" ولیکئ (2) او د نصبولو (3) باندې کلیک وکړئ، انځور وګورئ.
د کوډ مثالونه او ګام په ګام تشریح
لاندې کوډ ټوټې ښیي چې څنګه د Heltec ماډل تنظیم کړو ترڅو د DHT22 سینسر څخه د تودوخې معلومات ولولي او د LoRa له لارې یې انتقال کړي. کوډ ډسپلې پیل کوي او د DHT سینسر تنظیموي.
#include
#define DHTPIN 3 // د DHT22 لپاره GPIO پن
#define DHTTYPE DHT22 // د DHT ډول تعریف
DHT dht(DHTPIN, DHTTYPE);
void setup() {
Serial.begin(115200);
dht.begin(); // د DHT سینسر پیل کول
}
په دې ټوټه کې، موږ هغه پن تعریف کوو چې د DHT22 سینسر ورسره وصل دی او دا د setup() فنکشن کې پیل کوو. د Serial.begin(115200) کرښه د ډیبګ کولو آوټ پټ لپاره ده.
void loop() {
float tempC = dht.readTemperature(); // د تودوخې لوستل په سیلسیس کې
float tempF = dht.convertCtoF(tempC); // په فارنهایټ بدلول
sendData(tempC, tempF); // د تودوخې معلوماتو لیږلو لپاره فنکشن
}
دا اقتباس ښیي چې څنګه د loop() فنکشن کې د تودوخې معلومات ولولئ. د sendData() فنکشن د LoRa له لارې د تودوخې لوستلو لیږلو لپاره بلل کیږي.
void sendData(float tempC, float tempF) {
String data = "تودرجه: " + String(tempC) + "°C"; // د ډیټا سټرینګ جوړول
Radio.Send(data.c_str(), data.length()); // ډیټا لیږل
}
دلته، موږ د تودوخې په اړه ډیټا سټرینګ جوړوو او د Radio.Send() میتود په کارولو سره یې لیږو. دا به ډیټا په بېسیم ډول ترلاسه کونکي ماډل ته انتقال کړي.
مهرباني وکړئ د بشپړ تفصیلي پلي کولو لپاره هغه بشپړ کوډ ته مراجعه وکړئ چې د مقالې لاندې بار شوی دی.
ښودنه / څه تمه وکړو
یوځل چې هرڅه تنظیم شي او کوډ د Heltec ماډل ته پورته شي، تاسو باید د تودوخې لوستل د OLED سکرین پر مخ وګورئ. سیسټم به د تودوخې ډیټا انتقال کړي، کوم چې د بل Heltec ماډل لخوا ترلاسه کیدی شي چې د ډیټا لوستلو لپاره تنظیم شوی وي. تاسو کولی شئ د لیږدونکي څخه د ترلاسه کونکي په لرې کولو سره حد وازموئ، چې اعظمي فاصله تایید کړئ (په ویډیو کې په 1:30 کې).
د عامو ستونزو څخه محتاط اوسئ لکه غلط تارونه، ناکافي بریښنا رسول، یا د LoRa غلط فریکونسي کارول. ډاډ ترلاسه کړئ چې DHT22 په سمه توګه کار کوي او انټینا وصل دی ترڅو حد اعظمي شي.
د ویډیو وخت نښې
- 00:00 پیل
- 3:51 مشخصات
- 8:32 د اسنادو پاڼه
- 9:52 بسته او بیټرۍ
- 12:58 د لومړي ځل لپاره بریښنا ورکول
- 16:37 د کتابتون نصبول
- 18:19 د لیږدونکي اساسي کوډ
- 19:43 د ترلاسه کونکي اساسي کوډ
- 20:39 د متن لیږلو او ترلاسه کولو ښودنه
- 23:02 د OLED ډیمو کوډ
- 24:06 د OLED سکرین پر مخ اساسي متن کوډ
- 26:26 د OLED سکرین پر مخ اساسي متن ډیمو
- 26:58 د DHT22 سره د تودوخې لوستل
- 28:49 د LoRa لیږدونکی تودوخه او ښودنه
- 30:07 د LoRa ترلاسه کونکی تودوخه او ښودنه
- 32:13 د تودوخې د زیاتوالي پر مهال د LED فعالول
- 22:26 د LoRa لیږد حد ازموینه
- 35:01 dBm او ملی واټ
This tutorial is part of: WiFi LoRa 32 Tutorials
- 13 Miles 20km with NO WiFi? How LoRa Sent Voltage Across Crazy Distances! (Heltec WiFi LoRa 32 V3)
- Turn On a Device from 13 mile 21km Away – The Ultimate Off-Grid LoRa Project with WiFi LoRa 32!
- Remote Door Alert System from 13 mile 21 km Away With LoRa – Off the Grid! (Heltec WiFi LoRa 32 V3)
- Control a Servo motor from Miles Away! Heltec WiFi LoRa 32 V3 Arduino Tutorial (TX)
- DIY Remote Relay Project: 13 Mile No-Wi-Fi/No-SIM Heltec LoRa 32 Module
- 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
Resources & references
-
External
-
External
-
External
-
External
-
ExternalPurchase a WiFi LoRa 32 V3 from AliExpresss.click.aliexpress.com
-
ExternalPurchase a WiFi LoRa 32 V3 from AliExpress-2s.click.aliexpress.com
-
External
-
ExternalPurchase Wi-Fi LoRa 32 from Meshnologymeshnology.com
Files📁
Arduino Libraries (zip)
-
Heltec ESP32 libraries 2.1.5Libraries for all Heltec ESP32 boards. This is version 2.1.5.
Heltec_ESP32-master.zip3.86 MB
Other files
-
Heltec WiFi LoRa 32 V3 Schematic Diagram (V3.1)
Heltec_WiFiLoRAV3_Schematic_Diagram.pdf0.18 MB