See Retained huh, what is it good for? Absolutely. The only time it leads to unwanted behaviors is when you are using a retained message for something that is momentary (e.g. a message from a button push) or the message itself is ephemeral (e.g. a temp reading that is only really valid for five minutes at which point it will be replaced with a new value). In all other cases where the message represents a state, the retained flag should be set to true. This is how MQTT was designed to be used and it is how we should be using it in OH.
See https://github.com/openhab/openhab2-addons/issues/5879#issuecomment-524520334 for the research I did into the retained flag.
Properly using the retained flag would indeed replace restoreOnStartup for these Items and furthermore will allow devices to also be restored to their last commanded state when they restore their connection with the broker. This is as the MQTT protocol was designed and how it is expected to be used.
The behavior that the binding does with restore on startup has been deemed to be in error and there is an issue opened to make the binding not replace restored Items with UNDEF when it first comes up.
This is actually going to change as a result of the issue I linked to above. The binding will not set the Items to UNDEF any longer once that issue is addressed. But as you will see when you read that thread, I agree that the way the binding behaves now is correct but the proper solution is to rely on the retained flag instead of restoreOnStartup.
This actually is not working (i.e. the flag doesn’t actually do anything on the broker thing) and J-N-K is going to remove the flag. See https://github.com/openhab/openhab2-addons/issues/6100. You can define the retained flag on a Generic Thing Channel by Channel basis and you have the option to set a retained flag with the publishMQTT Actions. And J-N-K will add the option to set the flag for the LWT message. But the setting on the broker Thing will go away and it isn’t even working right now.
To elaborate on that a bit, the whole purpose of the retained flag is to allow subscribers to get the latest state from the publisher even if the subscriber didn’t happen to be online and connected when that state was published. So if the MQTT is set up properly, any Item that you would use restoreOnStartup to restore it’s state restored would more properly have the publisher of that message publish it as a retained message in the first place.
In cases where the message represents something ephemeral like a button press or a temperature reading that is only valid for a certain period of time, leaving the Items as UNDEF shouldn’t matter because they probably shouldn’t have been restoreOnStartup in the first place since the state is ephemeral, and if the publisher is working, it will get updated soon enough anyway.
But this is indeed behavior that is different from how most other bindings work.
In that case though the channel represents a state, which in MQTT would properly be published as a retained message. When the device has an ephemeral event like a motion detection, the device immediately publishes that value. So it could be proper for the binding to set that Channel to UNDEF. But the zwave binding doesn’t make a distinction between ephemeral events and states. For MQTT, that distinction is a little bit more apparent though, hence the conflict.
I lost the argument on the PR and really, if you are properly using MQTT retained messages it doesn’t matter. The binding will work properly either way, assuming that restoreOnStartup continues to occur before the binding starts up. We will have a problem though if restoreOnStartup values start to overwrite retained messages retrieved by the binding.
It depends. Like I said, if MQTT retained messages are used as designed, then Items that you would want to use restoreOnStartup on don’t need that because the latest state is stored on the broker. This is superior to restoreOnStartup because the publisher might publish a new message while OH was offline. With restoreOnStartup you would completely miss that state. With retained you would get the latest state from the device on re connection to the broker.
If the message is ephemeral, than using restoreOnStartup shouldn’t be used on those Items in the first place. UNDEF or NULL is the proper state because you don’t know how old that data restored actually is. It may no longer be valid or useful. Or it may represent an action that has already been acted upon.
Your Rules should be handling NULL and UNDEF in the first place. You should never assume in a Rule that an Item has a usable state.
Beyond that, there are many use cases where one needs to know whether the states being used are the most recent and up to date. Who wants to control their HVAC based on a thermometer that stopped reporting hours ago?
Even after the update, one should use retained for any MQTT message that represents a persistent state.