Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to set retained config to /set topic #677

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from

Conversation

labodj
Copy link
Contributor

@labodj labodj commented May 15, 2020

It's useful when:

  • You have a device that doesn't need to restore it's state after a power loss or a reboot.
  • You use this library in a device used as a "forwarder" for another device state that can change on its own and you want to be sure that /set topic is aligned with the current "virtual" state.

Example:
I'm using this library in a ESP32 connected to a Controllino Maxi via Serial, they communicate with Json payloads, ESP32 stores the state of Controllino as "virtual" state.
ESP32 "virtual" state does not matter, it's there only for code convenience, Controllino will always override it.

Controllino has many things controlled, it can change the state of controlled devices

  • On its own (example: internal timer).
  • With an external input (example: attached button).
  • With a command sent by ESP32.

ESP32 will configure it's name and nodes in setup() and will act as a bidirectional forwarder of states in loop().

I don't need the state to be restored upon power loss or reboot because:

  • Controllino has it's own default state at boot.
  • It can even restore previous state if I want.

I want the /set topic to be always aligned with the current state of Controllino, since the /set topic is only set when a "Homie Controller" wants to change the state of Controllino remotely I'm using overwriteSetter(true) method to override it when Controllino state changes on its own.

If ESP32 reboots (for whatever reason) it will automatically read the retained /set state ond forward it to Controllino, it can be avoided if /set topic is not retained, so I added setSetRetained(bool retain) method to SendingPromise.

To use this setup I created a custom HomieNode derived class that, among other things, stores bool setTopicState and this send method (very simplified and ugly version) that sends the new state to MQTT

/**
 * @brief Send state to proper MQTT state topic.
 * 
 * If a message is received right after a callback (MQTT -> set state -> new state) it doesn't overwrite the setter.
 * If a mesage is received without a callback (Controllino -> new state) overwrites the setter to keep it in sync.
 * 
 * @param state state to set
 */
void CustomNode::sendState(bool state) const
{
    const String stateToSend = state ? "true" : "false";
    if (this->setTopicState != stateToSend) // Controllino -> new state -> align "set" topic -> ignore next callback
    {
        this->setProperty("state").overwriteSetter(true).setSetRetained(false).send(stateToSend);
    }
    else // MQTT -> set state -> new state
    {
        this->setProperty("state").send(stateToSend);
    }
}

Clearly the callBack method must be modified to ignore the callback if /set is == bool setTopicState

An ugly simplifed example:

auto CustomNode::callBack(const HomieRange &range, const String &value) -> bool
{
    ...
    this->setTopicState = static_cast<bool>(value == "true"); // New state
    const bool storedState = this->getControllinoState()
    if (this->setTopicState == storedState)
    {
        return true; // No need to send the message, the stored state and state to send are equal
    }
    ...
}

It's useful when you have a device that doesn't need to restore it's state after a power loss or a reboot.
It's even more useful when you use this library in a device used as a "forwarder" for another device state.
@labodj
Copy link
Contributor Author

labodj commented May 15, 2020

It's also should be noted that following Homie v4 specifications

A Homie controller publishes to the set command topic with non-retained messages only.

The default behavior of this library is the opposite, and I know that this library is 3.0.1 compliant, but with my code you can let the user choose the default behavior.

@euphi
Copy link
Member

euphi commented May 26, 2020

This was discussed for Homie V4.

For reading the old state it was proposed to read the retained message of the property itself and not the set topic.

@euphi
Copy link
Member

euphi commented May 26, 2020

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants