I asked for some help on the forums with this, and it was suggested I post in the forums as it may be a little complex. Hoping someone can help get me started!
In short, I currently have a device configured like this (topic, etc has been simplified for clarity):
This works great. Toggling the switch writes either {"value":"3"} or {"value":"4"} to the command topic as it should, and the state is shown correctly.
However, the device actually has 2 switches (we’ll call them A and B), not one, and they are both reported by same MQTT topic. The values are:
Value | A | B
------|-----|---
1 | on | off
2 | off | on
3 | on | on
4 | off | off
Until now, I’ve only been interested in toggling both switches together, so switching the mode value from 3 to 4 worked fine. But now I’d like to toggle them independently.
I think what I need is a template switch, but I’m unclear how to combine that with MQTT. Again, I think the way it should work is that I make two switches - A and B.
A would be configured such that it is on if value is 1 or 3, else off. B would be configured to be on if value is 2 or 4. Then the payload_on and payload_off fields for each switch would need to check the value of the other switch and set the appropriate value. Am I on the right lines?
That would work for reading the switch status, but not for writing it. Turning on either switch would actually turn on both switches, and similarly turning either switch off would turn them both off.
Sorry, missed the part that you now what to operate them independently.
The problem is that they share the same commands. If a 3 is received it is understood by both switches to mean they should turn on (or off if a 4 is received).
So let’s say our solution for operating them independently is to cease using 3 and 4 and only use 1 and 2. However, that’s still not truly independent because, according to your table, the two switches maintain opposite states (send a 1 and it turns on A and turns off B; send a 2 and A is turned off and B is turned on).
As you already know, there’s no command_template option so we are unable to use a template to reformat the published payload in an MQTT Switch. However, what we can do is use a ‘middleman’ automation to achieve the same thing.
Each MQTT Switch publishes to a ‘middleman’ topic (for example, temp/my_device_a).
An automation is subscribed to the ‘middleman’ topic.
It converts a received payload and publishes it to things/my-device/mode/write.
MQTT Switches
- platform: mqtt
name: "My Device A"
state_topic: things/my-device/mode/read
value_template: "{{ 'ON' if value_json.value in ['1', '3'] else 'OFF' }}"
command_topic: temp/my_device_a
- platform: mqtt
name: "My Device B"
state_topic: "things/my-device/mode/read"
value_template: "{{ 'ON' if value_json.value in ['2', '3'] else 'OFF' }}"
command_topic: temp/my_device_b
Automation
- alias: 'my device command converter'
mode: queued
trigger:
- platform: mqtt
topic: temp/my_device_a
- platform: mqtt
topic: temp/my_device_b
action:
- service: mqtt.publish
data_template:
topic: things/my-device/mode/write
payload: >
{% set one = '{\"value\":\"1\"}' %}
{% set two = '{\"value\":\"2\"}' %}
{% set three = '{\"value\":\"3\"}' %}
{% set four = '{\"value\":\"4\"}' %}
{% set other_on = is_state('switch.my_device_' ~ 'b' if trigger.topic[-1:] == 'a' else 'a', 'on') %}
{% if trigger.topic[-1:] == 'a' %}
{% if trigger.payload == 'ON' %}
{{ three if other_on else one }}
{% else %}
{{ two if other_on else four }}
{% endif %}
{% else %}
{% if trigger.payload == 'ON' %}
{{ three if other_on else two }}
{% else %}
{{ one if other_on else four }}
{% endif %}
{% endif %}
I do have NodeRED running so had considered doing the normalization / denormalization there, but at the moment NodeRED isn’t being used for any critical operations (it’s mostly data gathering) so I was loathe to introduce it into the mix.
I just stumbled upon the mqtt_template_switch custom component and have managed to get it working with that. Full implementation is below in case anyone stumbles across this.
Thanks @123 for your help in working this one out!