Ce tutoriel fait partie de: Tutoriels WiFi LoRa 32
Toutes les vidéos relatives au routeur Heltec WiFi LoRa 32 sont regroupées ici. Vous trouverez des liens vers d'autres vidéos ci-dessous.
Utilisation du Heltec WiFi LoRa 32 V3 pour transmettre la température avec un DHT22 sur 1,4 km.
Dans ce tutoriel, nous allons explorer comment utiliser le module Heltec WiFi LoRa 32 V3 pour transmettre des données de température depuis un capteur DHT22 sur de longues distances, atteignant des portées allant jusqu'à 1,4 kilomètre. Cette capacité est rendue possible grâce à l'utilisation de la technologie LoRa, qui permet une communication à faible consommation d'énergie et longue portée. À la fin de ce guide, vous disposerez d'un système fonctionnel capable d'envoyer des relevés de température sans fil.
Nous commencerons par un aperçu des composants matériels impliqués dans ce projet, y compris le module Heltec WiFi LoRa 32 V3 et le capteur DHT22. Ensuite, nous passerons aux instructions de câblage, où vous apprendrez comment connecter ces composants. Enfin, nous passerons en revue le code nécessaire pour rendre ce système opérationnel. Pour des conseils visuels, veuillez vous référer à la vidéo à divers moments (dans la vidéo à 00:00).
Matériel expliqué
Les principaux composants de ce projet sont le module Heltec WiFi LoRa 32 V3 et le capteur de température et d'humidité DHT22. Le module Heltec est doté d'un microcontrôleur ESP32, qui offre des fonctionnalités Wi-Fi et Bluetooth en plus de la communication LoRa. Cela permet des options de transmission de données flexibles.
Le capteur DHT22 est un capteur numérique qui fournit des mesures précises de température et d'humidité. Il communique avec l'ESP32 par le biais d'une seule broche de sortie numérique, ce qui le rend facile à connecter et à utiliser dans vos projets. Ensemble, ces composants forment un système robuste pour la surveillance sans fil de la température.
Détails de la fiche technique
| Fabricant | Heltec Automation |
|---|---|
| Numéro de pièce | WiFi LoRa 32 V3 |
| Tension logique/IO | 3,3 V |
| Tension d'alimentation | 3,7-4,2 V |
| Courant de sortie (par canal) | ~1 A |
| Courant de crête (par canal) | ~2 A |
| Directives sur la fréquence PWM | 1 kHz (typ.) |
| Seuils logiques d'entrée | 0,7 V (haut), 0,3 V (bas) |
| Chute de tension / RDS(on)/ saturation | 0,3 V (max) |
| Limites thermiques | 85 °C (max) |
| Emballage | module PCB |
| Remarques / variantes | Différentes options de fréquence disponibles (par exemple, 433 MHz, 868 MHz, 915 MHz) |
- Assurez-vous d'alimenter le DHT22 avec 3,3 V, pas 5 V.
- Utilisez des niveaux logiques appropriés pour la communication entre l'ESP32 et le DHT22.
- Considérez le dissipateur de chaleur si vous fonctionnez à des courants élevés pendant de longues périodes.
- Vérifiez la connexion de l'antenne pour LoRa afin de maximiser la portée.
- Soyez conscient des réglementations sur la fréquence LoRa dans votre région.
Instructions de câblage

Pour câbler le Heltec WiFi LoRa 32 V3 avec le capteur DHT22, commencez par connecter la broche VCC du capteur à la broche 3.3V du module Heltec. Ensuite, connectez la broche GND du DHT22 à l'une des broches GND sur le Heltec. La broche de données du DHT22 doit être connectée à la broche GPIO 3 sur le Heltec.
Assurez-vous d'utiliser une résistance de tirage (environ 10kΩ) entre la broche de données et VCC pour des lectures stables. De plus, assurez-vous que l'antenne LoRa est correctement connectée pour améliorer la portée de transmission. Si vous utilisez une alimentation externe, assurez-vous que le module Heltec est alimenté correctement pour éviter tout problème de fonctionnement.
Installation des cartes Heltec ESP32
Ajoutez ce chemin dans les préférences de votre Arduino IDE comme montré dans la vidéo :https://resource.heltec.cn/download/package_heltec_esp32_index.json
Exemples de code et guide étape par étape
Les extraits de code suivants illustrent comment configurer le module Heltec pour lire les données de température du capteur DHT22 et les transmettre via LoRa. Le code initialise l'affichage et configure le capteur 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
}Dans cet extrait, nous définissons la broche à laquelle le capteur DHT22 est connecté et l'initialisons dans lesetup()function. LeSerial.begin(115200)la ligne est destinée à la sortie de débogage.
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
}Cet extrait montre comment lire les données de température dans leloop()fonction. LesendData()la fonction est appelée pour transmettre les relevés de température via 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
}Ici, nous créons la chaîne de données contenant la température et l'envoyons en utilisant leRadio.Send()méthode. Cela transmettra les données sans fil au module récepteur.
Veuillez vous référer au code complet chargé ci-dessous l'article pour une mise en œuvre détaillée.
Démonstration / À quoi s'attendre
Une fois que tout est configuré et que le code est téléchargé sur le module Heltec, vous devriez voir les relevés de température affichés sur l'écran OLED. Le système transmettra les données de température, qui peuvent être reçues par un autre module Heltec configuré pour lire les données. Vous pouvez tester la portée en éloignant le récepteur de l'émetteur, confirmant ainsi la distance maximale atteinte (dans la vidéo à 1:30).
Faites attention aux pièges courants tels qu'un câblage incorrect, une alimentation insuffisante ou l'utilisation d'une mauvaise fréquence LoRa. Assurez-vous que le DHT22 fonctionne correctement et que l'antenne est connectée pour maximiser la portée.
Horodatages vidéo
- 00:00 Début
- 3:51 Caractéristiques
- 8:32 Page de documentation
- 9:52 Paquet et batterie
- 12:58 Mise sous tension pour la première fois
- 16:37 Installation de la bibliothèque
- 18:19 Code de base du transmetteur
- 19:43 Code de Base du Récepteur
- 20:39 Démonstration de l'envoi et de la réception de textes
- 23:02 code de démonstration OLED
- 24:06 Texte de base sur le code d'affichage OLED
- 26:26 Texte de base sur la démo OLED
- 26:58 Lecture de la température avec DHT22
- 28:49 Température et affichage du transmetteur LoRa
- 30:07 Température et affichage du récepteur LoRa
- 32:13 Déclenchement de la LED lorsque la température augmente
- 22:26 Test de portée de transmission LoRa
- 35:01 dBm et Milli Watt
Ce tutoriel fait partie de: Tutoriels WiFi LoRa 32
- 13 miles 20 km sans WiFi ? Comment LoRa a envoyé des tensions à travers des distances incroyables ! (Heltec WiFi LoRa 32 V3)
- Allumez un appareil à 21 km (13 miles) de distance - Le projet LoRa hors réseau ultime avec WiFi LoRa 32 !
- Système d'alerte de porte à distance à 21 km (13 miles) avec LoRa - Hors réseau ! (Heltec WiFi LoRa 32 V3)
- Contrôlez un moteur servo à des kilomètres de distance ! Tutoriel Arduino Heltec WiFi LoRa 32 V3 (TX)
- Projet de relais à distance DIY : module Heltec LoRa 32 sans Wi-Fi/sans SIM sur 13 miles
- 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);
}
/*
* écrit le 27 mars 2025
* écrit par Ahmad Shamshiri pour www.Robojax.com
* Transmet la température et l'humidité via LoRa RF en utilisant le module ESP32 LoRA 32 V3.
* et affiche les informations à l'écran.
* Regardez l'explication vidéo complète https://youtu.be/WkyQMXkQhE8
* Page des ressources : 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, groupe i2c, résolution, 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, Humidité //uniquement pour affichage, pas pour transmission
// 4=F, Humidité //uniquement pour affichage pas pour transmission
// 5=Humidité seulement
int dataType = 2;
String labelTemp = "Temperature";
String labelHumidity = "Humidity";
const int TX_POWER = 2; // dBm de 2 à 20. lorsqu'il est alimenté par batterie, 2 à 14 dBm est la meilleure option.
#include "mbedtls/aes.h"
#include <cstring> // Pour memset, memcpy
mbedtls_aes_context aes;
const char *userKey = "hyhT676#h~_876s"; // Clé de sécurité.
#include "LoRaWan_APP.h"
#include "Arduino.h"
#define RF_FREQUENCY 915000000 // Hz
#define TX_OUTPUT_POWER TX_POWER // dBm de 2 à 20. lorsqu'il est alimenté par batterie de 2 à 14 dBm
#define LORA_BANDWIDTH 0 // 125 kHz
// 1 : 250 kHz,
// 2 : 500 kHz,
// 3 : Réservé
#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 // Même pour Tx et Rx
#define LORA_SYMBOL_TIMEOUT 0 // Symboles
#define LORA_FIX_LENGTH_PAYLOAD_ON false
#define LORA_IQ_INVERSION_ON false
#define RX_TIMEOUT_VALUE 1000
#define BUFFER_SIZE 30 // Définissez la taille de la charge utile ici.
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);
// L'initialisation de l'interface utilisateur va également initialiser l'affichage.
display.init();
display.setFont(ArialMT_Plain_10);
dht.begin();
// Des trucs 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(); // Effacer l'affichage avant le nouveau contenu
// Ligne 1 : "Température :" en police de 16pt
display.setTextAlignment(TEXT_ALIGN_LEFT);
// Ligne 2 : Valeur de température en police de 24pt
display.setFont(ArialMT_Plain_24);
// Formattez la température avec le symbole d'unité correct.
String tempStringC = String(tempC, 1) + "°C"; // 1 décimale
String tempStringF = String(tempF, 1)+ "°F"; // 1 décimale
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;; // par défaut
}
display.display(); // Mettre à jour 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 par défaut OFF
{
pinMode(Vext,OUTPUT);
digitalWrite(Vext, HIGH);
}
void sendData()
{
String tempStringC = String(tempC, 1) + " °C"; // 1 décimale
String tempStringF = String(tempF, 1)+ " °F"; // 1 décimale
String tempStringHumidity = String(humidity)+ " % RH";
String txData;
// 1=C
// 2=F
// 3=C, Humidité
// 4=F, Humidité
// 5=Humidité seulement
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); // Copiez la chaîne en toute sécurité
encryptAES(data, userKey); // Chiffrez avant d'envoyer
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(); // lire les données
// effacer l'affichage
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;
}
/*
* Convertit une clé en texte clair fournie par l'utilisateur en une clé de longueur fixe de 16 octets (128 bits) ou de 32 octets (256 bits).
*/
void processKey(const char *userKey, uint8_t *processedKey, size_t keySize) {
memset(processedKey, 0, keySize); // Remplir avec des zéros
size_t len = strlen(userKey);
if (len > keySize) len = keySize; // Raccourcir si trop long
memcpy(processedKey, userKey, len); // Copier la partie clé valide
}
/*
* Crypte un message de 16 octets (un bloc) en utilisant AES-128.
*/
void encryptAES(uint8_t *data, const char *key) {
uint8_t processedKey[16]; // clé 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);
}
/*
* Décrypte un message de 16 octets (un bloc) en utilisant AES-128.
*/
void decryptAES(uint8_t *data, const char *key) {
uint8_t processedKey[16]; // clé 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
Ressources et références
-
ExterneAcheter le Wi-Fi LoRa 32 auprès de Meshnologymeshnology.com
-
Externe
-
Externe
-
Externe
-
Externe
Fichiers📁
Autres fichiers
-
Schéma de câblage Heltec WiFi LoRa 32 V3 (V3.1)
Heltec_WiFiLoRAV3_Schematic_Diagram.pdf0.18 MB