Code de recherche

Utilisation du Heltec WiFi LoRa 32 V3 pour transmettre la température avec un DHT22 sur 1,4 km.

Cette leçon fait partie de: Introduction au WiFi LoRa

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.

Wifi LoRa 32 V3 à l'intérieur de Meshnology N30 RX et TX

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.

Wifi LoRa 32 V3 à l'intérieur de Meshnology N30 en tant qu'émetteur de température

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

Heltec_WiFi_loRa_32V3_DHT22_wiring

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

Images

Heltec_WiFi_loRa_32V3_DHT22_wiring
Heltec_WiFi_loRa_32V3_DHT22_wiring
Wifi LoRa 32 V3 inside Meshnology N30 as transmitter of Temperature
Wifi LoRa 32 V3 inside Meshnology N30 as transmitter of Temperature
meshnology-N30-LoRa-v3-red-black
meshnology-N30-LoRa-v3-red-black
Wifi LoRa 32 V3 inside Meshnology N30 RX and TX
Wifi LoRa 32 V3 inside Meshnology N30 RX and TX
563-Printing Simple Text on the screen of WiFi LoRa 32 V3
Langue: C++
/*
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);

}
773-Transmitter Code for Heltec WiFi LoRa 32 V3 to send temperature using DHT11, DHT22
Langue: C++
/*
 * é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);
}
867-Receiver Code for Heltec WiFi LoRa 32 to receive and display Temperature
Langue: C++
/*
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 Files

Fichiers📁

Autres fichiers