MQTT initial state

Hello!

I’ve been setting up some lights via MQTT and I wanted to make an inquiry.

The system works fine but I have problems when the system restarts because the state of the switch is unknown. I thought about creating a rule that changes the state of the switch to OFF when it starts but this would not be correct in the scenario when the lights are on and the system is restarted.

Any help on how the rule should be? or how it should be solved?

.items

Switch Verde {channel="mqtt:topic:mosquitto:prueba:verde1"}

.things

Bridge mqtt:broker:mosquitto "Mosquitto" @ "System" [ host="x.x.x.x", secure=false ]
{	
    Thing topic prueba "S" {
        Channels:
            Type switch : verde1 [  commandTopic="esp8266/4"
]
    }
}

The general recommendation is to have your device send retained mqtt messages. That way openhab always get the most recent state the devices reported on startup, even if the device changed state after oh was shut down.

1 Like

Do you have persistence service setup on openhab?

If you dont it is most likely what you are missing. Thi s service will remember the states of device when openhab restarts.

Unless the switch changed in the mean time then openhab will get it wrong.
Having the device publish a retained message ensures that when openHAB reconnects to the broker it will get the latest state from the broker.

how can I do that through text configuration?

with

retained=true

on .things?

That only changes the messages that is sent from openhab, you need to configure that on your device. If you tell us what it is someone might be able to point you in the right direction.

thanks!

It’s a ESP8266 module.

With what firmware?

Do you mean the Arduino code loaded into ESP?

Yes

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
  
const char* ssid = "x";
const char* password = "zzzzz";
const char* mqtt_server = "x.x.x.x";

WiFiClient espClient;
PubSubClient client(espClient);

const int ledGPIO5 = 5;
const int ledGPIO4 = 4;

void setup() {
  pinMode(ledGPIO4, OUTPUT);
  digitalWrite(ledGPIO4, LOW);
  
  pinMode(ledGPIO5, OUTPUT);
  digitalWrite(ledGPIO5, LOW);
  
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
}

void setup_wifi() {
  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("WiFi connected - ESP IP address: ");
  Serial.println(WiFi.localIP());
}

void callback(String topic, byte* message, unsigned int length) {
  Serial.print("Message arrived on topic: ");
  Serial.print(topic);
  Serial.print(". Message: ");
  String messageTemp;
  
  for (int i = 0; i < length; i++) {
    Serial.print((char)message[i]);
    messageTemp += (char)message[i];
  }
  Serial.println();
  
  if(topic=="esp8266/4"){
      Serial.print("Changing GPIO 4 to ");
      if(messageTemp == "1"){
        digitalWrite(ledGPIO4, HIGH);
        Serial.print("On");
        client.publish("esp8266/4/state","ON");
      }
      else if(messageTemp == "0"){
        digitalWrite(ledGPIO4, LOW);
        Serial.print("Off");
        client.publish("esp8266/4/state","OFF");
      }
  }
  if(topic=="esp8266/5"){
      Serial.print("Changing GPIO 5 to ");
      if(messageTemp == "1"){
        digitalWrite(ledGPIO5, HIGH);
        Serial.print("On");
        client.publish("esp8266/5/state","On");
      }
      else if(messageTemp == "0"){
        digitalWrite(ledGPIO5, LOW);
        Serial.print("Off");
        client.publish("esp8266/5/state","Off");
      }
  }
  Serial.println();
}

void reconnect() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    if (client.connect("ESP8266Client")) {
      Serial.println("connected");
      client.subscribe("esp8266/4");
      client.subscribe("esp8266/5");
    } else 
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

void loop() {
  int salida4 = digitalRead(ledGPIO4);

  if (!client.connected()) {
    reconnect();
  }
  if(!client.loop())
    client.connect("ESP8266Client");
}
  1. persistence does NOT work with MQTT
  2. retaining messages can be double edged sword (especially with switches) so be carefull

in the code you need to do this

message.topic = (char*)topic.c_str();
message.payload = (char*)topic.c_str();
message.length = topic.length();
message.retained = true;

client.publish(&message);

or

client.publish("topic","payload",lenth,true)
1 Like

It does now. But it is better to rely on retain messages (If you know how to use them) and refreshed payloads.

Maybe I am doing something wrong but for my setup I have 0 retained messages. I also only have powered mqtt devices so if they lose power my whole house is off.

Since they boot to last known state and openHAB is the last thing up it all just works.

The only time I would have an issue is if a manual change occurred while openHAB was shutdown. This problem exists for every device in my system and the assumption is openHAB is always online.

Seeing this thread shows many people have various methods of how they manage their devices, what works for one may not work for another. The key takeaway is find what works for you and implement your system that way. There is not one correct answer.

As a beginner we have to ask for feedback and try different methods until we find the one that works for us.

I’m not really tracking it from 2.5M1 anyway good to hear that it’s now not undefiing values as before :wink:

As before it was not working I’ve build my system in way that reboot of OH is not really an issue and everything will repair itself in like 2-3minutes anyways.
No need of retains and/or persistence at all.

Add to your code periodic state update of your device, every minute or so. You would not need retained messages.
Also consider using tasmota or other well known esp software. It has this out of the box.

1 Like

A little update…

After reading your answers, I changed the items and things files from OH and the Arduino code.

For “prevention” or for testing, create an extra item that tells me the status you read from MQTT. I got that after rebooting the system the status of both items is kept updated.

.items

Switch Verde {channel="mqtt:topic:mosquitto:prueba:verde1"}
String Verdestatus "Verde [%s]"  {channel="mqtt:topic:mosquitto:prueba:verde2"}

.things

    Thing topic prueba "S" {
        Channels:
            Type switch : verde1 [  commandTopic="esp8266/4",
                                    retained=true,
                                    stateTopic="esp8266/4/state"
                                    ]
            Type string : verde2 [  stateTopic="esp8266/4/state"]
    }
}

Arduino

...............................
  if(topic=="esp8266/4"){
      Serial.print("Changing GPIO 4 to ");
      if(messageTemp == "1"){
        digitalWrite(ledGPIO4, HIGH);
        Serial.print("On");
        client.publish("esp8266/4/state","ON",true);
      }
      else if(messageTemp == "0"){
        digitalWrite(ledGPIO4, LOW);
        Serial.print("Off");
        client.publish("esp8266/4/state","OFF",true);
      }
  }
........................

Regardless of whether the system works for now. How do you think? Is there any extra code or any errors to be rescued?

I’ll be testing how the system behaves for a few days and then I’ll close the issue.

third parameter in the arduino code is message lenth, your modification will (probably) get you error
you need to send this

client.publish("esp8266/4/state","OFF",3,true);

After writing the “update”, I checked the item, and switch off and nothing… so yes, something is wrong, I’ll test your code now and i’ll tell you

whit ON, will I write

client.publish("esp8266/4/state","ON",2,true);

?

yes