Actionner un bouton sur un Arduino et transmettre via wifi l'information sur un autre pour allumer des leds

Bonjour à tous,

Je jette une bouteille à la mer afin d'avoir un peu d'aide, je suis novice, mes connaissances sont très limitées sur Arduino. (quelques utilisations sur un UNO )

Dans le cadre d'un projet, je souhaiterais mettre en place plusieurs Arduino avec trois boutons actionneur (vert, orange, rouge) et qui peuvent transmettent à un seul et unique Arduino qui nous allumera une led de couleur en fonctions de l'arduino correspondant vert, orange, rouge.

J'aurais besoin de savoir dans un premier temps si cela est réalisable, ce que j'ai besoin en matériel et si pour un novice le codage ne sera pas trop compliqué.

Merci par avance.

Post mis dans la mauvaise section, on parle anglais dans les forums généraux, je viens de déplacer le post dans la section francophone.

Merci de prendre en compte les recommandations listées dans "Les bonnes pratiques du Forum Francophone".

Merci

1 Like

C’est tout à fait réalisable

Quel arduino?
Quel réseau WiFi? (Créé par votre Arduino ou celui de la maison où est-ce à travers internet ?)
Est ce OK are perdre des messages ?

Il faut étayer le cahier des charges pour être plus précis dans la réponse

Bonjour bryansurf

Je me suis amusé à l'exercice, comme l'on dit :wink:
Et avec l'aide de l'IA.

C'est via le Wifi de la maison et avec le protocole UDP.
J'ai légèrement retouché les sketches de l'IA et ça a fonctionné super!

Si ça t'intéresse.

Je vais essayer la communication peer to peer avec ESP-NOW.

A+
Cordialement
jpbbricole

pourquoi utiliser l'UDP, dans ce cas précis le TCP semble plus indiqué.

Bonjour terwal

Parce que le programme fonctionne très bien avec UDP.
Mais, pourquoi pas, quels seraient les avantages de TCP par rapport à UDP?
Est ce que le programme serait plus simple?

Cordialement
jpbbricole

En gros UDP ne garantit pas la livraison du message.

En détail - TCP offre la fiabilité, l’ordre des messages garanti et la détection d’erreurs, ce qui assure que chaque message arrive à destination dans l’ordre prévu (car contrairement à UDP, TCP gère automatiquement la retransmission des paquets perdus et garantit que les données sont complètes et correctes.).

Qu'appel tu très bien, tu as testé avec de la perte de paquet sur ton réseaux ?

Non ca sera exactement le même, mais il serait plus robuste à un réseaux parasité.

Le TCP garantit la réception des trames par le destinataire.
l'UDP tu ne peux pas savoir si le destinataire à bien reçu le message.

Donc l'utilisation de l'UDP est possible uniquement si cela n'a pas d'importance si l'appuis sur le bouton, n'allume pas forcément la LED sur l'autre Arduino.

Edit: Grillé par @J-M-L , j'ai fait trop de blabla :slight_smile:

Désolé je passais par là :slight_smile:

Bonjour J-M-L

Le pire est que, il y a longtemps, j'ai étudié tout ça :woozy_face:, je refais une version TCP.

Concernant ESP-NOW, j'ai des soucis de compilation:

   62 |   esp_now_register_recv_cb(OnDataRecv);
      |                            ^~~~~~~~~~
      |                            |
      |                            void (*)(const uint8_t*, const uint8_t*, int) {aka void (*)(const unsigned char*, const unsigned char*, int)}

Compilation error: invalid conversion from 'void (*)(const uint8_t*, const uint8_t*, int)' {aka 'void (*)(const unsigned char*, const unsigned char*, int)'} to 'esp_now_recv_cb_t' {aka 'void (*)(const esp_now_recv_info*, const unsigned char*, int)'} [-fpermissive]```

Le programme:

#include <esp_now.h>
#include <WiFi.h>
const char nom[10]="Master"; 
uint8_t broadcastAddress[2][6] = {
  {0x2C, 0xF4, 0x32, 0x15, 0x52, 0x22}, //station0
  {0xA0, 0x20, 0xA6, 0x08, 0x20, 0xD9}  //station1
};// REPLACE WITH RECEIVER MAC ADDRESS

// Structure example to send data
// Must match the receiver structure
typedef struct struct_message {
  char a[32];
  int b;
  float c;
  String d;
  bool e;
} struct_message;
struct_message myData;
struct_message dataRcv;

unsigned long previousTime=0;


// callbacks for sending and receiving data
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  Serial.print(F("\r\nMaster packet sent:\t"));
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}

void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
  memcpy(&dataRcv, incomingData, sizeof(dataRcv));
  Serial.print("\r\nBytes received: ");
  Serial.println(len);
  Serial.print("From slave: ");
  Serial.println(dataRcv.a);
  Serial.println();
}
void setup() {
  // Init Serial Monitor
  Serial.begin(115200);

  // Set device as a Wi-Fi Station
  WiFi.mode(WIFI_STA);

  // Init ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println(F("Error initializing ESP-NOW"));
    return;
  }
  Serial.print(F("Reciever initilized : "));
  Serial.println(WiFi.macAddress());
  
  // Define callback functions
  esp_now_register_send_cb(OnDataSent);
  esp_now_register_recv_cb(OnDataRecv);

  // Register peer
  esp_now_peer_info_t peerInfo;
  peerInfo.channel = 0;
  peerInfo.encrypt = false;
    
  memcpy(peerInfo.peer_addr, broadcastAddress[0], 6);
  if (esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println("Failed to add peer");
    return;
  }

  memcpy(peerInfo.peer_addr, broadcastAddress[1], 6);
  if (esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println("Failed to add peer");
    return;
  }
  
}

void loop() {
  if((millis() -previousTime)>5000){ 
    // Set values to send
    strcpy(myData.a, nom);
    myData.b = random(1, 20);
    myData.c = 1.2;
    
    myData.e = false;
  
    // Send message via ESP-NOW
    myData.d = "Slave0";
    esp_err_t result0 = esp_now_send(broadcastAddress[0], (uint8_t *) &myData, sizeof(myData));
    

    myData.d = "Slave1";
    esp_err_t result1 = esp_now_send(broadcastAddress[1], (uint8_t *) &myData, sizeof(myData));
    previousTime=millis();
  }
}

La solution que j'ai trouvé sur le net est de faire un downgrade de la carte ESP32, or le downgrade ne se termine pas :woozy_face:
J'ai vu ici que vos aviez réussi à compiler sans erreur, avec quelle version?

Merci par avance.
jpbbricole

je n'avais rien fait de particulier, je devais avoir les éléments à jour par rapport à ce qui est dit dans le post suivant

Sinon ESP-NOW c'est sympa mais c'est d'ESP à ESP donc il faut que les deux modules soient à portée radio l'un de l'autre. Si c'est le cas dans l'installation alors pourquoi pas, mais s'ils sont à deux bouts lointains de la maison ça sera plus compliqué et rejoindre un réseau WiFi (éventuellement mesh) sera plus fonctionnel.

Bonjour,

Merci pour ton retour effectivement j'ai reçu pour faire le test deux Arduino UNO R4 wifi il faudrais que j'essaye de le faire avec. oui l'objectif est de me connecté sur le même réseau et qu'il puisse communiquer entre .

Bonjour bryansurf

Je n'ai qu'un R4 WIFI que je vais mettre en récepteur et faire des essais avec des ESP32 en émetteurs.
Au début, je ferai ça en UDP avec toutes les remarques énoncées par @J-M-L. UDP peut être aisément sécurisé en demandant la quittance de chaque ordre. J'ai débuté des essais en TCP, mais c'est moins réactif :woozy_face:, si tu n'as pas besoin de vitesse ça peut le faire.

A+
Cordialement
jpbbricole

C'est très étonnant que tu es des problèmes de réactivité et aucun soucis de paquet perdu en UDP.
Tu envois des paquets de combien octet?
quel est l'ordre de la réactivité ?

Si tu réimplémente TCP, il faut penser à vérifier l'ordre des ordres que tu reçois.
Et bien sûre si tu veux garder une bonne réactivité, avoir un timer pour renvoyer l'ordre si l'acquittement n'a pas été reçu dans les temps.

Bonjour bryansurf

Voici, je t'ai fait un exemple basé sur UDP, avec toutes les réserves signalées ci-dessus, ça peut être une bonne base de départ. C'est basé sur un ChatGPT que j'ai "retouché".
A l'émetteur il y a 3 boutons, VERT, ORANGE et ROUGE, ce texte est envoyé tel quel au récepteur, tu peux voir ceci dans la console à 115200:

Envoyé :VERT
	Quittance <<< :VERT
Envoyé :ORANGE
	Quittance <<< :ORANGE
Envoyé :ROUGE
	Quittance <<< :ROUGE

lequel allume la LED désignée et renvoie une quittance à l'émetteur:

Message reçu : VERT
	quittance >>> : VERT
Message reçu : ORANGE
	quittance >>> : ORANGE
Message reçu : ROUGE
	quittance >>> : ROUGE

Pour installer ce réseau, il faut d'abord lancer le récepteur afin d'avoir son adresse IP (qui est affichée dans la console) afin de renseigner la variable de l'émetteur:
const char* udpAddress = "192.168.1.122"; // Changez cela par l'adresse IP de votre récepteur

Le programme émetteur:

/*
Name:       Test_UDPsender.ino 
Created:	
Author:     jpbbricole/IA

Remarque:   https://forum.arduino.cc/t/actionner-un-bouton-sur-un-arduino-et-transmettre-via-wifi-linformation-sur-un-autre-pour-allumer-des-leds/1305509
*/

#include <WiFi.h>
#include <WiFiUdp.h>

// Réseaux Wi-Fi (SSID et mot de passe)
const char* ssid = "ton-SSID";
const char* password = "ton-Password";

// Adresse IP du récepteur ESP32
const char* udpAddress = "192.168.1.122"; // Changez cela par l'adresse IP de votre récepteur
const int udpPort = 4510;

// Pin des boutons
const int btnVertPin = 13;
const int btnOrangePin = 12;
const int btnRougePin = 14;

WiFiUDP udp;
String couleur = "";

// Fonction pour se connecter au Wi-Fi
void connectToWiFi() {
  Serial.print("Connexion à ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connexion en cours...");
  }

  Serial.println("Connecté au WiFi!");
  Serial.print("Adresse IP : ");
  Serial.println(WiFi.localIP());
}

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

  // Connexion au réseau Wi-Fi
  connectToWiFi();

  // Configuration des pins des boutons
  pinMode(btnVertPin, INPUT_PULLUP);
  pinMode(btnOrangePin, INPUT_PULLUP);
  pinMode(btnRougePin, INPUT_PULLUP);
}

void loop() {
  // Lecture des boutons
  if (digitalRead(btnVertPin) == LOW) {
      udpEnvoiPaquet("VERT");
//    delay(1000); // Anti-rebond
  } else if (digitalRead(btnOrangePin) == LOW) {
      udpEnvoiPaquet("ORANGE");
 //   delay(1000); // Anti-rebond
  } else if (digitalRead(btnRougePin) == LOW) {
      udpEnvoiPaquet("ROUGE");
 //   delay(1000); // Anti-rebond
  }

  // Réception de la quittance
  int packetSize = udp.parsePacket();
  if (packetSize) {
    char incomingPacket[255];
    int len = udp.read(incomingPacket, 255);
    if (len > 0) {
      incomingPacket[len] = 0;
    }
    Serial.print("\tQuittance <<< :");
    Serial.println(incomingPacket);
  }
  delay(250);
}

void udpEnvoiPaquet(String btnCouleur){
    Serial.println("Envoyé :" + btnCouleur);
    udp.beginPacket(udpAddress, udpPort);
    udp.print(btnCouleur);
    udp.endPacket();
}

Le programme récepteur:

/*
Name:       Test_UDPreceiver.ino 
Created:	
Author:     jpbbricole

Remarque:   https://forum.arduino.cc/t/actionner-un-bouton-sur-un-arduino-et-transmettre-via-wifi-linformation-sur-un-autre-pour-allumer-des-leds/1305509
*/

#include <WiFi.h>
#include <WiFiUdp.h>

// Réseaux Wi-Fi (SSID et mot de passe)
const char* ssid = "ton-SSID";
const char* password = "ton-Password";

// Port UDP pour recevoir les données
const int localUdpPort = 4510;

// Pin des LEDs
const int ledVertPin = 5;
const int ledOrangePin = 6;
const int ledRougePin = 7;

WiFiUDP udp;
char incomingPacket[255];  // Buffer pour recevoir les paquets

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

  // Connexion au réseau Wi-Fi
  connectToWiFi();

  // Démarrage UDP
  udp.begin(localUdpPort);
  Serial.println("Serveur UDP en écoute sur le port" + localUdpPort);

  // Configuration des pins des LEDs
  pinMode(ledVertPin, OUTPUT);
  pinMode(ledOrangePin, OUTPUT);
  pinMode(ledRougePin, OUTPUT);
}

void loop() {
  // Vérification des paquets UDP
  int packetSize = udp.parsePacket();
  if (packetSize) {
    // Réception du message UDP
    int len = udp.read(incomingPacket, 255);
    if (len > 0) {
      incomingPacket[len] = 0;
    }

    String udpData = (String)incomingPacket;
    udpData.trim();  // Nettoyage de la chaîne
    Serial.print("Message reçu : ");
    Serial.println(udpData);

    // Gestion des LEDs selon le message reçu
    if (udpData == "VERT") {
      digitalWrite(ledVertPin, HIGH);
      digitalWrite(ledOrangePin, LOW);
      digitalWrite(ledRougePin, LOW);
      udpQuittance(udpData);
    } else if (udpData == "ORANGE") {
      digitalWrite(ledVertPin, LOW);
      digitalWrite(ledOrangePin, HIGH);
      digitalWrite(ledRougePin, LOW);
      udpQuittance(udpData);
    } else if (udpData == "ROUGE") {
      digitalWrite(ledVertPin, LOW);
      digitalWrite(ledOrangePin, LOW);
      digitalWrite(ledRougePin, HIGH);
      udpQuittance(udpData);
    }
  }
}

// Fonction pour Envoyer la quittance à l'émetteur
void udpQuittance(String quittance) {
  Serial.println("\tquittance >>> : " + quittance);
  udp.beginPacket(udp.remoteIP(), udp.remotePort());
  udp.print(quittance);
  udp.endPacket();
}

// Fonction pour se connecter au Wi-Fi
void connectToWiFi() {
  Serial.print("Connexion à ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connexion en cours...");
  }

  Serial.println("Connecté au WiFi!");
  Serial.print("Adresse IP : ");
  Serial.println(WiFi.localIP());
}

Dès que j'au du temps, je te fais un exemple avec UDP, ou tu fais comme moi, tu pose la question à ChatGPT :wink:

Cordialement
jpbbricole

Bonjour bryansurf

Sur la lancée, j'ai fait une version TCP, avec l'aide de l'IA, un peu arrangé par la suite.
Comme la version UDP, il faut d'abord installer le récepteur afin de renseigner l'émetteur de son adresse IP:
const char* tcpHost = "192.168.1.122"; // Mettre ici l'adresse IP du récepteur

Il y a quelques plus par rapport à la version UDP:
Côté émetteur:
avec la commande de couleur, s'ajoute l'intensité (0-255)
sendMessage("ORANGE", 127);
Au récepteur, la LED ORANGE sera à moitié allumée.

Il y a possibilité, depuis la ligne de commande du moniteur (115200),
image
d'envoyer des ordres au récepteur;
VERT,127 Allume la LED à moitié
ORANGE,255 Allume la ORANGE en plein
ROUGE,0 Eteint la ROUGE.

Autant du côté émetteur que du côté récepteur, il y a des indications quant au fonctionnement du programme.
L'émetteur:

/*
Name:       Test_TCPsender.ino 
Created:	
Author:     jpbbricole/IA
            https://chatgpt.com/share/66fec528-ea1c-8013-bf88-0d44719ba34d

Remarque:   Envoi de commandes via TCP avec quittance du récepteur.
            Les commandes s'envoient par 3 boutons ou des commandes dans le moniteur
            La commande ORANGE,127 allume à moitié la LED ORANGE, au récepteur
            L'émetteur est identifié par la variable emitterID
*/

#include <WiFi.h>
#include <WiFiClient.h>

// Paramètres WiFi
const char* ssid = "ton-SSID";
const char* password = "ton-Password";

// Adresse IP du serveur (récepteur)
const char* tcpHost = "192.168.1.122";  // Mettre ici l'adresse IP du récepteur
const uint16_t tcpPort = 5410;        // Port à utiliser

// Pins des boutons
const int btnVertPin = 13;
const int btnOrangetPin = 12;
const int btnRougetPin = 14;

// Identification de l'émetteur
const char* emitterID = "EM1";  // Adapter pour chaque ESP32 (EM2, EM3, etc.)

// Structure des données à envoyer
struct Message {
  char emitterID[10];
  char ledName[10]; // "VERT", "ORANGE", "ROUGE"
  int ledIntensity;    // Intensité de la LED à allumer (0-255)
};


void setup() {
  // Initialisation série
  Serial.begin(115200);

  // Configuration des boutons
  pinMode(btnVertPin, INPUT_PULLUP);
  pinMode(btnOrangetPin, INPUT_PULLUP);
  pinMode(btnRougetPin, INPUT_PULLUP);

  // Connexion WiFi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connexion au WiFi...");
  }
  Serial.print("Connecté au réseau WiFi avec l'adresse IP: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  // S'il y a une commande moniteur
  if (Serial.available()) {
    cmdExecute(Serial.readStringUntil('\n'));
  }
  
  // Vérification des boutons et envoi du message correspondant
  if (digitalRead(btnVertPin) == LOW) {
    sendMessage("VERT", 0);  // Intensité 255 pour le maximum
    delay(500);  // Anti-rebond
  }
  
  if (digitalRead(btnOrangetPin) == LOW) {
    sendMessage("ORANGE", 127);
    delay(500);  // Anti-rebond
  }
  
  if (digitalRead(btnRougetPin) == LOW) {
    sendMessage("ROUGE", 255);
    delay(500);  // Anti-rebond
  }
}

//------------------------------------- Fonction d'envoi d'un message TCP
void sendMessage(const char* ledColor, int ledIntensity) {
  WiFiClient client;
  if (client.connect(tcpHost, tcpPort)) {
    Serial.println("Connecté au serveur");
    Serial.println("\tEnvoi de " + (String)ledColor + " " + String(ledIntensity));
    
    // Préparation du message
    Message tcpData;
    strncpy(tcpData.emitterID, emitterID, sizeof(tcpData.emitterID));
    strncpy(tcpData.ledName, ledColor, sizeof(tcpData.ledName));
    tcpData.ledIntensity = ledIntensity;

    // Envoi du message
    client.write((uint8_t*)&tcpData, sizeof(tcpData));
    
    // Lecture de la réponse du serveur
    while (client.connected()) {
      if (client.available()) {
        String response = client.readString();
        Serial.println("\t\tRéponse du serveur: " + response);
        break;
      }
    }
    client.stop();
  } else {
    Serial.println("Erreur de connexion au serveur");
  }
}

//------------------------------------- Commandes moniteur CMD,PARAM
void cmdExecute(String cmdRx){
  cmdRx.trim(); // Nettoyage de cmd
  cmdRx.toUpperCase(); // En majuscules
  cmdRx.replace(" ", ""); // Supprimer les espaces

  Serial.println("Moniteur : " + cmdRx);
  String cmd = cmdRx.substring(0, cmdRx.indexOf(","));
  int cmdParam = cmdRx.substring(cmdRx.indexOf(",") +1).toInt();

  sendMessage(cmd.c_str(), cmdParam);
}

Le récepteur:

/*
Name:       Test_TCPreceiver.ino 
Created:	
Author:     jpbbricole/IA
            https://chatgpt.com/share/66fec528-ea1c-8013-bf88-0d44719ba34d

Remarque:	
*/

#include <WiFi.h>
#include <WiFiServer.h>

// Paramètres WiFi
const char* ssid = "ton-SSID";
const char* password = "ton-Password";

const int ledVertPin = 9;
const int ledOrangetPin = 10;
const int ledRougetPin = 11;

// Structure des données reçues
struct Message {
  char emitterID[10];
  char ledName[10];  // "VERT", "ORANGE", "ROUGE"
  int ledIntensity;     // Intensité de la LED à allumer (0-255)
};

WiFiServer server(5410);

void setup() {
  // Initialisation série
  Serial.begin(115200);
  
  // Configuration des LEDs
  pinMode(ledVertPin, OUTPUT);
  pinMode(ledOrangetPin, OUTPUT);
  pinMode(ledRougetPin, OUTPUT);

  // Connexion WiFi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connexion au WiFi...");
  }
  Serial.print("Connecté au réseau WiFi avec l'adresse IP: ");
  Serial.println(WiFi.localIP());

  // Démarrage du serveur TCP
  server.begin();
}

void loop() {
  WiFiClient client = server.available();  // Vérifie s'il y a un client
  
  if (client) {
    Serial.println("Client connecté");

    Message tcpData;
    int bytesReceived = client.read((uint8_t*)&tcpData, sizeof(tcpData));
    
    if (bytesReceived == sizeof(tcpData)) {
      Serial.print("Message reçu de: ");
      Serial.println(tcpData.emitterID);
      Serial.print("\tledName: ");
      Serial.print(tcpData.ledName);
      Serial.print("\tIntensité: ");
      Serial.println(tcpData.ledIntensity);
      
      String cmdOk = "OK";
      // Contrôle des LEDs
      if ((String)tcpData.ledName == "VERT") {
        analogWrite(ledVertPin, tcpData.ledIntensity);
      } else if ((String)tcpData.ledName == "ORANGE") {
        analogWrite(ledOrangetPin, tcpData.ledIntensity);
      } else if ((String)tcpData.ledName == "ROUGE") {
        analogWrite(ledRougetPin, tcpData.ledIntensity);
      } else {
        cmdOk = "???"; // Si commande inconnue
      }

      // Envoi de la quittance
      String ackMessage = "Recu de " + (String)tcpData.emitterID;
      ackMessage += "\n\t\tCouleur recue: ";
      ackMessage += tcpData.ledName;
      ackMessage += " ";
      ackMessage += tcpData.ledIntensity;
      ackMessage += " ";
      ackMessage += cmdOk;
      client.print(ackMessage);
    }
    
    client.stop();  // Ferme la connexion avec le client
    Serial.println("Client déconnecté");
  }
}

A +
Cordialement
jpbbricole

Si tu veux tu veux une méthode pour t'affranchir de devoir connaitre l'IP ou si celle-ci a des risques de changer(en DHCP par exemple), tu peux essayer de faire du broadcast.
le principe est que ton serveur écoute sur un port en particulier en UDP et lorsqu'un nouveau client est (re)connecté au réseau WIFI, celui-ci envois une trame broadcast, cette trame est envoyé à tous les appareils connecté sur le "sous-réseau".
le serveur répond alors au client, qui du coup obtient l'IP du "serveur".

Bonjour terwal

Oui, mais pas évident à transposer ça "en Arduino".
Une solution, plus simple est de fixer l'adresse IP du récepteur, dans le routeur.

Bon dimanche
jpbbricole

Avec les soucis potentiels de UDP à traiter - mais oui ce serait une solution sans câblage en dur.