Cerca codice

Utilizzando Heltec WiFi LoRa 32 V3 per trasmettere la temperatura utilizzando DHT22 fino a 1.4km

Questa lezione fa parte di: Introduzione al WiFi LoRa

Utilizzando Heltec WiFi LoRa 32 V3 per trasmettere la temperatura utilizzando DHT22 fino a 1.4km

In questo tutorial, esploreremo come utilizzare il modulo Heltec WiFi LoRa 32 V3 per trasmettere dati di temperatura da un sensore DHT22 su lunghe distanze, raggiungendo intervalli fino a 1,4 chilometri. Questa capacità è resa possibile grazie all'uso della tecnologia LoRa, che consente comunicazioni a bassa potenza e lunga distanza. Alla fine di questa guida, avrai un sistema funzionante in grado di inviare letture di temperatura in modalità wireless.

Wifi LoRa 32 V3 all'interno di Meshnology N30 RX e TX

Inizieremo con una panoramica dei componenti hardware coinvolti in questo progetto, incluso il modulo Heltec WiFi LoRa 32 V3 e il sensore DHT22. Dopo di che, procederemo con le istruzioni di cablaggio, dove imparerai come collegare questi componenti. Infine, esamineremo il codice necessario per rendere operativo questo sistema. Per una guida visiva, ti preghiamo di fare riferimento al video a vari timestamp (nel video a 00:00).

Hardware Spiegato

I componenti principali per questo progetto sono il modulo Heltec WiFi LoRa 32 V3 e il sensore di temperatura e umidità DHT22. Il modulo Heltec è dotato di un microcontrollore ESP32, che offre capacità Wi-Fi e Bluetooth insieme alla comunicazione LoRa. Questo consente opzioni di trasmissione dei dati flessibili.

Wifi LoRa 32 V3 all'interno di Meshnology N30 come trasmettitore di temperatura

Il sensore DHT22 è un sensore digitale che fornisce letture accurate di temperatura e umidità. Comunica con l'ESP32 attraverso un singolo pin di uscita digitale, rendendo facile la connessione e l'uso nei tuoi progetti. Insieme, questi componenti formano un sistema robusto per il monitoraggio della temperatura senza fili.

Dettagli della scheda tecnica

Fabbricante Heltec Automation
Numero di parte WiFi LoRa 32 V3
Tensione logica/IO 3.3 V
Tensione di alimentazione 3,7-4,2 V
Corrente di uscita (per canale) ~1 A
Corrente di picco (per canale) ~2 A
Guida sulla frequenza PWM 1 kHz (tip.)
Soglie logiche di ingresso 0,7 V (alto), 0,3 V (basso)
Caduta di tensione / RDS(on)/ saturazione 0,3 V (max)
Limiti termici 85 °C (max)
Pacchetto Modulo PCB
Note / varianti Varie opzioni di frequenza disponibili (ad es., 433 MHz, 868 MHz, 915 MHz)

  • Assicurati di alimentare il DHT22 con 3,3V, non con 5V.
  • Usa livelli logici appropriati per la comunicazione tra l'ESP32 e il DHT22.
  • Considera il raffreddamento se funzionando a correnti elevate per periodi prolungati.
  • Controlla la connessione dell'antenna per LoRa per massimizzare la portata.
  • Fai attenzione alle normative sulle frequenze LoRa nella tua regione.

Istruzioni di cablaggio

Heltec_WiFi_loRa_32V3_DHT22_wiring

Per collegare il Heltec WiFi LoRa 32 V3 con il sensore DHT22, inizia collegando il pin VCC del sensore al pin 3.3V del modulo Heltec. Successivamente, collega il pin GND del DHT22 a uno dei pin GND sul Heltec. Il pin dati del DHT22 dovrebbe essere collegato al pin GPIO 3 sul Heltec.

Assicurati di utilizzare una resistenza di pull-up (circa 10kΩ) tra il pin dei dati e VCC per letture stabili. Inoltre, assicurati che l'antenna LoRa sia collegata in modo sicuro per migliorare la gamma di trasmissione. Se stai utilizzando alimentazione esterna, assicurati che il modulo Heltec sia alimentato correttamente per evitare problemi operativi.

Installazione delle schede Heltec ESP32

Aggiungi questo percorso nelle preferenze del tuo Arduino IDE come mostrato nel video:https://resource.heltec.cn/download/package_heltec_esp32_index.json

Esempi di Codice e Guida passo-passo

I seguenti frammenti di codice illustrano come configurare il modulo Heltec per leggere i dati di temperatura dal sensore DHT22 e trasmetterli tramite LoRa. Il codice inizializza il display e configura il sensore 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
}

In questo frammento, definiamo il pin a cui è collegato il sensore DHT22 e lo inizializziamo nelsetup()funzione. IlSerial.begin(115200)la linea è per l'output di debug.

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
}

Questo estratto mostra come leggere i dati di temperatura nelloop()funzione. LasendData()viene chiamata la funzione per trasmettere le letture di temperatura tramite 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
}

Qui creiamo la stringa di dati contenente la temperatura e la inviamo usando ilRadio.Send()metodo. Questo trasmetterà i dati in modalità wireless al modulo ricevente.

Si prega di fare riferimento al codice completo caricato sotto l'articolo per un'implementazione dettagliata.

Dimostrazione / Cosa Aspettarsi

Una volta che tutto è configurato e il codice è caricato sul modulo Heltec, dovresti vedere le letture della temperatura visualizzate sullo schermo OLED. Il sistema trasmetterà i dati sulla temperatura, che possono essere ricevuti da un altro modulo Heltec configurato per leggere i dati. Puoi testare la portata spostando il ricevitore più lontano dal trasmettitore, confermando la distanza massima raggiunta (nel video a 1:30).

Fai attenzione ai comuni errori come cablaggi errati, alimentazione insufficiente o utilizzo della frequenza LoRa sbagliata. Assicurati che il DHT22 funzioni correttamente e che l'antenna sia collegata per massimizzare la portata.

Timestamp video

  • 00:00 Inizio
  • 3:51 Specifiche
  • 8:32 Pagina di documentazione
  • 9:52 Pacco e batteria
  • 12:58 Accendendolo per la prima volta
  • 16:37 Installazione della libreria
  • 18:19 Codice base del trasmettitore
  • 19:43 Codice di Base del Ricevitore
  • 20:39 Dimostrazione dell'invio e ricezione di testo
  • 23:02 codice demo OLED
  • 24:06 Testo di base sul codice del display OLED
  • 26:26 Testo base sulla demo OLED
  • 26:58 Lettura della temperatura con DHT22
  • 28:49 Temperatura e visualizzazione del trasmettitore LoRa
  • 30:07 Temperatura e visualizzazione del ricevitore LoRa
  • 32:13 Attivazione del LED quando la temperatura aumenta
  • 22:26 Test di Portata della Trasmissione LoRa
  • 35:01 dBm e Milli Watt

Immagini

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
Lingua: 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
Lingua: C++
/*
 * scritto il 27 marzo 2025  
 * scritto da Ahmad Shamshiri per www.Robojax.com  
 * Trasmette temperatura e umidità tramite RF LoRa usando il modulo ESP32 LoRA 32 V3.  
 * e visualizza le informazioni sullo schermo.  
 * Guarda la spiegazione video completa https://youtu.be/WkyQMXkQhE8  
 * Pagina delle risorse: 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); // indirizzo , frequenza , gruppo i2c , risoluzione , riavvio

#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, Umidità //solo per visualizzazione non per trasmissione
 // 4=F, Umidità //solo per visualizzazione non per trasmissione
 // 5=Solo umidità
int dataType = 2;
String labelTemp = "Temperature";
String labelHumidity = "Humidity";
const int TX_POWER = 2; // dBm da 2 a 20. quando alimentato a batteria, da 2 a 14dBm è la scelta migliore.

#include "mbedtls/aes.h"
#include <cstring> // Per memset, memcpy
mbedtls_aes_context aes;
const char *userKey = "hyhT676#h~_876s"; // Chiave di sicurezza.


#include "LoRaWan_APP.h"
#include "Arduino.h"


#define RF_FREQUENCY                                915000000 // Hz

#define TX_OUTPUT_POWER                             TX_POWER // dBm da 2 a 20. quando alimentato a batteria da 2 a 14dBm

#define LORA_BANDWIDTH                              0 // [0: 125 kHz,
 // 1: 250 kHz,
 // 2: 500 kHz,
 // 3: Riservato
#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 // Stesso per Tx e Rx
#define LORA_SYMBOL_TIMEOUT                         0 // Simboli
#define LORA_FIX_LENGTH_PAYLOAD_ON                  false
#define LORA_IQ_INVERSION_ON                        false


#define RX_TIMEOUT_VALUE                            1000
#define BUFFER_SIZE                                 30 // Definisci qui la dimensione del payload.

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'inizializzazione dell'interfaccia utente inizializzerà anche il display.
  display.init();

  display.setFont(ArialMT_Plain_10);
   dht.begin();

 // Materiale 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(); // Cancella il display prima del nuovo contenuto

 // Linea 1: "Temperatura:" in carattere 16pt
    display.setTextAlignment(TEXT_ALIGN_LEFT);


 // Linea 2: Valore della temperatura in font 24pt
    display.setFont(ArialMT_Plain_24);

 // Formato la temperatura con il simbolo di unità corretto.
    String tempStringC = String(tempC, 1) + "°C"; // 1 cifra decimale
    String tempStringF = String(tempF, 1)+ "°F"; // 1 cifra decimale
    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;; // predefinito
    }


    display.display(); // Aggiorna 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 predefinito OFF
{
  pinMode(Vext,OUTPUT);
  digitalWrite(Vext, HIGH);
}

void sendData()
{


    String tempStringC = String(tempC, 1) + " °C"; // 1 cifra decimale
    String tempStringF = String(tempF, 1)+ " °F"; // 1 cifra decimale
    String tempStringHumidity = String(humidity)+ " % RH";
    String txData;
 // 1=C
 // 2=F
 // 3=C, Umidità
 // 4=F, Umidità
 // 5=Solo umidità
        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); // Copia la stringa in modo sicuro

  encryptAES(data, userKey); // Crittografia prima di inviare
  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(); // leggi i dati

 // cancella il 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;
}


/*
 * Converte una chiave in formato testo fornita dall'utente in una chiave di lunghezza fissa di 16 byte (128 bit) o 32 byte (256 bit).
 */
void processKey(const char *userKey, uint8_t *processedKey, size_t keySize) {
    memset(processedKey, 0, keySize); // Riempi con zeri
    size_t len = strlen(userKey);
    if (len > keySize) len = keySize; // Tronca se troppo lungo
    memcpy(processedKey, userKey, len); // Copia la parte valida della chiave
}

/*
 * Cripta un messaggio di 16 byte (un blocco) usando AES-128.
 */
void encryptAES(uint8_t *data, const char *key) {
    uint8_t processedKey[16]; // chiave a 128 bit
    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);
}

/*
 * Decripta un messaggio di 16 byte (un blocco) utilizzando AES-128.
 */
void decryptAES(uint8_t *data, const char *key) {
    uint8_t processedKey[16]; // chiave a 128 bit
    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
Lingua: 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

File📁

Altri file