Cloud replacement for vacuum robots enabling local-only operation
View the Project on GitHub Hypfer/Valetudo
Newcomer Guide Why Valetudo? Why not Valetudo? Getting Started Supported Robots Rooting Essentials Buying Supported Robots Media & Content Creators
Implementation Overview Capabilities Overview Upgrading Firmware Updates
Valetudo Companion (Android) Valetudo Tray Companion Valeronoi Lovelace Valetudo Map Card I Can't Believe It's Not Valetudo node-red-contrib-valetudo Fun & Games Other Noteworthy Projects
MQTT Home Assistant Node-RED openHAB
FAQ Style Guide Troubleshooting
Valetudo supports publishing status data and receiving commands from MQTT.
The following autodiscovery protocols are supported:
They are both optional and mutually compatible: you can enable both at the same time or none at all.
Since the MQTT code is heavily based on the capabilities system you may want to first give a look to how capabilities, status attributes, and the robot object work.
The MQTT OOP structure is heavily influenced by the Homie convention. This page will also contain lots of references to it, so make sure you grasp the fundamental concepts of the convention before proceeding further:
To keep the codebase maintainable and prevent entire classes of potential issues, the code tries to define and restrict the responsibilities of each component as follows:
MqttHandle
and subclasses
HassComponent
and subclasses
MqttHandle
sMqttController
HassController
MqttController
and HassComponent
sHandles are subclasses of MqttHandle
. They are designed to map exactly to the levels of the Homie convention topology.
Specifically:
RobotMqttHandle
⇒ Homie deviceNodeMqttHandle
⇒ Homie nodePropertyMqttHandle
⇒ Homie propertyTwo more classes are present that further extend from these and bridge the handles to Valetudo’s internals:
RobotStateNodeMqttHandle
maps to StatusStateAttribute
CapabilityMqttHandle
maps to Capability
RobotMqttHandle
maps to ValetudoRobot
)Handles are assigned into a tree structure:
RobotMqttHandle
, being the root handle, registers to the MqttController
NodeMqttHandle
s register to RobotMqttHandle
PropertyMqttHandle
s register to NodeMqttHandle
This structure simplifies and unifies publication to the MQTT broker, Instead of publishing data directly, any handle may “refresh” itself.
When a handle is refreshed it will ask the MqttController
to retrieve a fresh payload from it and publish it to its
designated topic.
Refreshing is recursive: whenever a handle is refreshed all children are refreshed as well. Attached Home Assistant components will also be refreshed, but we will discuss this later.
RobotMqttHandle
is special since it is the root handle. It maps to a Homie device. It is mainly responsible for
checking which capabilities the robot supports and registering the corresponding handles.
It will also subscribe to the robot status and register matching handles as soon as the corresponding attributes are added (therefore it’s normal if they don’t show up until the robot is fully connected and the status is polled).
Finally, it handles the registration of MapNodeMqttHandle
, which as the name suggests provides map data.
RobotStateNodeMqttHandle
children all map to Homie nodes. Their peculiarity is that they provide infrastructure to
subscribe to the robot state.
This is accomplished by providing a list of status attribute matchers, which the handle will subscribe to.
When a status event occurs, the handle and all its children are refreshed.
CapabilityMqttHAndle
children also map to Homie nodes. The class itself inherits from RobotStateNodeMqttHandle
,
therefore it is as well able to subscribe to robot status events.
It is encouraged, whenever possible, to handle status data in a capability handle as opposed to a status handle whenever actions performed on the capability will be reflected into and match exactly to a status attribute event.
This is true, for example, for both PresetSelectionCapability
s, since setting a preset will usually result in the same
value being reflected back to the status attribute: you send low
and you get back low
.
This is NOT true, for example, for BasicControlCapability
. While actions performed on it will directly affect
StatusStateAttribute
, the status event won’t match exactly: you perform START
but you get back CLEANING
.
PropertyMqttHandle
, as the name suggests, maps to Homie properties. However, unlike the previously discussed handles,
property handles do not have subclasses and should not be subclassed.
Property handles are in fact defined and registered in-line in the capability/status handle constructors. All data is provided as parameters to the constructor.
These handles handle the actual data to be published and receive commands. However, they never interact directly with
the MQTT client. They instead must be provided with at least one of the following callbacks: a getter
to retrieve
fresh data to be published; a setter
to perform operations with the data received from MQTT.
When a setter
callback is provided, property handles will be subscribed to a /set
topic.
When a setter
is provided but a getter
is not provided, the property will act as a command property according to
the Homie convention: the data received in the /set
topic will automatically be reflected back to the main topic to
acknowledge the command.
Home Assistant uses a very different workflow. Instead of defining a structure, it defines components which may or may not map to some capabilities’ behavior.
In some instances it will try to adapt to an existing MQTT structure and allow you to provide topics and payloads for accomplishing different tasks. In some other cases it will try to impose its own structure.
This makes it difficult to share data with the previously defined structure. However, Valetudo provides enough
abstraction to make this easier: HassComponent
.
Home Assistant components may subscribe to topics. However, this should be avoided when possible: most features can and should be implemented by providing Hass with the handle topics.
Components are not handles, they are a separate entity. However, in order to share data with handles, they are attached to and managed by the handle they share information with.
Components may be attached to any type of handle, from the robot handle to the property handle. For instance, the map component is attached to the map handle.
Whenever an handle is refreshed, the attached Hass components are refreshed as well.
Some components are trickier. For example, the VacuumHassComponent
is attached to the robot handle since that’s what
it shares most data with. However, it also needs access to the fan speed and a reference to the BasicControlCapability
command topic in order to send cleaning control commands.
This is accomplished using HassAnchor
.
HassAnchor
is a utility to share data from the handle that manages some type of information to the hass component that
needs it.
There are two types of HassAnchor
: plain anchors and topic references. The implementation is exactly the same, the
distinction has been put in place, once again, to separate responsibilities: “plain” anchors may only be used in
payloads, topic references may only be used in autoconfiguration payloads.
HassAnchor
s can be thought of as fancy “template variables”. Hass component payloads are in fact provided as regular
JavaScript objects. For any value that is not immediately available, an HassAnchor
may be retrieved and used in its
place.
Of course, the value isn’t going to jump into existence on its own: some other component needs to provide it. This is a
responsibility of handles: whenever they share some value with a hass component, they should also post()
it into the
anchor every time they retrieve it for their own needs.
HassAnchor
s are eventful: whenever a handle posts a value into an anchor, the hass component that uses it is
automatically refreshed and its payload published to MQTT.
If for whatever reason an anchor doesn’t hold any value when the hass component payload is requested for publication, the publication will be delayed. This means that you should only use anchors if you are sure they will be populated, otherwise the hass component will stay in a limbo forever.
Here’s a bunch of things to keep in mind when adding new MQTT handles and Home Assistant components.
HassAnchor
$attributes
- they won’t be available if Homie is disabledThis section does not describe general MQTT troubleshooting, but rather troubleshooting of problems that can occur when writing new code.
Status handles are only published once the StatusAttribute
they subscribe to first appears. If it does appear, but the
handle isn’t published, you may have an incorrect attribute matcher.
Both status and capability handles have to be registered into the designated lists inside the HandleMappings.js
file
for them to be loaded.
You can enable debug.debugHassAnchors
in the configuration and set the log level to trace
. It will print a report
whenever an anchor is blocking publication for a Hass component.
Cloud replacement for vacuum robots enabling local-only operation
View the Project on GitHub Hypfer/Valetudo
Newcomer Guide Why Valetudo? Why not Valetudo? Getting Started Supported Robots Rooting Essentials Buying Supported Robots Media & Content Creators
Implementation Overview Capabilities Overview Upgrading Firmware Updates
Valetudo Companion (Android) Valetudo Tray Companion Valeronoi Lovelace Valetudo Map Card I Can't Believe It's Not Valetudo node-red-contrib-valetudo Fun & Games Other Noteworthy Projects
MQTT Home Assistant Node-RED openHAB
FAQ Style Guide Troubleshooting