Problem
In the MQTT1 binding there was a feature that let us filter messages published to a given topic and only pass those that match a given REGEX to the transformation and/or on to the Item. This was useful to handle devices that publish messages to a single well known topic for all their devices.
For example, the official firmware from the vendor of Shelly devices have a request/response protocol over MQTT to get meta data about the devices (IP address, MAC address, firmware version, whether there is a firmware update, etc.). Each individual device has their own topic you can send “announce” to. In response, the device will publish a JSON message to shellies/announce
. ?!
OK, well we have to deal with it if we don’t want to have to install alternative firmware.
Each Shelly device has a unique name. For example shelly1-25A289. The JSON published to shellies/announcement
includes this unique name.
Approach
The MQTT2 binding lacks direct support for a REGEX filter as a separate parameter. But it does support chaining transformations on incoming messages. So we can chain a REGEX transformation that matches and returns the entire message but only if it contains the unique name. Next we chain that to a JSONPATH transformation to extract the desired field. Thus, the Channel will ignore the messages posted for some other device and only pass the messages for this device to the JSONPATH.
Based on my tests there is no error in the log when the REGEX does not match the message, which is exactly what we want.
When we are done, the Thing will look something like:
Request Channel
MQTT command topic: shellies/<shelly name>/command
Custom On/Open value: announce
Custom Off/Closed value: announce
Replace <shelly name>
with the name of your specific device which you can find on config web page for the device. You need to know this anyway to command the device. For example, shellies/shelly1-25A289/command
.
Any time the Switch linked to this Channel receives any sort of command, it will publish “announce” to the device’s command topic.
IP Address
MQTT state topic: shellies/announce
Incoming value transformations: REGEX:(.*<shelly name>.*)∩JSONPATH:$.ip
The trick is the REGEX needs to match the full message, hence the parens around the full expression. But we only want to pass on messages that include this device’s name. As above, replace <shelly name>
with the real name. For example REGEX:(.*shelly1-25A289.*)∩JSONPATH:$.ip
.
The rest of the fields in the JSON can be extracted in the same way using a different JSONPATH expression.
Commentary
Obviously, this approach can be used in different and more powerful ways. For example, the REGEX can both filter and select just a portion of the message, not just filter the message. Any transformation can follow the REGEX. And more than two transformations can be chained. This should give us the same flexibility, if not more than the MQTT 1 REGEX filter.