Go Down

Topic: Node red + MQTT + callback (Read 512 times) previous topic - next topic

steven63

Bonjour

Actuellement j'utilise le protocole MQTT pour allumer une pompe d'extérieur et l'éteindre en envoyant avec node red une information  "PompeON" ou "PompeOFF".

Je souhaiterai pouvoir envoyer en plus une valeur pour définir le temps qu'elle doit resté allumé.

Je pensais faire comme ceci par exemple envoyé "PompeON10000" extraire le mot PompeON pour lancer l'allumage et utilisé 10000 pour définir un delay .

Je suis juste arrivé à extraire PompeON mais pas le temps, car j'ai voulu extraire les données grace à un tableau mais sans résultat.

J'ai essayé d'envoyer avec node red les données sous cette forme  Payload: {pompe, 10000};
pour pouvoir créer un tableau à la réception mais je n'es pas réussi

Code: [Select]
void callback(char* topic, byte* payload, unsigned int length) {
  int i = 0;
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i=0;i<length;i++) {
    Serial.print((char)payload[i]);
  }
  for (i = 0; i<length; i++) {
  message_buff[i] = payload[i];
  }
  message_buff[i] = '\0';
  String msgString = String(message_buff);
  Serial.println("Payload: " + msgString);
int test[] = msgString; // impossible d'y convertir en tableau ou je mit prend mal.
}



Pourriez vous m'aider cordialement ou m'orienter sur une solution.

Voila le code basic mqtt que j'utilise et que je veus améliorer.

Code: [Select]

//Ethernet mqtt////////////////////////////////////////////////////////////////////
#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
byte mac[]    = {  0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xEF };
IPAddress ip(192, 168, 0, 31);
#define mqtt_server "192.168.0.52"
#define mqtt_user "1234"     //s'il a été configuré sur Mosquitto
#define mqtt_password "1234" //idem
EthernetClient ethClient;
PubSubClient client(ethClient);
char message_buff[100];
//Fin Ethernet mqtt////////////////////////////////////////////////////////////////

void setup() {
Serial.begin(9600);
//Ethernet mqtt////////////////////////////////////////////////////////////////////
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
Ethernet.begin(mac, ip);
//Fin Ethernet mqtt////////////////////////////////////////////////////////////////
}
void loop() {

//Ethernet mqtt////////////////////////////////////////////////////////////////////
 if (!client.connected()) {
    reconnect();
  }
 client.loop();
//Fin Ethernet mqtt////////////////////////////////////////////////////////////////
}

//Ethernet mqtt////////////////////////////////////////////////////////////////////
void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect("arduino2", mqtt_user, mqtt_password)) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish("Infos2/arduino2","hello");
      // ... and resubscribe
      client.subscribe("home/piscinerequetes");  
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(2000);
    }
  }
}
//Fin Ethernet mqtt////////////////////////////////////////////////////////////////

void callback(char* topic, byte* payload, unsigned int length) {
  int i = 0;
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i=0;i<length;i++) {
    Serial.print((char)payload[i]);
  }
  for (i = 0; i<length; i++) {
  message_buff[i] = payload[i];
  }
  message_buff[i] = '\0';
  String msgString = String(message_buff);
  Serial.println();
  Serial.println("-----------------------");
  Serial.println("Payload: " + msgString);

  if (msgString == "PompeON" ) {
  String payload = "{";
  payload += "\"EtatPompe\":"; payload += "1";
  payload += "}";
  // Send payload
  char attributes1[100];
  payload.toCharArray( attributes1, 100 );
  client.publish("home/piscinemsg", attributes1);
  Serial.println( attributes1 );
  delay(500);
  }
 }



iznobe

Salut ,

vu que vous recuperez un string dans votre variable , ce que je ferais pour faire simple , je changerais pompeOFF en pompeOF ce qui donne le meme nombre de caracteres pour pompe ON et pompeOF  histoire de ne pas creer de soucis plus tard .

ensuite lors de la reception du string il suffit d' utiliser les fonctions qui vont bien .

dans un premier temps enlever le nombre de carateres de la chaine correspondant a pompeON ( et pompeOF ) grace a la fonction : strcpy
ensuite convertir les caracteres correspondant a la durée en chiffre grace a la fonction : atol
mini serveur domotique : https://forum.arduino.cc/index.php?topic=493039.0

iznobe

ca pourrait donner genre un truc comme ca a partir de PompeON10000 :

Code: [Select]
completeMessage = msgString;
strcpy(chaineDurée, (completeMessage + 6));
duree = atol(chaineDurée);


bien sur il faut faire les declarations de variables qui correspondent etc .

c '  est juste pour vous montrer le cheminement d' extraction . :)
mini serveur domotique : https://forum.arduino.cc/index.php?topic=493039.0

hbachetti

#3
May 06, 2020, 12:16 pm Last Edit: May 06, 2020, 12:17 pm by hbachetti
Si tu veux éviter les ennuis, évite les objets String, sauf si tu disposes d'un ESP8266 ou ESP32.

Code: [Select]


char message_buff[] = "PompeON10000";

void setup()
{
  Serial.begin(115200);
  unsigned long t = 0;
  if (strncmp(message_buff, "PompeON", 7)) {
    Serial.println("msg=PompeON");
    t = atol(message_buff+6);
  }
  else if (strncmp(message_buff, "PompeOFF", 8)) {
    Serial.println("msg=PompeOFF");
    t = atol(message_buff+7);
  }
  else {
    Serial.println("Commande inconnue");
  }
  Serial.print("t="); Serial.println(t);
}

void loop()
{
}
Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

steven63

Merci à tous vous m'avez bien orienté :

J'ai compilé ca en 2 fois car j'y arrive pas en 1 fois^^

J'envoie ca a l'arduino : Payload: test:10000

J'utilise en premier la boucle for pour extraire  "test" grace au 4 premiers caractères (pas top)
et une deuxieme boucle pour extraire la valeur aprés le ":"

Je ne comprend pas pourquoi si je fais
Code: [Select]
Serial.println(test[0]);
Je devrai obtenir la valeur test mais j'obtiens 0 à la place.
(ca doit être encore une merde avec char^^)

Code: [Select]
void callback(char* topic, byte* payload, unsigned int length) {
  int i = 0;
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i=0;i<length;i++) {
    Serial.print((char)payload[i]);
  }
  for (i = 0; i<length; i++) {
  message_buff[i] = payload[i];
  }
  message_buff[i] = '\0';
  String msgString = String(message_buff);
  Serial.println();
  Serial.println("-----------------------");
  Serial.println("Payload: " + msgString);

  char message2_buff[5];
  for (i = 0; i<4; i++) {
  message2_buff[i] = payload[i];
  }

  char delimiters[] = ":";
  char* valtest;
  valtest = strtok(message_buff, delimiters);
  int test[] = {0,0};
  for(int i = 0; i < 2; i++){
    test[i] = atoi(valtest);
    valtest = strtok(NULL, delimiters);
  }
  Serial.println(test[1]);
  Serial.println(message2_buff);
  delay(1000);

hbachetti

Si tu changes d'avis sans arrêt ...
On t'a bien orienté mais apparemment tu ne tiens pas compte de l'orientation.
Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

iznobe

#6
May 06, 2020, 12:44 pm Last Edit: May 06, 2020, 12:50 pm by iznobe
Quote
Code: [Select]
int test[] = {0,0};
  for(int i = 0; i < 2; i++){
    test[i] = atoi(valtest);
    valtest = strtok(NULL, delimiters);

tu definis un tableau a 2 entrées de int .

atoi => convertit un string en nombre a conditions que ca ne soit pas des lettres , donc Serial.println(test[0]);

renvoi rien .

seulement la 2eme partie devrait etre convertie en int , la premiere , : " test " devrait rester en string , tout simplement :P

voir mon 1er post et celui de henry , qui explique tout deux la meme chose .

Henry t ' as quasiement fait tout le boulot dans sa reponse ! en +
mini serveur domotique : https://forum.arduino.cc/index.php?topic=493039.0

steven63

Dsl mais en fait ce que j'ai écris ces ce que j'avais bidouillé en attendant d'avoir des avis sur le forum, du coup j'avais presque trouvé une solution seul mais effectivement je n'es pas encore appliqué vos idées je me mais au travail tous de suite^^

hbachetti

strtok() n'est pas difficile à utiliser.
Il suffit d'affecter le premier jeton au nom de la commande (un pointeur).

Code: [Select]


char message_buff[] = "PompeON:10000";

void setup()
{
  Serial.begin(115200);
  const char delimiters[] = ":";
  char *tok;
  char *cmd = 0;
  unsigned long t = 0;

  tok = strtok(message_buff, delimiters);
  if (tok != 0) {
    cmd = tok;
    tok = strtok(NULL, delimiters);
    if (tok != 0) {
      t = atoi(tok);
    }
    else {
      Serial.println("#: Commande incorrecte");
    }
  }
  else {
    Serial.println("@: Commande incorrecte");
  }
  Serial.print("cmd="); Serial.println(cmd); Serial.print("t="); Serial.println(t);
}

void loop()
{
}


C'est vraiment comme tu veux.
Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

steven63

J avais pas vu ton dernier commentaire je vais  regardé ton code, mais la j'ai besoin d'une pause.


Moi j'ai fait ca de mon coté et au final j'arrive bien à séparé le non et la valeur.

Code: [Select]
  char* val;
  val = strtok(message_buff, ":");
  Serial.println(val);
  int test[] = {0,0};
  for(int i = 0; i < 2; i++){
    test[i] = atoi(val);
    val = strtok(NULL, ":");
  }
  Serial.println(test[1]);

hbachetti

#10
May 06, 2020, 03:04 pm Last Edit: May 06, 2020, 03:06 pm by hbachetti
Sauf que tu appelles 3 fois strtok() pour 2 jetons.
2 fois suffisent.

A moins que tu aies encore changé ton format pour passer 2 valeurs : test:10000:1234
Dans ce cas  OK, à ceci près que la chaîne "test" est perdue car la variable val sert 3 fois.
Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

steven63

#11
May 06, 2020, 07:19 pm Last Edit: May 06, 2020, 07:25 pm by steven63
Quote
Sauf que tu appelles 3 fois strtok() pour 2 jetons.
A cause de ca ?
Code: [Select]
i < 2
j'ai voulu le passé a 1 car j'utilise que 2 cases dans le tableau "{0,0}" mais si je le passe à 1 ca ne marche plus .

Quote
la chaîne "test" est perdue car la variable val sert 3 fois
Tu me conseil de faire comment la j'avoue que je suis arrivé au bout de mes competences sachant que j'ai commencé à apprendre les tableau et les manipulé que hier soir ^^.

Ah j'ai peus être encore une idée ^^
En tous ces très gentil de me critiqué j'avance à grand pas vers un code correct ^^
Code: [Select]
char* val;
  char* val2;
  val = strtok(message_buff, ":");
  Serial.println(val);
  val2 = strtok(atoi(message_buff), ":");



hbachetti

J'ai donné une solution en #8.
Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

Go Up