Ok, I think I got it, thanks to @123 .
An MQTT binary sensor HAS to know its state, and it can be done either by providing value_template
that returns ON/OFF (default payload_on
/payload_off
values) OR making sure payload_on
and payload_off
are the only values that being published to that topic.
Having only payload_on
and payload_off
defined and allowing something that is not matched by above mentioned payloads to be published to that topic triggers that warning.
So basically that warning means: look, your MQTT switch received a message, but couldnât react (as there is no corresponding rule in a form of payload_xxx
OR value_template
), something is wrong with your configuration.
Pretty obvious, isnât it.
And there are at least 3 ways to get rid of that warning with binary_sensors:
- Provide
value_template
definition that returns only ON/OFF - Provide
payload_on
andpayload_off
AND make sure these are the only 2 values that are allowed in that topic. - Provide
value_template
definition that returns onlypayload_on
orpayload_off
values
Iâm off to fix my switches
But itâs not wrong OpenMQTT binary sensors work fine while removing the four lines in the binary_sensor.py.
Anyway, I canât test it but for binary sensors that only use one value (switches, PIR sensors) an automation that forwards each payload into its separate mqtt topic could be used and then change the binary sensor topic (for open door sensors or other devices that send two codes it needs templating).
- platform: "mqtt"
name: "friendly_name"
state_topic: "home/433toMQTT/code_from_device"
payload_on: 'code_from_device'
payload_off: 'off'
force_update: true
off_delay: 1
- alias: OpenMQTT forward
initial_state: True
trigger:
- platform: mqtt
topic: 'home/433toMQTT'
action:
- service: mqtt.publish
data_template:
topic: 'home/433toMQTT/{{trigger.payload}}'
payload_template: '{{ trigger.payload}}'
yes, itâs not wrong.
I presume the author just wanted to make easier debugging situations like âWhy on Earth my sensor is not working?!â as potentially that can happen.
And yes, you can get rid of these warnings just by fixing your config and not touching the HA code, result!
yes, there are many ways to skin a cat
I use input_booleans and this automation (one per device)
- alias: "[int] pir__catch_code__groung_floor__hall"
initial_state: true
trigger:
platform: mqtt
topic: !secret rf_bridge__topic
condition:
condition: template
value_template: "{{ (trigger.payload_json['value'] == 13937454) and (states.input_boolean.pir_groung_floor_hall.state == 'off') }}"
action:
- service: input_boolean.turn_on
data:
entity_id: input_boolean.pir_groung_floor_hall
- delay: !secret pir__reset_indicator_interval
- service: input_boolean.turn_off
data:
entity_id: input_boolean.pir_groung_floor_hall
but maybe itâs time to enable value as topic suffix and replace it with MQTT binary sensor with off_delayâŚ
UPDATE: here is my version for PIRs - instead of input_boolean and automation I can have just
- platform: mqtt
name: pir_1st_floor_landing
state_topic: !secret pir_1st_floor_landing_topic
value_template: 'ON'
device_class: motion # this bit can be moved to customize_glob.yaml for all pir_*
off_delay: !secret pir_off_delay
I like it!
I imagine the automation you posted was meant to represent the concept and not a working example? These lines below will produce a horrendously long MQTT topic because the typical payload is a long string in JSON format.
- service: mqtt.publish
data_template:
topic: 'home/433toMQTT/{{trigger.payload}}'
payload_template: '{{ trigger.payload}}'
Ideally, you want to demultiplex tele/rf_bridge/RESULT
using each sensorâs unique identifier, or its unique payload, instead of its entire payload. Iâve already supplied links to two other relevant examples of demultiplexer automations (see above), but itâs worth repeating at least one of them.
In this post, the assumption is the RF buttons are uniquely identified by Sync
.
- alias: 'sonoff bridge demultiplexer'
hide_entity: true
trigger:
platform: mqtt
topic: tele/sonoff/RESULT
action:
service: mqtt.publish
data_template:
topic: "home/button/{{trigger.payload_json.RfReceived.Sync|string }}"
payload: 'ON'
Binary_sensors are defined for each RF button:
- platform: mqtt
name: "Button 1"
state_topic: "home/button/13550" # <--- 13550 comes from Sync
off_delay: 1
- platform: mqtt
name: "Button 2"
state_topic: "home/button/13560"
off_delay: 1
If Sync
canât be used to uniquely identify the RF device, then the recourse is to use the deviceâs payload which is often represented by Data
.
action:
service: mqtt.publish
data_template:
topic: "home/button/{{trigger.payload_json.RfReceived.Data|string }}"
payload: 'ON'
- platform: mqtt
name: "Button 1"
state_topic: "home/button/2B4AC"
off_delay: 1
This works as long as the RF devices only report when they are on
and not off
such as certain models of motion sensor, RF button, and contact sensor (thatâs the same constraint you mentioned for your automation example).
If the RF devices report both their on
and off
states (two payloads), yet have no unique identifier within the payload, then this simplistic demultiplexing automation is no longer useful. It will produce two topics per sensor and thatâs unusable for MQTT Sensor or Binary Sensor.
For this situation, the automationâs data_template
requires a more complex template that is aware of each sensorâs Data
payload, representing on
and off
, and forwards it to the sensorâs single topic. Itâs not difficult, just more work.
Nope; it is a working automation for use with OpenMQTT 433Mhz gateway (codes received from the 433Mhz devices are up to 10 char in length if not using the JSON functionality for the payload). Agree that using JSON payload in the topic is a no go.
For PIRs with only one state I use the method given by @123
Am I missing something* or is there a down side to this solution, because I canât see one? All the other solutions seem to require more code.
*Serious question, not trying to be difficult.
None that Iâm aware of.
FWIW, if there are many sensors, my preferred solution is the demultiplexer because I believe itâs more efficient. Hereâs why:
- Imagine you have ten binary_sensors and all are subscribed to one topic:
tele/rf_bridge/RESULT
. - Each time the topic has a new payload itâs evaluated ten times (once by each binary_sensor).
Using a demultiplexer:
- Each time the topic has a new payload itâs evaluated by the automation which forwards the payload to a specific topic.
- The binary_sensor subscribed to the topic evaluates the payload.
Thatâs a maximum of two evaluations for every payload as opposed to ten per payload.
So if you only have 2 or 3 devices then the demultiplexer automation and the template-based solution are equally efficient. However, when there are many devices, the demultiplexer has the advantage.
Good point. But (and I havenât entirely thought this throughâŚ) how does this method deal with a mix of sensors some of which have two states and some only one. Specifically, what if you wish to retain the states of door/window sensors which have two states but do not want to retain states of PIR sensors which have only one?
The demultiplexer would presumably need a (possibly very) complex template to decide when to retain?
I offer you the âdeluxeâ solution.
Letâs say we have three RF sensors:
- A contact sensor that reports both its
on
andoff
states (assume âA1Aâ = âONâ and âA2Aâ = âOFFâ). - A motion sensor that reports only its
on
state (assume âB1Bâ = âONâ). - A button that only reports its
on
state (assume âC1Câ = âONâ).
-
Because the contact sensor reports both of its states, the demultiplexer automation can use
retain: true
when publishing to the contact sensorâs topic. When Home Assistant restarts, it will re-subscribe to the contact sensor topicâs and receive its current (retained) state from the broker. -
The other two sensors (motion sensor and button) donât report their
off
state. We will use theoff_delay
option to automatically reset them tooff
. However, this technique does not publishoff
to their respective MQTT topic (i.e. once set toon
the topic will always showon
). Therefore the demultiplexer automation should publish to their topics usingretain: false
. Otherwise, usingretain: true
, when you restart Home Assistant, it would erroneously set these sensors toon
.
To make the automation neater, and avoid elaborate if-elif-else trees, we will use dictionaries.
This one defines which commands belongs to a sensorâs topic.
{ 'A1A':'sensor1', 'A2A':'sensor1', 'B1B':'sensor2', 'C1C':'sensor3' }
This one defines which commands represents ON
or OFF
.
{ 'A1A':'ON', 'A2A':'OFF', 'B1B':'ON', 'C1C':'ON' }
Finally, this one defines which commands are retained or not.
{ 'A1A':'true', 'A2A':'true', 'B1B':'false', 'C1C':'false' }
Putting it all together, we get this demultiplexer automation. If it receives a command that is not defined in the dictionaries, it will publish it to home/unknown
(with retain: false
).
- alias: 'RF_Bridge demultiplexer'
hide_entity: true
trigger:
platform: mqtt
topic: tele/RF_Bridge/RESULT
action:
service: mqtt.publish
data_template:
topic: >-
{% set cmd = trigger.payload_json.RfReceived.Data %}
{% set commands = { 'A1A':'sensor1', 'A2A':'sensor1', 'B1B':'sensor2', 'C1C':'sensor3' } %}
{% set topic = commands[cmd] if cmd in commands.keys() else 'unknown' %}
home/{{topic}}
payload: >-
{% set cmd = trigger.payload_json.RfReceived.Data %}
{% set commands = { 'A1A':'ON', 'A2A':'OFF', 'B1B':'ON', 'C1C':'ON' } %}
{% set payload = commands[cmd] if cmd in commands.keys() else cmd %}
{{payload}}
retain: >-
{% set cmd = trigger.payload_json.RfReceived.Data %}
{% set commands = { 'A1A':'true', 'A2A':'true', 'B1B':'false', 'C1C':'false' } %}
{% set retain = commands[cmd] if cmd in commands.keys() else 'false' %}
{{retain}}
Configuring the binary sensors becomes an easy task:
- platform: mqtt
name: 'Bathroom Door'
state_topic: 'home/sensor1'
device_class: Door
- platform: mqtt
name: 'Hallway Motion'
state_topic: 'home/sensor2'
off_delay: 5
device_class: motion
- platform: mqtt
name: 'Button1'
state_topic: 'home/sensor3'
off_delay: 1
FWIW, I tested all of this and can confirm it works.
Indeed you do!
Thanks, that is not only a great solution but a bit of an education for me too. Tomorrow I was planning on embarking on some
Iâll let you know if it doesnât
EDIT: So far, so good! Thank you once again.
This seems like a very ingenious solution. Do we still need to have a sensor that represents the current RFRecieved Data from the SonoffRF unit in order for the the trigger to work?
Ie thisâŚ
- platform: mqtt
state_topic: 'tele/RF_Bridge/RESULT'
value_template: '{{ value_json.RfReceived.Data }}'
name: "Sonoff RF Bridge"
expire_after: 1
This is the demultiplexer automationâs trigger:
trigger:
platform: mqtt
topic: tele/RF_Bridge/RESULT
No other sensor is needed to trigger it.
Sincere thanks for sharing this solution. Equally impressive and effective.
My working and tested solution (for alarming purposes)âŚ
# ALARM - vklopi alarm DSC spodaj (RF kljuÄ C)
- id: '30006'
alias: 'ALARM - vklopi alarm DSC spodaj (RF kljuÄ C)'
hide_entity: true
trigger:
- platform: mqtt
topic: "tele/Sonoff-RF-Bridge/RESULT"
- platform: mqtt
topic: "tele/Sonoff-RF-Bridge2/RESULT"
condition:
condition: and
conditions:
- condition: template
value_template: "{{ trigger.payload_json.RfReceived.Data == '!RF-SECRET-RECEIVED-CODE-KEY-C' }}"
- condition: state
entity_id: alarm_control_panel.DSC5020
state: disarmed
action:
service: alarm_control_panel.alarm_arm_away
data:
entity_id: alarm_control_panel.DSC5020
code: !SECRET-DSC-ALARM-CODE
# ALARM - izklopi alarm DSC spodaj (RF kljuÄ D)
- id: '30007'
alias: 'ALARM - izklopi alarm DSC spodaj (RF kljuÄ D)'
hide_entity: true
trigger:
- platform: mqtt
topic: "tele/Sonoff-RF-Bridge/RESULT"
- platform: mqtt
topic: "tele/Sonoff-RF-Bridge2/RESULT"
condition:
condition: or
conditions:
- condition: template
value_template: "{{ trigger.payload_json.RfReceived.Data == '!RF-SECRET-RECEIVED-CODE-KEY-D' }}"
- condition: state
entity_id: alarm_control_panel.DSC5020
state: armed_away
- condition: state
entity_id: alarm_control_panel.DSC5020
state: armed_home
action:
service: alarm_control_panel.alarm_disarm
data:
entity_id: alarm_control_panel.DSC5020
code: !SECRET-DSC-ALARM-CODE
Before I had binary_sensor which was switched ON/OFF via payload ON/OFFâŚ
I assume you are aware that using a 433MHz RF button to arm/disarm an alarm panel is not very secure. The RF codes are easily detectable and reproducible. You would need to (minimally) use a rolling-code system and, as far as I know, RF bridges based on stock and Tasmota firmware donât support rolling-code.
If you are aware of the vulnerability and feel the risk is acceptable then allâs well. However, be advised that for a professionally-installed residential, especially commercial, alarm system, it would be unacceptable to use an unencrypted and unchanging RF signal to control it.
Thanks for your solution.
I spent last 2 days playing with various ways of handling my PIRs, smoke detectors, door contacts, RF wall switches and remotes.
First I enabled adding code to each mqtt message and changed all my config to work with it.
Have to say itâs great for devices that only send one code (PIRs, smoke detectors) - you just need to define corresponding mqtt binary sensors.
For devices with two or more codes things get complicated as apart from creating mqtt switch/sensors you need automations to forward every command to a corresponding switch/sensor topic.
It worked, but I didnât like it because of extra automations and need for plenty of !secret
constants.
Then I tried your solution. Have to say in that form itâs ok for demonstration, but not suitable if you have a real setup even with a modest number of devices.
First of all, I believe itâs hard to maintain 3 separate but interlinked dicts if you have plenty of devices, many possibilities to make a mistake.
Second, in my setup (Hass.io @ RPi3 with Mosquitto add-on) mqtt messages take a while to appear and therefore reposting mqtt messages makes it even slower (not dramatically, but still).
I went for a proper dict that contains records with code, command and retain flag:
'sensor/smoke_detector/1st_floor/landing': {'codes': {5997800: {'state': 'detected', 'command': 'ON'}}},
'wall_switch/1st_floor/master_bedroom': {
'codes': {
10952785: {'state': 'on', 'command': 'ON'},
10952784: {'state': 'off', 'command': 'OFF'}
}
}
That means I have to use nested for
loops instead of simple lookup:
{% set devices = {...}
{% set code = trigger.payload_json.value | int %}
{% set ns = namespace(topic='unknown') %}
{% for device, definition in devices.items() %}
{% for state_code, details in definition.codes.items() if state_code | int == code %}
{% if loop.first %}
{% set ns.topic = device %}
{% endif %}
{% endfor %}
{% endfor %}
home/{{ ns.topic }}
It might add up to slow response as well.
And my major complain is the size of dict AND the fact that I need to replicate it to each template (command, topic and retain). It doesnât look great and I donât like to copy it every time I add/change something in devicesâ description.
Any thoughts on how it can be improved, or maybe a better solution?
Migrate to NUC
MicroSD card will fail exactly when you needed it the most, anyway.
When I started designing the âdeluxeâ demultiplexer automation, I thought of using an âall-in-oneâ dictionary where each value is an array containing topic, payload, and retain.
Example: x
{% set x = { 'A1A':['sensor1','ON','true'], 'A2A':['sensor1','OFF','true'], 'B1B':['sensor2','ON','false'], 'C1C':['sensor3','ON','false'] } %}
The problem is the scope of x
is limited to within the option where itâs defined. That means, as you have also discovered, you have to define the dictionary three times: one for topic:
, another for payload:
and yet another for retain:
.
Although Jinja2 supports macros, their scope is also limited to where they are defined. See this thread for more information: Jijnja2 macro in template
Given that I had to define the dictionary three times, I chose to make it compact. Each one of the three dictionaries only contains whatâs needed for its associated option:
topic { 'A1A':'sensor1', 'A2A':'sensor1', 'B1B':'sensor2', 'C1C':'sensor3' }
payload { 'A1A':'ON', 'A2A':'OFF', 'B1B':'ON', 'C1C':'ON' }
retain { 'A1A':'true', 'A2A':'true', 'B1B':'false', 'C1C':'false' }
Yes, this makes it more challenging to construct because each commandâs data is spread over three dictionaries. However, this is a âone-timeâ editing exercise and the dictionaryâs structure is simple (basic key:value pairs).
I agree interlinked dictionaries arenât optimal but, seeing that weâre obliged to have three of them (due to scope limitations) itâs a way of keeping them compact. The alternative is to use the âall-in-oneâ style of dictionary (shown above) and use three full copies (for topic, payload, and retain). Effectively, this is what youâve done but with a more complex dictionary design.
Second, in my setup (Hass.io @ RPi3 with Mosquitto add-on) mqtt messages take a while to appear and therefore reposting mqtt messages makes it even slower (not dramatically, but still).
I have not noticed a delay on my system. Iâm running Home Assistant on an old laptop and the Mosquitto broker runs on a Raspberry Pi 3B. Theyâre separate hosts yet MQTT communications are virtually instantaneous.
Any thoughts on how it can be improved, or maybe a better solution?
If you donât like the demultiplexer solution, thereâs always the other solution I offered: create a value_template
for each sensor that always returns a valid state.