Suchcode

Verwendung des Heltec WiFi LoRa 32 V3 zur Übertragung der Temperatur mittels DHT22 über 1,4 km

Diese Lektion ist Teil von: Einführung in WiFi LoRa

Verwendung des Heltec WiFi LoRa 32 V3 zur Übertragung der Temperatur mittels DHT22 über 1,4 km

In diesem Tutorial werden wir untersuchen, wie man das Heltec WiFi LoRa 32 V3-Modul verwendet, um Temperaturdaten von einem DHT22-Sensor über lange Strecken zu übertragen und Reichweiten von bis zu 1,4 Kilometern zu erreichen. Diese Fähigkeit wird durch den Einsatz von LoRa-Technologie ermöglicht, die eine energieeffiziente Kommunikation über große Entfernungen erlaubt. Am Ende dieses Leitfadens werden Sie ein funktionierendes System haben, das Temperaturmessungen drahtlos senden kann.

Wifi LoRa 32 V3 innerhalb von Meshnology N30 RX und TX

Wir werden mit einem Überblick über die Hardwarekomponenten beginnen, die in diesem Projekt verwendet werden, einschließlich des Heltec WiFi LoRa 32 V3 Moduls und des DHT22 Sensors. Danach werden wir zu den Verkabelungsanleitungen übergehen, in denen Sie lernen werden, wie Sie diese Komponenten verbinden. Schließlich werden wir den Code durchgehen, der erforderlich ist, um dieses System betriebsbereit zu machen. Für visuelle Unterstützung beziehen Sie sich bitte auf das Video zu verschiedenen Zeitstempeln (im Video bei 00:00).

Hardware erklärt

Die Hauptkomponenten für dieses Projekt sind das Heltec WiFi LoRa 32 V3 Modul und der DHT22 Temperatur- und Feuchtigkeitssensor. Das Heltec Modul verfügt über einen ESP32 Mikrocontroller, der WLAN- und Bluetooth-Funktionen sowie LoRa-Kommunikation bietet. Dies ermöglicht flexible Datenübertragungsoptionen.

Wifi LoRa 32 V3 innerhalb von Meshnology N30 als Temperatursender

Der DHT22-Sensor ist ein digitaler Sensor, der genaue Temperatur- und Feuchtigkeitsmessungen liefert. Er kommuniziert mit dem ESP32 über einen einzelnen digitalen Ausgangspin, was die Verbindung und Verwendung in Ihren Projekten erleichtert. Zusammen bilden diese Komponenten ein robustes System zur drahtlosen Temperaturüberwachung.

Technische Datenblatt Einzelheiten

Hersteller Heltec Automation
Teilenummer WiFi LoRa 32 V3
Logik/IO-Spannung 3,3 V
Versorgungsspannung 3,7-4,2 V
Ausgangsstrom ( pro Kanal) ~1 A
Spitzenstrom (pro Kanal) ~2 A
PWM-Frequenzanleitung 1 kHz (Typ.)
Eingangslogikschwellen 0,7 V (hoch), 0,3 V (niedrig)
Spannungsabfall / RDS(on)/ Sättigung 0,3 V (max)
Thermische Grenzen 85 °C (max)
Paket PCB-Modul
Anmerkungen / Varianten Verschiedene Frequenzoptionen verfügbar (z. B. 433 MHz, 868 MHz, 915 MHz)

  • Stellen Sie sicher, dass der DHT22 mit 3,3 V und nicht mit 5 V betrieben wird.
  • Verwenden Sie geeignete Logikpegel für die Kommunikation zwischen dem ESP32 und dem DHT22.
  • Berücksichtigen Sie die Wärmeableitung, wenn Sie über längere Zeiträume bei hohen Strömen betreiben.
  • Überprüfen Sie die Antennenverbindung für LoRa, um die Reichweite zu maximieren.
  • Achten Sie auf die LoRa-Frequenzvorschriften in Ihrer Region.

Verdrahtungsanweisungen

Heltec_WiFi_loRa_32V3_DHT22_wiring

Um den Heltec WiFi LoRa 32 V3 mit dem DHT22-Sensor zu verdrahten, beginnen Sie damit, den VCC-Pin des Sensors mit dem 3,3V-Pin des Heltec-Moduls zu verbinden. Verbinden Sie als Nächstes den GND-Pin des DHT22 mit einem der GND-Pins am Heltec. Der Datenpin des DHT22 sollte mit dem GPIO-Pin 3 am Heltec verbunden werden.

Stellen Sie sicher, dass Sie einen Pull-Up-Widerstand (ca. 10 kΩ) zwischen dem Datenpin und VCC verwenden, um stabile Messwerte zu erhalten. Stellen Sie außerdem sicher, dass die LoRa-Antenne sicher angeschlossen ist, um die Reichweite der Übertragung zu verbessern. Wenn Sie externe Stromversorgung verwenden, stellen Sie sicher, dass das Heltec-Modul korrekt mit Strom versorgt wird, um Betriebsprobleme zu vermeiden.

Installation der Heltec ESP32-Boards

Fügen Sie diesen Pfad in die Einstellungen Ihrer Arduino IDE ein, wie im Video gezeigt:https://resource.heltec.cn/download/package_heltec_esp32_index.json

Codebeispiele und Anleitung

Die folgenden Codeausschnitte zeigen, wie man das Heltec-Modul einrichtet, um Temperaturdaten vom DHT22-Sensor zu lesen und sie über LoRa zu übertragen. Der Code initialisiert das Display und richtet den DHT-Sensor ein.

#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 diesem Snippet definieren wir den Pin, an den der DHT22-Sensor angeschlossen ist, und initialisieren ihn in dersetup()Funktion. DieSerial.begin(115200)Diese Zeile dient der Debugging-Ausgabe.

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
}

Dieser Auszug zeigt, wie man Temperaturdaten in derloop()Funktion. DiesendData()Die Funktion wird aufgerufen, um die Temperaturmesswerte über LoRa zu übertragen.

void sendData(float tempC, float tempF) {
  String data = "Temperature: " + String(tempC) + "°C"; // Create data string
  Radio.Send(data.c_str(), data.length()); // Send data
}

Hier erstellen wir die Datenzeichenfolge, die die Temperatur enthält, und senden sie mit demRadio.Send()Methode. Dies wird die Daten drahtlos an das Empfangsmodul übermitteln.

Bitte beziehen Sie sich auf den vollständigen Code, der unter dem Artikel geladen ist, für eine detaillierte Implementierung.

Demonstration / Was zu erwarten ist

Sobald alles eingerichtet ist und der Code auf das Heltec-Modul hochgeladen wurde, sollten die Temperaturwerte auf dem OLED-Bildschirm angezeigt werden. Das System überträgt die Temperaturdaten, die von einem anderen Heltec-Modul empfangen werden können, das so konfiguriert ist, dass es die Daten liest. Sie können die Reichweite testen, indem Sie den Empfänger weiter vom Sender entfernen und die maximale erreichte Entfernung bestätigen (im Video bei 1:30).

Seien Sie vorsichtig bei häufigen Fallstricken wie falscher Verkabelung, unzureichender Stromversorgung oder der Verwendung der falschen LoRa-Frequenz. Stellen Sie sicher, dass der DHT22 ordnungsgemäß funktioniert und dass die Antenne angeschlossen ist, um die Reichweite zu maximieren.

Video-Zeitstempel

  • 00:00 Start
  • 3:51 Spezifikationen
  • 8:32 Dokumentationsseite
  • 9:52 Paket und Batterie
  • 12:58 Zum ersten Mal einschalten
  • 16:37 Bibliothek installieren
  • 18:19 Sender Grundcode
  • 19:43 Empfänger Grundcode
  • 20:39 Demonstration des Sendens und Empfangens von Text
  • 23:02 OLED-Democode
  • 24:06 Basistext zum OLED-Displaycode
  • 26:26 Basistext zur OLED-Demo
  • 26:58 Temperaturmessung mit DHT22
  • 28:49 LoRa-Sender-Temperatur und Anzeige
  • 30:07 LoRa-Empfänger-Temperatur und Anzeige
  • 32:13 Auslösen der LED bei Temperaturerhöhung
  • 22:26 LoRa Übertragungsreichweite-Test
  • 35:01 dBm und Milli Watt

Bilder

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
Sprache: 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
Sprache: C++
/*
 * geschrieben am 27. März 2025  
 * geschrieben von Ahmad Shamshiri für www.Robojax.com  
 * Überträgt Temperatur und Luftfeuchtigkeit über LoRa RF mit dem ESP32 LoRA 32 V3 Modul.  
 * und zeigt die Informationen auf dem Bildschirm an.  
 * Siehe vollständige Videoerklärung https://youtu.be/WkyQMXkQhE8  
 * Ressourcenseite: 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-Gruppe, Auflösung, 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, Feuchtigkeit //nur zur Anzeige, nicht für die Übertragung
 // 4=F, Luftfeuchtigkeit //nur zur Anzeige, nicht zur Übertragung
 // 5=Nur Luftfeuchtigkeit
int dataType = 2;
String labelTemp = "Temperature";
String labelHumidity = "Humidity";
const int TX_POWER = 2; // dBm von 2 bis 20. Bei Stromversorgung über Batterie ist 2 bis 14 dBm die beste Option.

#include "mbedtls/aes.h"
#include <cstring> // Für memset, memcpy
mbedtls_aes_context aes;
const char *userKey = "hyhT676#h~_876s"; // Sicherheitsschlüssel.


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


#define RF_FREQUENCY                                915000000 // Hz

#define TX_OUTPUT_POWER                             TX_POWER // dBm von 2 bis 20. bei Batterieversorgung 2 bis 14 dBm

#define LORA_BANDWIDTH                              0 // [0: 125 kHz,
 // 250 kHz,
 // 2: 500 kHz,
 // 3: Reserviert
#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 // Das Gleiche gilt für Tx und Rx.
#define LORA_SYMBOL_TIMEOUT                         0 // Symbole
#define LORA_FIX_LENGTH_PAYLOAD_ON                  false
#define LORA_IQ_INVERSION_ON                        false


#define RX_TIMEOUT_VALUE                            1000
#define BUFFER_SIZE                                 30 // Definieren Sie hier die Payload-Größe.

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);

 // Die Initialisierung der Benutzeroberfläche wird auch das Display initialisieren.
  display.init();

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

 // LoRa Zeug
  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(); // Anzeige vor neuem Inhalt löschen

 // Zeile 1: "Temperatur:" in 16pt Schriftgröße
    display.setTextAlignment(TEXT_ALIGN_LEFT);


 // Zeile 2: Temperaturwert in 24pt Schriftart
    display.setFont(ArialMT_Plain_24);

 // Temperatur mit dem richtigen Einheitssymbol formatieren
    String tempStringC = String(tempC, 1) + "°C"; // 1 Dezimalstelle
    String tempStringF = String(tempF, 1)+ "°F"; // 1 Dezimalstelle
    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;; // Standard
    }


    display.display(); // OLED aktualisieren
}

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 standardmäßig AUS
{
  pinMode(Vext,OUTPUT);
  digitalWrite(Vext, HIGH);
}

void sendData()
{


    String tempStringC = String(tempC, 1) + " °C"; // 1 Dezimalstelle
    String tempStringF = String(tempF, 1)+ " °F"; // 1 Dezimalstelle
    String tempStringHumidity = String(humidity)+ " % RH";
    String txData;
 // 1=C
 // 2=F
 // 3=C, Luftfeuchtigkeit
 // 4=F, Luftfeuchtigkeit
 // 5=Nur Luftfeuchtigkeit
        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)); // Nullauffüllung
  strncpy((char*)data, txData.c_str(), sizeof(data) - 1); // Kopiere Zeichenfolge sicher

  encryptAES(data, userKey); // Vor dem Senden verschlüsseln
  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(); // Daten lesen

 // Anzeige löschen
  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;
}


/*
 * Konvertiert einen vom Benutzer bereitgestellten Klartextschlüssel in einen festen 16-Byte (128-Bit) oder 32-Byte (256-Bit) Schlüssel.
 */
void processKey(const char *userKey, uint8_t *processedKey, size_t keySize) {
    memset(processedKey, 0, keySize); // Mit Nullen auffüllen
    size_t len = strlen(userKey);
    if (len > keySize) len = keySize; // Trunkiere, wenn zu lang
    memcpy(processedKey, userKey, len); // Kopieren Sie den gültigen Schlüsselteil
}

/*
 * Verschlüsselt eine 16-Byte (ein Block) Nachricht mit AES-128.
 */
void encryptAES(uint8_t *data, const char *key) {
    uint8_t processedKey[16]; // 128-Bit-Schlüssel
    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);
}

/*
 * Entschlüsselt eine 16-Byte (ein Block) Nachricht mit AES-128.
 */
void decryptAES(uint8_t *data, const char *key) {
    uint8_t processedKey[16]; // 128-Bit-Schlüssel
    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
Sprache: C++
/*
 * Geschrieben am 01. April 2025  
 * geschrieben von Ahmad Shamshiri für www.Robojax.com  
 * Diese Skizze empfängt die sichere Temperatur oder Luftfeuchtigkeit von WiFi LoRa 32 und entschlüsselt sie  
 * und zeigt sie auf dem OLED an. Es gibt eine Aktionsfunktion, die ausgelöst wird, wenn die Temperatur unter triggeredValue liegt.  
 * Sieh dir das vollständige Video mit Erklärungen an: https://youtu.be/WkyQMXkQhE8  
 * Ressourcenseite: https://robojax.com/tutorial_view.php?id=387
 */
#include <Arduino.h>
 // Alarmkonfiguration
const String triggerdText = "Too High"; // Korrekte Zeichenfolgentyp
const float triggerdValue = 90.0f; // exklusiv (dieser Wert ist nicht enthalten)
const int triggerdYpos = 45;
const bool triggerdType = true; // wahr ist > (größer als triggerdValue) und falsch ist < (kleiner als triggerdValue)
const int triggerdOutputPin = 7; // GPIO07 wird aktiviert, wenn es ausgelöst wird.
const bool triggerdBlink4Me= true; // soll blinken oder nicht

#include "mbedtls/aes.h"
#include <cstring> // Für memset, memcpy
mbedtls_aes_context aes;
const char *userKey = "hyhT676#h~_876s"; // Sicherheitsschlüssel

#define MIN_RSSI -120 // Schlechtestmöglicher Signal
#define MAX_RSSI -50 // Bestmögliches Signal


 // Für eine Verbindung über I2C unter Verwendung der Arduino Wire-Bibliothek:
#include <Wire.h>
#include "HT_SSD1306Wire.h"

static SSD1306Wire  display(0x3c, 500000, SDA_OLED, SCL_OLED, GEOMETRY_128_64, RST_OLED); // addr, freq, i2c-Gruppe, Auflösung, 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: Reserviert
#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 // Gleich für Tx und Rx
#define LORA_SYMBOL_TIMEOUT                         0 // Symbole
#define LORA_FIX_LENGTH_PAYLOAD_ON                  false
#define LORA_IQ_INVERSION_ON                        false


#define RX_TIMEOUT_VALUE                            1000
#define BUFFER_SIZE                                 30 // Definieren Sie hier die Payload-Größe.

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 Sekunden

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);

 // Die Initialisierung der Benutzeroberfläche wird auch das Display initialisieren.
  display.init();

  display.setFont(ArialMT_Plain_10);
  pinMode(triggerdOutputPin, OUTPUT);
 // LoRa-Sachen unter dieser Linie
     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(); // Anzeige vor neuem Inhalt löschen

 // Temperatur: in 16pt Schriftgröße
    display.setTextAlignment(TEXT_ALIGN_LEFT);
    display.setFont(ArialMT_Plain_16);
    display.drawString(0, 0, data1);

 // Zeile 2: Temperaturwert in 24pt Schriftgröße
    display.setFont(ArialMT_Plain_24);
    display.drawString(0, 20, data2);
    displaySignalStrength(rssi);
 // display.display(); // OLED aktualisieren


}

void displayLine(String data, int y) {
 // Temperatur: in 16pt Schriftgröße
    display.setTextAlignment(TEXT_ALIGN_LEFT);
    display.setFont(ArialMT_Plain_10);

    if (triggerdBlink4Me) {
 // Blink-Effekt: Text anzeigen, warten, Text löschen, warten, dann zurückkehren
        display.drawString(0, y, data);
        display.display();
        delay(500); // Halte den Text für 500 ms sichtbar

        display.clear(); // Bildschirm löschen
        display.display();
        delay(500); // Halte den Bildschirm für 500 ms schwarz.
    }
    else {
 // Normale Anzeige ohne Blinken
        display.drawString(0, y, data);
        display.display();
    }
}


void VextON(void)
{
  pinMode(Vext,OUTPUT);
  digitalWrite(Vext, LOW);
}

void VextOFF(void) // Vext standardmäßig AUS
{
  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) {
 // Konvertiere RSSI in Prozentsatz (0-100%)
    int percent = map(constrain(rssi, MIN_RSSI, MAX_RSSI), MIN_RSSI, MAX_RSSI, 0, 100);

 // Anzeige in der unteren rechten Ecke
    display.setTextAlignment(TEXT_ALIGN_RIGHT);
    display.setFont(ArialMT_Plain_16);

 // Erstellen Sie einen Signalstärkeindikator
    String strength = String(percent) + "% [";
    for (int i = 0; i < 5; i++) {
        strength += (percent > (i * 20)) ? "|" : " ";
    }
    strength += "]";

    display.drawString(128, 45, strength); // Position unten rechts
}

void noSignalCheck()
{
 // Automatische "Kein Signal" nach Zeitüberschreitung
    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();
    }
}

/*
 * Löst eine Aktion basierend auf einem Schwellenwertvergleich aus.
 * 
 * @param type - Wenn wahr, wird ausgelöst, wenn floatValue **überschreitet** triggerdValue. Wenn falsch, wird ausgelöst, wenn floatValue **unter** triggerdValue **fällt**. 
 * @param floatValue - Der aktuell gemessene Wert, der verglichen werden soll. 
 * @param triggerdValue - Der Schwellenwert, der die Auslösebedingung bestimmt.
 */
void triggerAction(float floatValue)
{
  if(triggerdType)
  {
    if (floatValue > triggerdValue) {
        displayLine(triggerdText, triggerdYpos);
        Serial.println(triggerdText);
        digitalWrite(triggerdOutputPin, HIGH); // setzt triggeredOutputPin auf HIGH
    }else{
        digitalWrite(triggerdOutputPin, LOW);
    }
  }else{
    if (floatValue < triggerdValue) {
        displayLine(triggerdText, triggerdYpos);
        Serial.println(triggerdText);
        digitalWrite(triggerdOutputPin, HIGH); // setzt triggeredOutputPin auf HIGH
    } else{
        digitalWrite(triggerdOutputPin, LOW); // setzt den triggerdOutputPin auf LOW
    }
  }
}
void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr )
{
    lastRxTime = millis(); // Zurücksetzen des Timers bei neuen Daten
    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("Verschlüsselte Daten (Hex):");
 // für (int i = 0; i < 16; i++) {
 // Serial.printf("%02X ", rxpacket[i]);
 // }
 // Serial.println();
   decryptAES((uint8_t *)rxpacket, userKey);

 // Teilen Sie das empfangene Paket in Teile.
    String receivedStr = String((char*)rxpacket);
    int firstSpacePos = receivedStr.indexOf(' ');
    if (firstSpacePos != -1) {
 // Erster Teil (vor dem ersten Leerzeichen)
        String part1 = receivedStr.substring(0, firstSpacePos); // Temperatur

 // Finde den zweiten Raum (nach der Zahl)
        int secondSpacePos = receivedStr.indexOf(' ', firstSpacePos + 1);

        if (secondSpacePos != -1) {
 // Zweiter Teil (numerischer Wert)
            String part2 = receivedStr.substring(firstSpacePos + 1, secondSpacePos); // 34,5
            float floatValue = part2.toFloat(); // In Float umwandeln 34,5

 // Dritter Teil (Einheit)
            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));

 // eine Aktion auszulösen.
        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;
}

/*
 * Konvertiert einen vom Benutzer bereitgestellten Klartextschlüssel in einen Schüssel mit fester Länge von 16 Byte (128-Bit) oder 32 Byte (256-Bit).
 */
void processKey(const char *userKey, uint8_t *processedKey, size_t keySize) {
    memset(processedKey, 0, keySize); // Mit Nullen füllen
    size_t len = strlen(userKey);
    if (len > keySize) len = keySize; // Abschneiden, wenn zu lang
    memcpy(processedKey, userKey, len); // Kopiere gültigen Schlüsselteil
}

/*
 * Verschlüsselt eine 16-Byte (ein Block) Nachricht mit AES-128.
 */
void encryptAES(uint8_t *data, const char *key) {
    uint8_t processedKey[16]; // 128-Bit-Schlüssel
    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);
}

/*
 * Dekodiert eine 16-Byte (ein Block) Nachricht mit AES-128.
 */
void decryptAES(uint8_t *data, const char *key) {
    uint8_t processedKey[16]; // 128-Bit-Schlüssel
    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

Dateien📁

Andere Dateien