mikrocontroller.net

Forum: Compiler & IDEs ESP8266 - MQTT - volatile variable


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Jörg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich habe ein Problem mit meinem ESP8266 und MQTT.
Ich nutze Arduino IDE und die PubSubClient Bibliothek.

MQTT funktioniert soweit. Ich kann Sensordaten empfangen und Nachrichten 
an den ESP8266 kommen auch an.

Das einzige was nicht funktioniert ist eine variable per MQTT zu setzen.

Ziel: Ich möchte die Meldezeiten der Sensordaten über eine variable 
einstellen.

Umsetzung (vereinfacht, da Prüfung funktionieren):

loop() {
  checkMQTT();
}

volatile int idleTime = 60000; // jede Minute
volatile unsigned int lastRun = millis();

void checkMQTT() {
  if( millis() - lastRun > idleTime) {
    // publish sensor data
    char[10] msg;
    itoa(idleTime, msg, 10); 
    client.publish(TOPIC_IDLETIME, msg, true);
  }
}

void callback(char* topic, byte* payload, unsigned int length) {
  char msg[length+1];
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
    msg[i] = (char)payload[i];
  }
  msg[length] = '\0';

  if(topic == SET_IDLE) {
    idleTime = atoi(msg);
    char[10] msg1;
    itoa(idleTime, msg1, 10); 
    client.publish(TOPIC_IDLETIME, msg1, true);
  }
}


Wenn ich den Wert 300000 über MQTT sende, dann erhalte ich direkt die 
Antwort 300000 über den publish in der callback routine.

Leider bleibt aber idleTime auf 1 Minute da ich danach auf dem topic 
TOPIC_IDLETIME 60000 erhalte und auch die Sensordaten jede Minute 
kommen.

Habe schon versucht die Variable idleTime static zu setzen aber auch 
kein Erfolg. Ich dachte bisher - und so hat es auch immer funktioniert - 
das volatile die variable nicht weg optimiert.

idleTime wird nirgendwo anders im code verändert.

Woran könnte das liegen, was muss ich ändern?

Besten Dank für eure Hilfe.

Gruß
Jörg

Autor: Eric B. (beric)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg schrieb:
> void callback(char* topic, byte* payload, unsigned int length) {
...
>   if(topic == SET_IDLE) {

Da topic ein char * ist, vermute ich, dass es ein String ist. Strings 
kann man in C nicht mit einem einfachen == vergleichen.

Autor: Johannes S. (jojos)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wo wird lastRun aktualisiert? So ist der Code etwas sehr reduziert.

Autor: Rolf M. (rmagnus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eric B. schrieb:
> Jörg schrieb:
>> void callback(char* topic, byte* payload, unsigned int length) {
> ...
>>   if(topic == SET_IDLE) {
>
> Da topic ein char * ist, vermute ich, dass es ein String ist.

Bei MQTT werden alle Nachrichten mit einem "Topic" versendet, der ein 
String ist.

> Strings kann man in C nicht mit einem einfachen == vergleichen.

Man vergleicht damit nicht den Inhalt des Strings, sondern die Adresse. 
Ein char* ist ja ein Zeiger auf einen char. Es steht also eine Adresse 
drin. Bei einem Vergleich wird entspreichend auch diese Adresse 
verglichen, nicht der Inhalt des String.
Interessant wäre noch, wie SET_IDLE definiert ist.

Autor: Eric B. (beric)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rolf M. schrieb:
>> Strings kann man in C nicht mit einem einfachen == vergleichen.
>
> Man vergleicht damit nicht den Inhalt des Strings, sondern die Adresse.

Genau. ein strcmp() oder stncmp() an der Stelle löst wahrscheinlich das 
Problem des TO.

Autor: Jörg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ok, wie ich geschrieben habe, wurde der code vereinfacht.
Ich habe ja geschrieben, dass die Prüfungen stimmen, da ich den 
Quelltext zu Hause habe, hab ich es vereinfacht.
void checkMQTT() {
  if( millis() - lastRun > idleTime) {
    // publish sensor data
    char[10] msg;
    itoa(idleTime, msg, 10); 
    client.publish(TOPIC_IDLETIME, msg, true);

    lastRun = millis();

  }
}

lastRun = millis habe ich vergessen zu erwähnen, ist aber drin, sonst 
würde ich ja nie jede Minute einen Wert über MQTT erhalten.

strcmp verwende ich auch in der if-clause. Das funktioniert ja auch. 
Wenn ich einen Wert publishe über topic SET_IDLE, dann melde die 
Anwendung auch über MQTT topic TOPIC_IDLETIME die neue Einstellung, die 
ich gesendet habe.
Aber max. eine Minute später erhalte ich eine Nachricht über die 
Sensordaten und zum Schluss nochmals den Wert TOPIC_IDLETIME.
An dieser Stelle ich der Wert aber wieder auf dem initialen Wert.

Und genau das verstehe ich nicht.

Gruß
Jörg

Autor: Rolf M. (rmagnus)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Mit Codefragmenten, die grob so ähnlich ist wie das, was du tatsächlich 
machst und den ganzen Prosa-Beschreibungen dazu werden wir hier nicht 
weiter kommen. Zeige echten Code, der nicht so funktioniert, wie 
erwartet, dann hat man auch eine Chance, herauszufinden, warum er nicht 
funktioniert.

Autor: Johannes S. (jojos)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
richtig. Vielleicht resettet der ESP auch ständig und startet dann 
wieder mit dem 60s voreingestelltem Wert. Lass mal im setup() eine 
Glocke läuten um irgendwie anzuzeigen das ein Reset ausgeführt wurde. Im 
Broker müsste man das auch sehen wenn der geschwätzig ist.

Autor: Jörg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das mit dem Reset ist eine sehr interessante Idee.
Da werde ich heute abend mal etwas in die Setup-Routine einbauen.

Gruß
Jörg

Autor: Jörg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich kann einfach MQTT.fx nicht bedienen...

Hab auf das Topic gesendet, somit funktioniert meine Abfrageroutine noch 
nicht...
void callback(char* topic, byte* payload, unsigned int length) {
  char msg[length+1];
  for (int i = 0; i < length; i++) {
    msg[i] = (char)payload[i];
  }
  
  msg[length] = '\0';
  
  if(strncmp(topic, MQTT_TOPIC_CISTERN_ACTION_TEMPERATURE, strlen(MQTT_TOPIC_CISTERN_ACTION_TEMPERATURE)) == 0) {
    reportTemperature();
  } else
  if(strncmp(topic, MQTT_TOPIC_CISTERN_ACTION_DELAY, strlen(MQTT_TOPIC_CISTERN_ACTION_DELAY)) == 0) {
    idleTime = atoi(msg);
    char cstr[16];
    itoa(idleTime, cstr, 10);
    client.publish(MQTT_TOPIC_CISTERN_SETTINGS_DELAY2, cstr);
  } else 
  if(strncmp(topic, MQTT_TOPIC_CISTERN_TOPICS, strlen(MQTT_TOPIC_CISTERN_TOPICS)) == 0) {
    reportTopics();
  } else 
  if(strncmp(topic, MQTT_TOPIC_CISTERN_ACTION_DISTANCE_EMPTY, strlen(MQTT_TOPIC_CISTERN_ACTION_DISTANCE_EMPTY)) == 0) {
    distanceEmptyInCM = atoi(msg);
  } else
  if(strncmp(topic, MQTT_TOPIC_CISTERN_ACTION_DISTANCE_FULL, strlen(MQTT_TOPIC_CISTERN_ACTION_DISTANCE_FULL)) == 0) {
    distanceFullInCM = atoi(msg);
  }
}

hier scheint noch der Hund begraben. Mal sehen

Gruß
Jörg

Autor: Jörg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OH MANN,

# in der subscription vergessen...

Dann funktioniert es auch auf Anhieb.

Fehler 1: Falsche Bedienung MQTT.fx; Publish auf falsches topic.
Fehler 2: # im topic von client.subscribe() vergessen.

Danke für eure Mühen!

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.