Communications LoRa cryptées

Bonjour.

Système d'exploitation : Windows 10 Pro (64-bit)
Version de l'IDE Arduino : 1.8.5

Dans le cadre de ma licence en LP Supervision des Automatismes et des Réseaux, je fais actuellement un projet visant à étudier la technologie LoRa, c'est un protocole de communication similaire à la 3G/4G (détails ici).

Je travaille avec des modules ESP32 de type Wifi_LoRa_32 avec un écran OLED : Détails du produit

Il faut que je réalise un réseau avec ces modules. Ils doivent pouvoir envoyer et recevoir des messages entre eux de préférence cryptés.

Voici un schéma du réseau :

LoRa 1 envoie à LoRa 2
LoRa 2 envoie à LoRa 3
LoRa 3 envoie à LoRa 1
LoRa Server en écoute

J'ai réalisé mon code en me basant sur les librairies suivantes :

LoRa : GitHub - sandeepmistry/arduino-LoRa: An Arduino library for sending and receiving data using LoRa radios.

Cryptage xxtea : https://github.com/boseji/xxtea-iot-crypt

Base64 : https://github.com/boseji/rBASE64

(nécessaire pour que le cryptage fonctionne correctement d'après le créateur)

L'envoi et la réception ainsi que le cryptage fonctionnent.

Le problème est que pour l'instant, les modules peuvent seulement envoyer ou recevoir des paquets, pas les deux en même temps.

J'ai fait un essai avec la fonction "millis" qui était présente dans l'exemple de la librairie mais ça marche aléatoirement. C'est peut-être la solution à mon problème mais je ne vais pas vous cacher que j'ai du mal à comprendre comment cette fonction marche.

Il faut absolument que j'arrive à avoir un réseau qui fonctionne correctement pour l'entreprise où je suis et pour avoir quelque chose à présenter pour ma soutenance.

Voici le code (celui de LoRa 1) :

#include <SPI.h>
#include <LoRa.h>
#include <Wire.h>  
#include <xxtea-iot-crypt.h>
#include "SSD1306.h"
#include <rBase64.h>

//initialisation base64
rBase64generic<250> mybase64; 

//définition de la fréquence (ici 868MHz)
#define BAND    868E6  
#define PABOOST true

//variables pour envoi
int counter = 0;
int sender = 1; //ID du LoRa expéditeur (lui-même)
int dest = 2;   //ID du LoRa destinataire
String message = "Bonjour";
String crypt;
String base;

//variables pour reception
String cryptr;
String baser;
String packSize;
String rssi;
int rsender;
int rdest;
int rid;
char packet[32];

//variables pour millis
unsigned long currentMillis = millis();
unsigned long previousMillis = 0;
long interval = 2000;

//OLED
SSD1306 display(0x3c, 4, 15);

void setup() {
  Serial.begin(115200);

  //initialisation OLED
  pinMode(16,OUTPUT);
  
  digitalWrite(16, LOW);
  delay(50); 
  digitalWrite(16, HIGH); 

  display.init();
  display.flipScreenVertically();  
  display.setFont(ArialMT_Plain_10);
  display.clear();

  Serial.println("LoRa Sender");

  //initialisation LoRa
  LoRa.begin(BAND,PABOOST);  
}

//fonction d'envoi de message
void sendMessage(String message)
{
    //déclaration clé de cryptage
    xxtea.setKey("abprod");

    //cryptage
    crypt = xxtea.encrypt(message);

    //encodage
    mybase64.encode(crypt);

    //écriture et envoi du paquet
    LoRa.beginPacket();
    LoRa.write(sender);
    LoRa.write(dest);
    LoRa.write(counter);
    LoRa.print(mybase64.result());
    LoRa.endPacket();
  
    counter++;

    //affichage des informations d'envoi sur le serial
    //Serial.println("LoRa " + String(sender));
    //Serial.println("Sending packet to LoRa " + String(dest));
    //Serial.println("ID = " + String(counter));
    //Serial.println("Message = " + String(message));

    //affichage des informations d'envoi sur le OLED
    display.clear();
    display.setTextAlignment(TEXT_ALIGN_LEFT);
    display.setFont(ArialMT_Plain_10);
    display.drawString(0, 0, "LoRa " + String(sender));
    display.drawString(0, 26, "Sending packet to LoRa " + String(dest));
    display.drawString(0, 37, "ID = " + String(counter));
    display.drawString(0, 48, "Message = " + String(message));
    display.display(); 

    delay(2000);
}

//reception du message
void reception(int packetSize)
{  
  if (packetSize) 
  {    
  //déclaration clé de cryptage
  xxtea.setKey("abprod");
  
  //lecture du paquet LoRa
  rsender = LoRa.read();
  rdest = LoRa.read();
  rid = LoRa.read();
  for (int i = 0; i < packetSize; i++) 
  { 
    //récupération des caractères du message et stockage de ceux-ci dans la variable
    packet[i] = (char)LoRa.read(); 
  }
  rssi = "RSSI : " + String(LoRa.packetRssi(), DEC);

  //décodage
  mybase64.decode(packet);

  //décryptage
  cryptr = xxtea.decrypt(mybase64.result());

  //check si le paquet entrant est pour lui
  if(rdest == 1)
  {
  //affichage du message sur le OLED
  display.clear();
  display.setTextAlignment(TEXT_ALIGN_LEFT);
  display.setFont(ArialMT_Plain_10);
  display.drawString(0 , 0 , "Received from LoRa " + String(rsender));
  display.drawString(0 , 11 , "ID = " + String(rid));
  display.drawStringMaxWidth(0 , 26 , 128, "Message : " + String(cryptr));
  display.drawString(0, 48, rssi);  
  display.display();

   //affichage du message pour le serial
   //Serial.println("Received from LoRa " + String(rsender));
   //Serial.println("ID = " + String(rid));
   //Serial.println("Message : " + String(cryptr));
   //Serial.println(rssi);
  
  delay(2000); 
  } 
}
}

void loop() {    
  //envoi du message
  if(currentMillis - previousMillis > interval) 
  {
    sendMessage(message);
    previousMillis = currentMillis;   
  }
 
  //check si paquet entrant
  reception(LoRa.parsePacket());
   
}

Si vous avez besoin de plus de détails, dites le moi.

Merci d'avance.

Bonjour
je ne sais pas comment marchent les communications Lora mais ce site donne un tuto très bien fait sur la réception de données sur une liaison série et son traitement sans latence. Tu dois pouvoir t'en inspirer pour ton problème.

Bonjour

Il faut peut être également etudier la doc du transceiver LoRa SX1278 pour découvrir les contraintes d timing des basculements entre les modes TX et Rx. Emettre et recevoir 'en même temps' n'est pas possible avec un transceiver.

Je vais regarder ça merci.

dans ta fonction loop(), il manque:

currentMillis = millis();

Cette affectation est par ailleurs inutile dans la déclaration de currentMillis, en tête du prog.

je ne vais pas vous cacher que j'ai du mal à comprendre comment cette fonction marche.

Beuuuuh ?? Voir ici.

biggil:
dans ta fonction loop(), il manque:

currentMillis = millis();

Cette affectation est par ailleurs inutile dans la déclaration de currentMillis, en tête du prog.

Où est-ce que je dois placer cette ligne dans le loop ?

biggil:
Beuuuuh ?? Voir ici.

Je me suis mal exprimé, c'est plutôt la manière de l'utiliser qui me pose des difficultés.

hello

void loop() {    
  //envoi du message
  if(millis() - previousMillis > interval) 
  {
    sendMessage(message);
    previousMillis = millis();   
  }
 
  //check si paquet entrant
  reception(LoRa.parsePacket());
   
}

dfgh:
hello

void loop() {    

//envoi du message
 if(millis() - previousMillis > interval)
 {
   sendMessage(message);
   previousMillis = millis();  
 }

//check si paquet entrant
 reception(LoRa.parsePacket());
 
}

C'est étrange, ça marche très bien entre deux LoRa (1 envoie à 2 et 2 envoie à 1) mais quand j'ajoute le troisième, ça marche plus (1 à 2, 2 à 3, 3 à 1).

Je crois que je sais d'où vient le problème, on dirait que ça vient d'un conflit de paquets. Ce qui expliquerait pourquoi ça marche avec deux LoRa mais pas trois.

Reprenons mon réseau :

En passant par le serial, j'ai remarqué que les LoRa ne reçoivent que les paquets d'un seul LoRa (bien sur celui qui n'est pas pour lui). Par exemple, LoRa 1 reçoit que les paquets de LoRa 2 et pas ceux de LoRa 3.

Quand on envoie un paquet LoRa, on écrit dans le paquet valeur par valeur. "dest" est l'ID du LoRa destinataire (ici 1 parce que LoRa 3 envoie à LoRa 1).

LoRa.beginPacket();
LoRa.write(sender);
LoRa.write(dest);
LoRa.write(counter);
LoRa.print(mybase64.result());
LoRa.endPacket();

Et quand on reçoit, on lit valeur par valeur dans le même ordre. Chaque LoRa.read() lit une valeur. "rdest" est la valeur qui stocke l'ID de destination.

rsender = LoRa.read();
rdest = LoRa.read();
rid = LoRa.read();
for (int i = 0; i < packetSize; i++) 
  { 
    //récupération des caractères du message et stockage de ceux-ci dans la variable
    packet[i] = (char)LoRa.read(); 
  }

Donc quand le code arrive au "if" qui vérifie si le message est bien destiné au LoRa en question (si "rdest" est égal à 1), il n'affiche pas le paquet vu qu'il lui est pas destiné.

//check si le paquet entrant est pour lui
  if(rdest == 1)
  {
  //affichage du message sur le OLED
  display.clear();
  display.setTextAlignment(TEXT_ALIGN_LEFT);
  display.setFont(ArialMT_Plain_10);
  display.drawString(0 , 0 , "Received from LoRa " + String(rsender));
  display.drawString(0 , 11 , "ID = " + String(rid));
  display.drawStringMaxWidth(0 , 26 , 128, "Message : " + String(cryptr));
  display.drawString(0, 48, rssi);  
  display.display();

   //affichage du message pour le serial
   //Serial.println("Received from LoRa " + String(rsender));
   //Serial.println("ID = " + String(rid));
   //Serial.println("Message : " + String(cryptr));
   //Serial.println(rssi);
    
  
  delay(2000); 
  }

Je suis un peu coincé pour le coup, je vois pas comment faire en sorte qu'ils lisent les paquets des deux autres LoRa en alternant.

Au pire, je pourrais limiter mon réseau à 2 LoRa mais ce serait bien qu'il puisse y en avoir plus.

L'exemple LoRaDuplex (et d'autres) de la librairie utilisée montre une possibilité "d'envoi à tous" à l'adresse 0xFF et la possibilité de réception d'un message par le destinataire unique désigné par son adresse..... ou par tous si envoi à l'adresse de 'broadcast'. ( cf ligne 90 et suivantes)

  // if the recipient isn't this device or broadcast,
  if (recipient != localAddress && recipient != 0xFF) {
    Serial.println("This message is not for me.");
    return;                             // skip rest of function
  }

Il me semble que pour atteindre ton objectif tu aura à entrer plus à fond dans le fonctionnement de cette librairie et aussi te documenter sur le transceiver SX1278.
Les codes de base fournis avec les cartes paraissent justes bon à tester un point à point basique entre 2 cartes.

et c'est bien ce que tu nous décrit

tu as du te planter dans les identifiants codés dans les prog de chacun des loRa
ou dans la numérotation de tes loRa