MQTT und die Payload

Mehr
25 Mär 2021 16:24 #759 von SvenScherf
SvenScherf erstellte das Thema MQTT und die Payload
Hallo zusammen,

ich bin neu unterwegs mit den ESPs und deren Programmierung..

Bis dato habe ich auch einiges hinbekommen auch wenn mir die Stings OK Array in Char doch einiges an Probleme bereitet wenn man von VB, VBA usw. kommt.

Aktuell beiße ich mir die Zähne an der MQTT Payload aus.
Ich habe einen fhem Broker laufen und dem ich zum testen über MQTT.fx mit Topic und payload füttere.

Bei den Bespielen die ich gefunden habe findet man immer diese Zeile

void callback(char* topic, byte* payload, unsigned int length)


als Funktionsheader. Das byte* payload sagt doch eigentlich aus, dass die Rückgabe in byte sprich Zahlen 0-255 sein soll oder ?

Wenn dem so ist warum bekomme ich dann auch Text zurück ??

Bei dem folgenden Code habe ich das Problem wenn ich dem Topic die Payload mit abc mitgebe erhalte ich abc
und die Stinglänge ist 4.

Wenn ich der Payload nun abcd mitgebe erhalte ich ⸮bcd"⸮⸮?⸮⸮⸮?⸮ @
und die Stringlänge ist 16. :smiley-confuse:
Bei einer Payload von 123 erhalte ich 123 und bei 1234 erhalte ich 1234"⸮⸮?⸮⸮⸮?⸮ @.


Ich verstehe es nicht.


Hier mein Beispielcode mit der Callback Funktion.
#include <ESP8266WiFi.h> // Klasse für WiFi Verbindungen
#include <PubSubClient.h> // Klasse für MQTT Verbindungen
#undef MQTT_KEEPALIVE
#define MQTT_KEEPALIVE 60

const int ledPin1 = 12;
const int ledPin2 = 4;
const int tasterPin1 = 5;
const int tasterPin2 = 14;
const int blaueLED = 2;
int i;
int rssi;
int startup = 0;
int cnt = 10;

const char* versionstr = "0.1"; // Programmverion
const char* ssid = "xxxxxxxxxxxxxxxxxxxx";
const char* password = "xxxxxxxxxxxxxxxxxxx";
const char* mqtt_brocker = "000.000.000.000";
char* clientname = "TestSystem";

char rssistring[4];
char myIpString[24];
char mqttB_str[40] = "MQTT";
char mqtt_str[40] = "hallo";

WiFiClient espClient; // Deklarieren vom Object espClient mit dem ein Verbindung zu einer bestimmten IP Adresse hergestellt werden kann
PubSubClient client(espClient); // Deklarieren vom Object client welcher den Konstruktor vom zuvor erstellen WiFiClient empfängt

void setup_wifi(){
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    cnt = cnt - 1;
    Serial.print(".");
    if (cnt < 1 ){
      ESP.restart();
    }
    delay(2000);
  }
  cnt = 10; // reset cnt nach erfolgreichem reconnect
  rssi = WiFi.RSSI();
  Serial.println(rssi);
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());  

}

void reconnect() {
    while (!client.connected()) {
        Serial.println("MQTT Verbindungsversuch...");
        if (client.connect(clientname)) {
          Serial.println("MQTT Verbindung hergestellt");
          cnt = 10; // reset cnt nach erfolgreichem connect
          
          if (startup == 1) {
            strcpy(mqtt_str,mqttB_str);
            strcat(mqtt_str,"startup");
            client.publish(mqtt_str,"StartUp");
            startup = 2;
          }
          strcpy(mqtt_str,mqttB_str);
          strcat(mqtt_str,"version");
          client.publish(mqtt_str,versionstr);
          strcpy(mqtt_str,mqttB_str);
          strcat(mqtt_str,"relais/1");
          client.subscribe(mqtt_str);
          strcpy(mqtt_str,mqttB_str);
          strcat(mqtt_str,"relais/2");
          client.subscribe(mqtt_str);



          IPAddress myIp = WiFi.localIP();
          sprintf(myIpString, "%d.%d.%d.%d", myIp[0], myIp[1], myIp[2], myIp[3]);
          strcpy(mqtt_str,mqttB_str);
          strcat(mqtt_str,"ip");
          client.publish(mqtt_str,myIpString);
          sprintf(rssistring, "%d",rssi);
          strcpy(mqtt_str,mqttB_str);
          strcat(mqtt_str,"rssi");          
          client.publish(mqtt_str, rssistring);


          
         } else {        
            Serial.print("failed, rc=");
            Serial.print(client.state());
            Serial.println(" retrying in 5 seconds");
            cnt = cnt - 1;
            if (cnt < 1 ){
              ESP.restart();
            }
            digitalWrite(LED_BUILTIN, LOW);
            delay(2000);
            digitalWrite(LED_BUILTIN, HIGH);
            delay(2000);
        }
    }
}

void callback(char* topic, byte* payload, unsigned int length) {
    Serial.print("Received message [");
    Serial.print(topic);
    Serial.print("] ");
  
    char msg[length+1];
    Serial.println("*********************");
    for (int i = 0; i < length ; i++) {
        // Serial.print((char)payload[i]);
        msg[i] = (char)payload[i];
        Serial.print("Zähler: ");
        Serial.println(i, DEC);
        Serial.print("Zeichen: ");
        Serial.println(msg[i]);
        Serial.println();
    }
    msg[i] = '\0';
    Serial.print("*********************");
    // Serial.println(length);
  
   // Serial.println(msg.length(), DEC);
    String myString = String(msg);
    Serial.println();
    Serial.print("Payload: ");
     // msg[length] = '&#92;&#48;';
    Serial.println(myString);
    Serial.println(myString.length());
    Serial.println(sizeof(msg));    
    
    if(strcmp(topic, "MQTT/TestSystem/relais/1") == 0){
      if(strcmp(msg,"open")==0){
          digitalWrite(ledPin1, HIGH);
      } else if(strcmp(msg,"closed")==0){
          digitalWrite(ledPin1, LOW);
      }
    } else if(strcmp(topic, "MQTT/TestSystem/relais/2") == 0){
      if(strcmp(msg,"on")==0){
          digitalWrite(ledPin2, HIGH);
      } else if(strcmp(msg,"off")==0){
          digitalWrite(ledPin2, LOW);
      }
    }
    memset(msg,'\0',sizeof(msg));
}  


void setup()
{
  Serial.begin(115200);
  Serial.println();
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
  pinMode(blaueLED, OUTPUT);
  pinMode(tasterPin1, INPUT);
  pinMode(tasterPin2, INPUT);
  digitalWrite(blaueLED,HIGH);
  strcat(mqttB_str,"/");
  strcat(mqttB_str,clientname);
  strcat(mqttB_str,"/");      

  
  setup_wifi();
  
  client.setServer(mqtt_brocker, 1883);
  client.setCallback(callback);
  reconnect();
}



void blinker(int a, int b) {
  for(i=4;i>=0;i--){
    digitalWrite(blaueLED,LOW);
    delay(a);
    digitalWrite(blaueLED,HIGH);
    delay(b);  
  }
}

void startDeepSleep(){
  Serial.println("Going to deep sleep...");
  ESP.deepSleep(0);
}


void loop(){


  if (!client.connected()) {
      reconnect();
  }

  if (digitalRead(tasterPin1)  == LOW){
    //Serial.println("Taster 1 = low");
    digitalWrite(ledPin1,HIGH);
    delay(1000);
    digitalWrite(ledPin1,LOW);
  }else{
    Serial.println("Taster 1 = high");
  
  }
  if (digitalRead(tasterPin2) == LOW){
    digitalWrite(ledPin2,HIGH);
    delay(1000);
    digitalWrite(ledPin2,LOW);
  }
  blinker(200,100);
  client.loop();

}

Hier dann die Ausgaben im Monitor
abc =
18:47:25.030 -> Received message [MQTT/TestSystem/relais/1] *********************
18:47:25.030 -> Zähler: 0
18:47:25.030 -> Zeichen: a
18:47:25.030 ->
18:47:25.030 -> Zähler: 1
18:47:25.030 -> Zeichen: b
18:47:25.030 ->
18:47:25.030 -> Zähler: 2
18:47:25.030 -> Zeichen: c
18:47:25.030 ->
18:47:25.030 -> *********************
18:47:25.030 -> Payload: abc
18:47:25.030 -> 3
18:47:25.030 -> 4

abcd =
18:48:40.099 -> Received message [MQTT/TestSystem/relais/1] *********************
18:48:40.099 -> Zähler: 0
18:48:40.099 -> Zeichen: a
18:48:40.099 ->
18:48:40.099 -> Zähler: 1
18:48:40.099 -> Zeichen: b
18:48:40.099 ->
18:48:40.099 -> Zähler: 2
18:48:40.099 -> Zeichen: c
18:48:40.099 ->
18:48:40.099 -> Zähler: 3
18:48:40.099 -> Zeichen: d
18:48:40.099 ->
18:48:40.099 -> *********************
18:48:40.099 -> Payload: abcd"⸮⸮?⸮⸮⸮?⸮ @
18:48:40.099 -> 16
18:48:40.099 -> 5

Nachdem ich mit der Bibliothek "PubSubClient.h" die oben im Code verwende zu zurecht kam habe ich mir die Bibliothek "EspMQTTClient.h" angeschaut.

Hier bekomme ich die Payload schön zurück aber ich kann hier meine Relais nicht schalten.
Ich weiß nicht wie ich die Rückgaben(Payload) vergleichen soll. Es ist wieder das char, char* und String Thema.
Da stehe ich immer noch auf Kiegsfuß.

Kann mir hier jemand eine Schubs geben damit ich es kapiere ?

Viele Dank und Grüße

Sven

P.S. Derzeit nutze ich einen NodeMCU

Bitte Anmelden oder Registrieren um der Konversation beizutreten.

Mehr
27 Mär 2021 19:06 #761 von Greenhouse
MQTT und die Payload
Hallo SvenScherf,

Deine Annahme, daß byte * einem Zahlenwert entspricht ist nicht ganz richtig - um nicht zu sage falsch.

Der * hinter der Typenbezeichnung zeigt an, daß es sich um einen Pointer des jeweiligen Typs handelt.
Du kannst das vergleichen mit der Variable topic (char*). Dort wird ein Zeiger (Speicheradresse) auf den ersten Buchstaben übergeben.
Bei der Variablen payload verhält sich das gleich. Hier erhälts Du einen Zeiger auf das erste Zeichen (Byte) der Payload Kette.
In der for Schleife wird diese Kette durchlaufen und die einzelnen Zeichen nach msg übertragen. Am Ende der for Schleife ist msg ein Abbild von payload.
Da im klassischen C ein String mit einem 0 Zeichen abgeschlossen wird, erfolgt nach der for Schleife der Befehl msg = 0.

Das ganze hat aber noch wenig mit Deinem Fehlerbild zu tun.
Ich vermute, daß der Wert der Variablen length nicht korrekt übergeben wird.
Baue mal in der Callback Funktion vor die for Schleife eine Ausgabe der Variablen length ein
[Serial.println (length); ]
Dann siehst Du welche Länge ankommt.

Ich habe mich bislang noch nicht mit MQTT beschäftigt und kann deher nicht sagen, in welchem Format die Daten übertragen werden. Es könnte sein, daß der Payload ebenfalls eine 0 terminierte Zeichenfolge ist und die length Variable nicht zu berücksichtigen ist.
Dann müsste Deine for Schleife bei payload == 0 abbrechen.

Viel Erfolg
Gruß Greenhouse
Folgende Benutzer bedankten sich: supporter

Bitte Anmelden oder Registrieren um der Konversation beizutreten.

Mehr
29 Mär 2021 17:51 #762 von SvenScherf
MQTT und die Payload
Hallo,

vielen lieben Dank für deine Unterstützung und der Erklärung.
Die Variable lenght wird/wurde richtig übergeben.
Der Witz an der Sache war ja wenn ich drei Zeichen in die Payload geschrieben habe wurden dies drei korrekt ausgegeben und length hatte die richtige Länge.
Habe ich der Payload 4 Zeichen übergeben kam die wirre Ausgabe und lenght gab mir 16 zurück.

Okay nun geht es aber und die Fehlerursache lag hier.
In der callback Funktion war folgendes definiert char msg[length+1];

Dies scheint so falsch zu sein obwohl ich es so irgendwo hier übernommen habe .

In dem Code habe ich es dann wie folgt abgeändert.
#define MSG_BUFFER_SIZE (50)
char msg[MSG_BUFFER_SIZE];


So scheint es richtig zu sein und funktioniert.
Meine Relaiskarte kann ich nun auf fhem(Smarthome) richtig schalten.

Vielen Dank und Grüße

Sven

Bitte Anmelden oder Registrieren um der Konversation beizutreten.

Powered by Kunena Forum