Forum: Compiler & IDEs ESP8266 - MQTT - volatile variable


von Jörg (Gast)


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):
1
loop() {
2
  checkMQTT();
3
}
4
5
volatile int idleTime = 60000; // jede Minute
6
volatile unsigned int lastRun = millis();
7
8
void checkMQTT() {
9
  if( millis() - lastRun > idleTime) {
10
    // publish sensor data
11
    char[10] msg;
12
    itoa(idleTime, msg, 10); 
13
    client.publish(TOPIC_IDLETIME, msg, true);
14
  }
15
}
16
17
void callback(char* topic, byte* payload, unsigned int length) {
18
  char msg[length+1];
19
  for (int i = 0; i < length; i++) {
20
    Serial.print((char)payload[i]);
21
    msg[i] = (char)payload[i];
22
  }
23
  msg[length] = '\0';
24
25
  if(topic == SET_IDLE) {
26
    idleTime = atoi(msg);
27
    char[10] msg1;
28
    itoa(idleTime, msg1, 10); 
29
    client.publish(TOPIC_IDLETIME, msg1, true);
30
  }
31
}

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

von Eric B. (beric)


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.

von Johannes S. (Gast)


Lesenswert?

wo wird lastRun aktualisiert? So ist der Code etwas sehr reduziert.

von Rolf M. (rmagnus)


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.

von Eric B. (beric)


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.

von Jörg (Gast)


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.
1
void checkMQTT() {
2
  if( millis() - lastRun > idleTime) {
3
    // publish sensor data
4
    char[10] msg;
5
    itoa(idleTime, msg, 10); 
6
    client.publish(TOPIC_IDLETIME, msg, true);
7
8
    lastRun = millis();
9
10
  }
11
}

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

von Rolf M. (rmagnus)


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.

von Johannes S. (Gast)


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.

von Jörg (Gast)


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

von Jörg (Gast)


Lesenswert?

Ich kann einfach MQTT.fx nicht bedienen...

Hab auf das Topic gesendet, somit funktioniert meine Abfrageroutine noch 
nicht...
1
void callback(char* topic, byte* payload, unsigned int length) {
2
  char msg[length+1];
3
  for (int i = 0; i < length; i++) {
4
    msg[i] = (char)payload[i];
5
  }
6
  
7
  msg[length] = '\0';
8
  
9
  if(strncmp(topic, MQTT_TOPIC_CISTERN_ACTION_TEMPERATURE, strlen(MQTT_TOPIC_CISTERN_ACTION_TEMPERATURE)) == 0) {
10
    reportTemperature();
11
  } else
12
  if(strncmp(topic, MQTT_TOPIC_CISTERN_ACTION_DELAY, strlen(MQTT_TOPIC_CISTERN_ACTION_DELAY)) == 0) {
13
    idleTime = atoi(msg);
14
    char cstr[16];
15
    itoa(idleTime, cstr, 10);
16
    client.publish(MQTT_TOPIC_CISTERN_SETTINGS_DELAY2, cstr);
17
  } else 
18
  if(strncmp(topic, MQTT_TOPIC_CISTERN_TOPICS, strlen(MQTT_TOPIC_CISTERN_TOPICS)) == 0) {
19
    reportTopics();
20
  } else 
21
  if(strncmp(topic, MQTT_TOPIC_CISTERN_ACTION_DISTANCE_EMPTY, strlen(MQTT_TOPIC_CISTERN_ACTION_DISTANCE_EMPTY)) == 0) {
22
    distanceEmptyInCM = atoi(msg);
23
  } else
24
  if(strncmp(topic, MQTT_TOPIC_CISTERN_ACTION_DISTANCE_FULL, strlen(MQTT_TOPIC_CISTERN_ACTION_DISTANCE_FULL)) == 0) {
25
    distanceFullInCM = atoi(msg);
26
  }
27
}

hier scheint noch der Hund begraben. Mal sehen

Gruß
Jörg

von Jörg (Gast)


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!

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.