Envoyer une commande moniteur série via un bouton

Bonjour à tous, j’ai récemment trouvé un code me permettant d’ajouter des télécommandes Somfy supplémentaires à mon domicile.

Pour actionner la monté, l’arrêt ou la descente des volets roulants je dois envoyer des commandes à l’arduino via le moniteur série (m0 Monte, s0 Stop, d0 Descend).

Ma question est la suivante: comment puis-je ajouter un bouton pour envoyer ses mêmes commandes vers le port série ?

J’ai essayé “(digitalRead(Bouton) == HIGH) et Serial.println(“m0”);” pour envoyé le fameux “m0” au moniteur série mais ça ne fonctionne pas.

Je vous joins le code plus bas

Merci de m’avoir lu

#include <EEPROM.h>
#define PORT_TX 5
 
#define SYMBOL 640
#define HAUT 0x2
#define STOP 0x1
#define BAS 0x4
#define PROG 0x8
#define EEPROM_ADDRESS 0
 
#define VERSION 1
 
byte frame[7];
byte checksum;
 
struct Remote
{
  unsigned long remoteID;
  unsigned int rollingCode;
};
 
struct SomfyController
{
  int appVersion;
  Remote remotes[1];
};
 
SomfyController somfyControllers;
Remote newRemotes [1] = {
  {0x123456, 0}
};
 
void BuildFrame(unsigned long remoteID, unsigned int rollingCode, byte *frame, byte button);
void SendCommand(byte *frame, byte sync);
 
 
void setup()
{
  Serial.begin(115200);
  DDRD |= 1<<PORT_TX;
  PORTD &= !(1<<PORT_TX);
 
  EEPROM.get(EEPROM_ADDRESS, somfyControllers);
 
  if (somfyControllers.appVersion < VERSION)
  {
    Serial.println("La version de l'application en mémoire n'est pas dans la bonne version ou la mémoire est vide");
    somfyControllers.appVersion = VERSION;
    memcpy(&somfyControllers.remotes, &newRemotes, sizeof(newRemotes));
    
    EEPROM.put(EEPROM_ADDRESS, somfyControllers);
  }
 
  for (int i = 0; i < (sizeof(somfyControllers.remotes) / sizeof(Remote)); i++)
  {
    Remote currentRemote = somfyControllers.remotes[i];
    Serial.print("Commande ["); Serial.print(i); Serial.println("]");
    Serial.print("\tID de la commande : "); Serial.println(currentRemote.remoteID, HEX);
    Serial.print("\tCompteur actuel : "); Serial.println(currentRemote.rollingCode);
  }
}
 
void loop()
{
  if (Serial.available())
  {
    String data = "";
    
    while (Serial.available())
    {
      char c = Serial.read();
      data += String(c);
      delay(10);
    }
 
    char serie = data[0];
 
    for (int i = 1; i < data.length(); i++)
    {
      char cRemotePosition = data[i];
      
      int remotePosition = cRemotePosition - '0';
      Serial.print("Commande "); Serial.println(remotePosition);
 
      Remote remote = somfyControllers.remotes[remotePosition];
      unsigned long remoteID = remote.remoteID;
      unsigned int rollingCode = remote.rollingCode;
      
      Serial.println("");
      if (serie == 'm')
      {
        Serial.println("Monte");
        BuildFrame(remoteID, rollingCode, frame, HAUT);
      }
      else if (serie == 's')
      {
        Serial.println("Stop");
        BuildFrame(remoteID, rollingCode, frame, STOP);
      }
      else if (serie == 'd')
      {
        Serial.println("Descend");
        BuildFrame(remoteID, rollingCode, frame, BAS);
      }
      else if (serie == 'p')
      {
        Serial.println("Prog");
        BuildFrame(remoteID, rollingCode, frame, PROG);
      }
      else
      {
        Serial.println("Code custom");
        BuildFrame(remoteID, rollingCode, frame, serie);
      }
  
      Serial.println("");
      SendCommand(frame, 2);
      for (int i = 0; i < 2; i++)
      {
        SendCommand(frame, 7);
      }
  
      //Incrémente le compteur et le sauvegarde en mémoire
      somfyControllers.remotes[remotePosition].rollingCode++;
      EEPROM.put(EEPROM_ADDRESS, somfyControllers);
    }
  }
}
 
 
void BuildFrame(unsigned long remoteID, unsigned int rollingCode, byte *frame, byte button)
{
  frame[0] = 0xA7;
  frame[1] = button << 4;
  frame[2] = rollingCode >> 8;
  frame[3] = rollingCode;
  frame[4] = remoteID >> 16;
  frame[5] = remoteID >>  8;
  frame[6] = remoteID;
 
  Serial.print("Frame         : ");
  for (byte i = 0; i < 7; i++)
  {
    if (frame[i] >> 4 == 0)
    {
      Serial.print("0");
    }
    Serial.print(frame[i], HEX); Serial.print(" ");
  }
 
  checksum = 0;
  for (byte i = 0; i < 7; i++)
  {
    checksum = checksum ^ frame[i] ^ (frame[i] >> 4);
  }
  checksum &= 0b1111;
 
  frame[1] |= checksum;
 
 
  Serial.println(""); Serial.print("Avec checksum : ");
  for (byte i = 0; i < 7; i++)
  {
    if (frame[i] >> 4 == 0)
    {
      Serial.print("0");
    }
    Serial.print(frame[i], HEX); Serial.print(" ");
  }
 
  for (byte i = 1; i < 7; i++)
  {
    frame[i] ^= frame[i-1];
  }
 
  Serial.println(""); Serial.print("Obfuscation    : ");
  for (byte i = 0; i < 7; i++)
  {
    if (frame[i] >> 4 == 0)
    {
      Serial.print("0");
    }
    Serial.print(frame[i], HEX); Serial.print(" ");
  }
  Serial.println("");
  Serial.print("Compteur  : "); Serial.println(rollingCode);
}
 
void SendCommand(byte *frame, byte sync)
{
  if (sync == 2)
  {
    PORTD |= 1<<PORT_TX;
    delayMicroseconds(9415);
    PORTD &= !(1<<PORT_TX);
    delayMicroseconds(89565);
  }
 
  for (int i = 0; i < sync; i++)
  {
    PORTD |= 1<<PORT_TX;
    delayMicroseconds(4*SYMBOL);
    PORTD &= !(1<<PORT_TX);
    delayMicroseconds(4*SYMBOL);
  }
 
  PORTD |= 1<<PORT_TX;
  delayMicroseconds(4550);
  PORTD &= !(1<<PORT_TX);
  delayMicroseconds(SYMBOL);
  
  for (byte i = 0; i < 56; i++)
  {
    if (((frame[i/8] >> (7 - (i%8))) & 1) == 1)
    {
      PORTD &= !(1<<PORT_TX);
      delayMicroseconds(SYMBOL);
      PORTD ^= 1<<PORT_TX;
      delayMicroseconds(SYMBOL);
    }
    else
    {
      PORTD |= (1<<PORT_TX);
      delayMicroseconds(SYMBOL);
      PORTD ^= 1<<PORT_TX;
      delayMicroseconds(SYMBOL);
    }
  }
  
  PORTD &= !(1<<PORT_TX);
  delayMicroseconds(30415);
}

vous comprenez le code que vous avez posté ?

Je suis débutant en Arduino j’apprends depuis peu, se que je comprends du code c’est qu’il est à l’écoute du moniteur série en attente d’une instruction.

Avec mon manque de maîtrise je suis forcément à coter… pouvez-vous donc m’éclairer ?

Au lieu d'attendre que quelque chose arrive sur Serial, comme il le fait, le programme doit attendre un appui sur un bouton.

je me refuse presque à lire un code qui fait

if (Serial.available())
  {
    String data = "";
    
    while (Serial.available())
    {
      char c = Serial.read();
      data += String(c);
      delay(10);
    }

tellement ça pique les yeux…

leur code n’est pas très robuste, si vous balancez une commande fausse la fonction BuildFrame ne sera pas appelée mais SendCommand() l’est quand même…

pour votre question lisez les tutos sur la gestion des boutone

Une fois que vous savez détecter l’appui sur un bouton appelez (une seule fois, pas tant que le bouton est appuyé) BuildFrame(remoteID, rollingCode, frame, XXXX);ou XXXX est la commande souhaitée puis ce qu’ils font dans la boucle de réception de commandes

 SendCommand(frame, 2);
      for (int i = 0; i < 2; i++)
      {
        SendCommand(frame, 7);
      }
  
      //Incrémente le compteur et le sauvegarde en mémoire
      somfyControllers.remotes[remotePosition].rollingCode++;
      EEPROM.put(EEPROM_ADDRESS, somfyControllers);

Je reviens auprès de vous après des heures de migraine, j’ai remplacé toute la partie “écoute sur moniteur série” par un digitalRead.

Lorsque j’appuie sur mon bouton, les commandes s’envoient correctement d’après le moniteur série, comme à l’origine, par contre le volet roulant ne réagit pas.

De plus je remarque que le compteur est plus élevé que quand je réutilise le programme d’origine.

Vais-je dans la bonne direction ?

Je joins la partie void loop() que j’ai modifiée.

void loop() {
  if  (digitalRead(Bouton) == HIGH) {

    String data = "m0";
    char serie = data[0];

    for (int i = 1; i < data.length(); i++)
    {
      char cRemotePosition = data[i];

      int remotePosition = cRemotePosition - '0';
      Serial.print("Commande "); Serial.println(remotePosition);

      Remote remote = somfyControllers.remotes[remotePosition];
      unsigned long remoteID = remote.remoteID;
      unsigned int rollingCode = remote.rollingCode;

      Serial.println("");
      if (serie == 'm')
      {
        Serial.println("Monte");
        BuildFrame(remoteID, rollingCode, frame, HAUT);
      }
      else if (serie == 's')
      {
        Serial.println("Stop");
        BuildFrame(remoteID, rollingCode, frame, STOP);
      }
      else if (serie == 'd')
      {
        Serial.println("Descend");
        BuildFrame(remoteID, rollingCode, frame, BAS);
      }
      else if (serie == 'p')
      {
        Serial.println("Prog");
        BuildFrame(remoteID, rollingCode, frame, PROG);
      }
      else
      {
        Serial.println("Code custom");
        BuildFrame(remoteID, rollingCode, frame, serie);
      }

      Serial.println("");
      SendCommand(frame, 2);
      for (int i = 0; i < 2; i++)
      {
        SendCommand(frame, 7);
      }

      //Incrémente le compteur et le sauvegarde en mémoire
      somfyControllers.remotes[remotePosition].rollingCode++;
      EEPROM.put(EEPROM_ADDRESS, somfyControllers);
    }
  }
}

j'ai pas vu les détails, mais déjà :

  if  (digitalRead(Bouton) == HIGH) {

tu testes l'état du bouton. Ce n'est pas ce qui t'intéresse.
Tu ne t'intéresses qu'au changement d'état du bouton, c'est à dire le moment où il passe de lâché à appuyé.
Dans ton code actuel, tant que le bouton est tenu appuyé, tu exécutes tout le tra-la-la en boucle à la vitesse maxi. Ce n'est probablement pas ce que tu veux.

Il faut donc une variable qui va mémoriser l'état actuel du bouton, et quand tu testes le bouton, tu n'envoies la sauce que si l'état a changé (et tu mémorises le nouvel état actuel)

bonsoir,
je rejoins biggil (du moins son point de vue) :

tu testes un BP, mais tu le testes en continu ... ça va donner un état 'on' ou 'off', mais tu ne sauras pas si entre 2 tests il a été relâché ou pas tant que tu n'auras pas mémorisé son état entre 2 lectures.

ce que biggil te dit, c'est qu'à chaque nouvelle lecture il faut comparer l'état actuel à l'état précédent : à toi maintenant de trouver l'astuce pour le faire ... et il te met sur la voie :

Il faut donc une variable qui va mémoriser l'état actuel du bouton

La seule chose que je connaisse pour mémoriser l'état d'un bouton c'est ça.

const int Bouton = 8;
int Etat_Bouton = 0;

void setup() {
  pinMode(Bouton, INPUT);

}

void loop() {
  if digitalRead(Bouton) == HIGH; {
    Etat_Bouton = ! Etat_Bouton;
  }

}

Mais je vous avoue ne pas trop savoir comment placer le tout, pour ne pas polluer le topic j'ai d'abord fait beaucoup d'essai, mais la je sèche.