Commutateur via lora 433

Bonjour,
Je cherche a faire un simple commutateur a distance, fiable et non perturbable par d'autres système HF.
On appuie sur un bouton et ça commute un relais ( furtif ou maintenue plusieurs secondes) a une distance d'environ 400 mètres maxi, mais sans être perturbé car le système doit fonctionner au milieu d'autre système HF en extérieur et intérieur et pas forcément dans la même pièce.
j'ai fait des essaies avec une E32 433T30D et une ESP8266 avec un code trouvé sur le net. Ça a l'aire de fonctionner mais je voudrai être sur de mon coup car c'est pour commander des effets au milieux de spectacles.
j'aimerai que le système vérifie la liaison (led verte des deux coté pour dire que la liaison est établie) avec un retour vers l’émetteur pour indiquer que la réception est ok.
voici le code que j'ai testé.
TX.

/**************************** TX ****************************/
#include "EBYTE.h"
#define PIN_RX 14      // D5 sur la carte (Connecter la pin TX de la EBYTE)
#define PIN_TX 12      // D6 sur la carte (Connecter la pin RX de la EBYTE)
#define PIN_M0 5       // D1 sur la carte (Connecter la pin M0 de la EBYTE)
#define PIN_M1 4       // D2 sur la carte (Connecter la pin M1 de la EBYTE)
#define PIN_AX 16      // D0 sur la carte (Connecter la pin AUX de la EBYTE)
#define Contact1 13    // D7 connecter le contact 01 (principal)
#define LED1 17        // D4 sortie Led supplémentaire 

struct DATA {
  int Bits;
};

DATA MyData;
EBYTE Transceiver(&Serial, PIN_M0, PIN_M1, PIN_AX);

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

  pinMode(Contact1, INPUT_PULLUP); // contact Tally
  pinMode(LED1, OUTPUT);    // sortie pin D4 pour un contact exterieur
  Serial.println(Transceiver.init());
}

void loop() {
  int b1 = digitalRead(Contact1); // lis le contact Tally

  if (b1 == LOW) {
    MyData.Bits = 12345;
    Transceiver.SendStruct(&MyData, sizeof(MyData));
    digitalWrite(LED1, HIGH);
    delay(10);
  }

  digitalWrite(LED1, LOW);
}

RX:

/**************************** RX ****************************/
#include <SoftwareSerial.h>
#include "EBYTE.h"

#define PIN_RX 14   // D5 sur la carte (Connecter la pin TX de la EBYTE)
#define PIN_TX 12   // D6 sur la carte (Connecter la pin RX de la EBYTE)
#define PIN_M0 5    // D1 sur la carte (Connecter la pin M0 de la EBYTE)
#define PIN_M1 4    // D2 sur la carte (Connecter la pin M1 de la EBYTE)
#define PIN_AX 16   // D0 sur la carte (Connecter la pin AUX de la EBYTE)
#define LED1 13     // D7 sortie Led 1
#define LED2 17     // D4 sortie Led 2

struct DATA {
  int Bits;
};

int Chan;
DATA MyData;
unsigned long Last;

SoftwareSerial ESerial(PIN_RX, PIN_TX);
EBYTE Transceiver(&ESerial, PIN_M0, PIN_M1, PIN_AX);

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

  ESerial.begin(9600);
  pinMode(LED1, OUTPUT);
   pinMode(LED2, OUTPUT);
 
  Transceiver.init();

  Transceiver.PrintParameters();
}

void loop() {

  if (ESerial.available()) {

    Transceiver.GetStruct(&MyData, sizeof(MyData));

     digitalWrite(LED1, LOW);  
      digitalWrite(LED2, LOW); 
     Serial.print("Bits: "); Serial.println(MyData.Bits);

    Last = millis();
    
  }
  else {
    if ((millis() - Last) > 200) {
      Last = millis();
      digitalWrite(LED1, HIGH);
       digitalWrite(LED2, HIGH);
    }

  }
}

peut être avec une carte TTGO LoRa32 OLED pour indiquer les paramètres de liaison entre les deux cartes. je n'en connais pas la distance maxi

Bonjour @imaljl1

j'aimerai que le système vérifie la liaison (led verte des deux coté pour dire que la liaison est établie) avec un retour vers l’émetteur pour indiquer que la réception est ok.

1-Tes modules E32-433 de chez EBYTE sont des transceivers (=emetteurs ET recepteurs)
Tu les testes actuellement avec un code émetteur à un bout et un code récepteur à l'autre, dons en mode unidirectionnel.

Si à chaque bout le code est émetteur + récepteur il sera alors possible à l'appareil commandé d'accuser réception des ordes réçus. Ce serait déjà un premier niveau d contrôle de la liaison
Tu peux en plus , entre les ordres, envoyer périodiquement une petite info juste pour vérifier que l'autre l'à reçue et que sa réponse parvient.

Il te faut donc passer des 'codes trouvés' à des codes rédigés par toi en fonction de tes besoins.

je n'en connais pas la distance maxi

2-Parce que tu n'a pas encore fait les essais sur le terrain !! dans les conditions réelles d'utilisation , en tenant compte du positionnement des antennes , de leur distance au sol.....de la présence d'arbres de buissons ......etc...
La distance dépend des conditions de propagation, personne ne peux les tester à part toi.
Ls distances annoncées par les fabricants et vendeurs sont justes indicatives (et bien entendu optimistes)
A priori 400m avec du LoRa ça parait confortable, sauf situation très particulière sur le terrain

peut être avec une carte TTGO LoRa32 OLED

3-les modules E32-433 assurent un cryptage 'maison' des trames ajouté en dehors de LoRa par EBYTE, fabricant des E32
Une carte ESP32 à module LoRa normal ne sait pas décrypter les trames échangées entres modules E32, elle ne peut donc pas jouer un rôle dans la surveillance de la liaison entre modules

4-Utilisant des E32-868 d'EBYTE sans bibliothèque je ne connais pas celle que tu utilises,
Vois déjà ce qu'elle propose pour aller au delà de tes tests unidirectionnels actuels. Peut être donne-t-elle accès au paramétrage des modules de manière à les mettre dans la configuration (débit, portée) qui conviens à ta situation

je vais tester un code genre "duplex"

j'ai fait un code qui fonctionne bien en émetteur récepteur , mais je n'arrive pas a trouver comment passé en duplex, ça coupe l’émission.

// RX //
#include <WiFi.h>
#include <SPI.h>
#include <LoRa.h>
#include <Wire.h>
#include <SSD1306Wire.h>
#include "board_defs.h"  // broches utilisées par le module LILYGO® TTGO LoRa32 V2.1_1.6
#include "images.h"
#include "my_fonts.h"
#define effet 13  // sortie effet

String tally;   // pour afficher les pointillés 
String packet;  // paquet à envoyer sur LoRa
String rssi = "RSSI";
String packSize = "--";
float battery = 0;  // Voltage de batterie
int value;
SSD1306Wire display(OLED_ADDRESS, OLED_SDA, OLED_SCL);
SPIClass loraSPI(VSPI);  //Entrée pour utiliser le module LoRa sur le module VSPI (SPI3) Tension

void setup() {
  pinMode(LED, OUTPUT);       // Led verte
  pinMode(LEDTally, OUTPUT);  // effet
  pinMode(VBAT, INPUT);       // Entrée pour la tension de la batterie

  Serial.begin(115200);
  while (!Serial);
  delay(500);

  // OLED
  display.init();
  display.flipScreenVertically();
  display.clear();
  delay(100);
  display.setTextAlignment(TEXT_ALIGN_LEFT);
  display.setFont(Monospaced_bold_11);

  // Module LoRa
  loraSPI.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_SS);
  LoRa.setPins(LORA_SS, LORA_RST, LORA_DI0);
  LoRa.setSPI(loraSPI);
  LoRa.setSpreadingFactor(12);  //entre 7 et 12 (7 plus rapide, mais distance plus courte)
  LoRa.setCodingRate4(8);       //entre 5 et 8 (8 plus lent mais plus de sécurité)
  LoRa.enableCrc();             //activer le contrôle CRC pour une communication garantie sans erreur

  if (!LoRa.begin(LORA_BAND))  // 868 Mhz
  {
    display.drawString(0, 0, "Bande 868Mh Erreur");
    display.display();
    while (1)
      ;
  }
  display.drawString(0, 0, "Reception ON");
  display.display();
  // définir un mot de synchronisation à utiliser avec les deux modules pour la synchronisation
  LoRa.setSyncWord(0xF3);  // de 0 à 0xFF, par défaut 0x34, voir docs API
  LoRa.receive();
  delay(300);

  // vérifier la batterie
  battery = checkBattery();  // première vérification de la batterie au démarrage
  display.drawString(0, 22, "Battery: " + String(battery) + "V");
  display.display();
  delay(1000);

  display.drawString(0, 44, "Init OK");
  display.display();
  delay(2000);
  display.clear();

}

void loop() {
  // variables utilisées pour vérifier la batterie et donner une valeur moyenne
  static uint16_t chkbat = 0;
  static float tempbatt = 0;
  display.clear();

  display.drawString(11, 22, "RX ");
  display.drawString(0, 33, String(battery) + "V");
  display.drawString(75, 33, "868 Mhz");
  display.drawString(0, 44, rssi);
  value = map(LoRa.packetRssi(), -115, 0, 1, 70);
  display.fillRect(60, 47, value, 8);
  display.drawString(0, 55, tally);

  display.display();

  int packetSize = LoRa.parsePacket();
  if (packetSize) getLoRaPacket(packetSize);

  // tension de la batterie en moyenne sur 2000 lectures
  tempbatt += checkBattery();
  chkbat++;
  if (chkbat == 2000) {
    chkbat = 0;
    battery = (tempbatt / 2000);
    tempbatt = 0;
  }
}

// Reconstruire le paquet LoRa
void getLoRaPacket(int packetSize) {
  packet = "";
  packSize = String(packetSize, DEC);
             Serial.print("test:  ");
  Serial.println(packSize);
  for (int i = 0; i < packetSize; i++) {
    packet += (char)LoRa.read();  // reconstruire le paquet caractère par caractère
  }
  rssi = "RX:" + String(LoRa.packetRssi(), DEC);

  if (packet == "1234") {
    tally = ("------------------");
    digitalWrite(effet, HIGH);
    //LedOn();
    if (value <= 1) {
      tally = ("");
      digitalWrite(effet, LOW);
      //LedOff();
    }
  } else {
    tally = ("");
    digitalWrite(effet, LOW);
    //LedOff();
  }
}
void LedOn() {
  digitalWrite(LED, HIGH);
}
void LedOff() {
  digitalWrite(LED, LOW);
}
float checkBattery(void) {
  return (float)(analogRead(VBAT)) / 4095 * 2 * 3.3 * 1.1;
}

pour le TX

#include <WiFi.h>
#include <SPI.h>
#include <LoRa.h>
#include <Wire.h> 
#include <SSD1306Wire.h>
#include "board_defs.h" //  broches utilisées par le module LILYGO® TTGO LoRa32 V2.1_1.6
#include "images.h"
#include "my_fonts.h"
#define Contact1 13 // entrée contact tally

String tally;  // pour afficher les pointillés 
String verif =("agito"); // paquet à envoyer sur LoRa pour verif liaison
uint32_t envoitally=1234; // variable pour envoi effet
float battery=0; // Voltage de batterie

SSD1306Wire display(OLED_ADDRESS, OLED_SDA, OLED_SCL);
SPIClass loraSPI(VSPI); // module LoRa sur le module VSPI (SPI3)

void setup() 
  {
//
  pinMode(LED,OUTPUT); // Led verte carte
  pinMode(VBAT,INPUT); // Entrée pour la tension de la batterie
  pinMode(Contact1, INPUT_PULLUP); // contact effet

//
  Serial.begin(115200);
  while (!Serial);
  delay(500);

  // OLED
  display.init();
  // affichage antenne vers le haut
  display.flipScreenVertically(); 
  display.clear();
  delay(100); 
  display.setTextAlignment(TEXT_ALIGN_LEFT);
  display.setFont(Monospaced_bold_11);

  // Module LoRa
  loraSPI.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_SS);
  LoRa.setPins(LORA_SS, LORA_RST, LORA_DI0);
  LoRa.setSPI(loraSPI);
  LoRa.setSpreadingFactor(12); //entre 7 et 12 (7 plus rapide, mais distance plus courte)
  LoRa.setCodingRate4(8); //entre 5 et 8 (8 plus lent mais plus de sécurité)
  LoRa.enableCrc(); //activer le contrôle CRC pour une communication garantie sans erreur

  if (!LoRa.begin(LORA_BAND)) // 868 Mhz
    {
    display.drawString(0,0,"Liaison Erreur");
    display.display();
    while (1);
    }
  display.drawString(0,0,"Emission ON");
  display.display();
  // définir un mot de synchronisation à utiliser avec les deux modules pour la synchronisation
  LoRa.setSyncWord(0xF3); // de-a: 0-0xFF, par defaut 0x34, voir API documentations
  delay(300);

  
  // test batterie
  battery=checkBattery(); // première vérification de la batterie au démarrage
  display.drawString(0,22,"Battery: "+String(battery)+"V");
  display.display();
  delay(1000);

  display.drawString(0,44,"Init OK");
  display.display();
  delay(2000);
  display.clear();

  }

void loop() 
  {
  // variables utilisées pour vérifier la batterie et donner une valeur moyenne
  static uint8_t chkbat=0;
  static float tempbatt=0;

 // affichage principal
  display.clear();
  display.setTextAlignment(TEXT_ALIGN_LEFT);
  display.setFont(Monospaced_bold_11);
  display.drawString(0,33,"TX ");
  display.drawString(0,44,String(battery)+"V");
  display.drawString(75,44,"868 Mhz"); 
  display.drawString(0, 55,tally);
  //display.drawString(48,44, String(counter));
  display.display();

int T1 = digitalRead(Contact1); // lis le contact effet
if (T1 == LOW) {
tally =("------------------");
  // envoyer un paquet sur LoRa 
  //packet="@"+String(envoitally)+"#";
  LoRa.beginPacket();
  LoRa.print(envoitally);
  LoRa.endPacket();
 }
 else
 {
   tally =("");
  LoRa.beginPacket();
  LoRa.print(verif);
  LoRa.endPacket();
   }
  // tension de la batterie en moyenne sur 20 lectures
  tempbatt+=checkBattery();
  chkbat++;
  if (chkbat==20)
    {
    chkbat=0;
    battery=(tempbatt/20);
    tempbatt=0;
    }
  delay(50);
  }
float checkBattery(void)
  {
  return (float)(analogRead(VBAT))/4095*2*3.3*1.1;
  }

Bonjour @imaljl1

les deux codes ci dessus sont donc exécutés sur des cartes TTGO Lora Oled possédant leurs puces radio LoRa SPI en 868 MHz ....

il n'est donc plus question de modules E32 en 433 MHz sur port série
c'est bien ça ? ... pas évident de suivre ....

Si la bibliothèque LoRa utilisée est arduino-LoRa de Sandeep Mistry voir les exemples en duplex proposés :

En effet j'ai pris l’option TTGO 868Mhz.
mais après plusieurs tentative je n'arrive toujours pas a intégrer le code duplex dans mon code.

OK

si tu as fait pu faire fonctionner de manière satisfaisante l'un des deux exemples de fonctionnement en duplex as-tu tenté de le faire évoluer en direction de ton besoin ?

utilsant ce type de carte en LoRaWAN, pas en LoRa point à point je connais très peu cette bibliothèque et ne peux guère être plus utile. :anguished: (Des modules E32 me servent parfois en Lora 'point à point')

tu as vu l'API de la bibliothèque mentionnée plus haut ?

j'ai trouvé un moyen de lire la liaison et d’interdire tout contacts si perte de liaisons

Je n'arrive vraiment pas a faire un duplex avec mon code. dès que je mets un "LoRa.beginPacket();" ça coupe la réception complétement. il doit y avoir un irq qui manque

Bonsoir

.....mais je n'arrive pas a trouver comment passé en duplex,

Quel duplex : semi duplex (half duplex) ou duplex intégral (full duplex) ?

le transceivers LoRa font du semi-duplex pas du duplex intégral !
Le circuit intégré SX1276 (transceiver LoRa) qui est utilisé sur la carte TTGO LoRa ou dans un module E32-868 ne peut être simultanément en mode émission ET en mode réception , il faut gérer une alternance entre ces modes

"LoRa.beginPacket();" ça coupe la réception complétement.

TRès certainement la conséquence du passage en mode 'idle' au début de la fonction LoRa.BeginPacket()
cf ligne 169 : https://github.com/sandeepmistry/arduino-LoRa/blob/master/src/LoRa.cpp

semi duplex .
il y a une histoir d'interuption, mais je n'ai pas encore trouvé

Bonsoir @imaljl1

Les deux exemples de dupleix indiqués au message #6 ne t'inspirent pas ?

La bibliothèque LoRa de Sandeep Mistry prend en charge les interruptions déclenchées par la sortie DIO0 du SX1876 (trasnsceiver LoRa), on le voit dans le code de cette bibliothèque.

Il faudrait vérifier sur le schéma de ta carte TTGO si DIO0 est bien relié à un GPIO de l'ESP32, il serrai étonnant que TTGO ne l'ai pas fait sur le circuit imprimé

je n'avais pas vue que la sortie DIO0 était sur 2 et non 1 comme sur l'exemple. Je vais tester ça ce soir

pfff je ne trouve pas pourquoi, lorsque je met " LoRa.beginPacket(); " ça coupe la réception "int packetSize = LoRa.parsePacket();
if (packetSize) { etc... "