Sonoff RF Bridge. Strategies for receiving data

The important issue is, i have 3 RF bridge, and i have 4 binary sensor activated by 4 key of a RF remote and i configured each key that go on or off with the same key/code, but if i receved the code with 2 RF bridge i can see the binary sensor go on and immediately go off because i receive the same MQTT message 2 times.
Not important issue is too many MQTT traffic, i have 7 PIR that send the code 4 times, and i can see many mqtt message.

EDITED:
this the configuration of the bynary sensor:

  - platform: mqtt
    name: "rem 1-k1"
    state_topic: "home/RF433/rem_old_key1"
    value_template: "{%if is_state(entity_id,\"on\")-%}OFF{%-else-%}ON{%-endif%}"
    force_update: true
    device_class: power
    
  - platform: mqtt
    name: "rem 1-k2"
    state_topic: "home/RF433/rem_old_key2"
    value_template: "{%if is_state(entity_id,\"on\")-%}OFF{%-else-%}ON{%-endif%}"
    force_update: true
    device_class: power

  - platform: mqtt
    name: "rem 1-k3"
    state_topic: "home/RF433/rem_old_key3"
    value_template: "{%if is_state(entity_id,\"on\")-%}OFF{%-else-%}ON{%-endif%}"
    force_update: true
    device_class: power
    
  - platform: mqtt
    name: "rem 1-k4"
    state_topic: "home/RF433/rem_old_key4"
    value_template: "{%if is_state(entity_id,\"on\")-%}OFF{%-else-%}ON{%-endif%}"
    force_update: true
    device_class: power

Good luck fixing it because thereā€™s little available to make the job easy. At a minimum, you will need to use Strategy #2 (a heavily modified version of Strategy #2).

You will have to store the received payload (such as in an input_text). If the next one is a duplicate of the previous one then you ignore it. Because you have three bridges, all potentially reporting activity from the same remote-control, you may also need to track the topic (in order to identify the bridge).

If you have set your automationā€™s mode to parallel then you may want to consider changing that (for example, to queued). Imagine two instances of the same automation (executing in parallel) trying to store the same payload to the same input_text at the same time (nothing good can come of it).

Let us know if you have any success with this.

Iā€™ve been trying a somewhat different approach, when the demux event is trigged I fire the python script and set an input_text with the code.
The condition to fire the demux automation should be that the code about to be handled is not the code in the input_text.

Itā€™s still work in progress, but maybe you can help me with it too, as we are working on the same issue.

- id: '1590752641349'
  alias: RF Bridge Demultiplexer
  description: ''
  trigger:
  - platform: mqtt
    topic: RFBridge/tele/RESULT
  - platform: mqtt
    topic: RFBridge2/tele/RESULT
  condition:
  - condition: not
    conditions:
    - condition: state
      entity_id: input_text.lastcode
      state: 6D7A3D
  action:
  - service: input_text.set_value
    data:
      entity_id: input_text.lastcode
      value: '{{trigger.payload_json.RfReceived.Data}}'
  - data_template:
      payload: code{{trigger.payload_json.RfReceived.Data}}
    service: python_script.rfcodes
  mode: parallel
  max: 10

somehow I got an issue with testing trigger.payload_json.RfReceived.Data vs the state of lastcode so for now I have put in (hardcoded) the code my device is emitting.

And I made a new automation that changes the input_text (lastcode) to 000000 after 1 second.

- id: '1606319294282'
  alias: Reset LastCode
  description: ''
  trigger:
  - platform: state
    entity_id: input_text.lastcode
    from: '000000'
    for: 00:00:01
  condition: []
  action:
  - service: input_text.set_value
    data:
      entity_id: input_text.lastcode
      value: '000000'
  mode: single

This way all events fired within 1 second of the first will be ignored.

See my previous post. It describes precisely what you are attempting to do (store payload in input_text) and also cautions against using mode: parallel (which your automation is using).

The automationā€™s condition needs to compare the received payload to the input_textā€™s value and execute the action only if the two values are different. While the payload is being stored in the input_text, you donā€™t want a parallel instance doing the same thing.

Iā€™ve been thinking about this, and I think itā€™s not the problem that it incorrectly detects it as a scientific notation (and yes it does), but that is incorrectly doesnā€™t detect that itā€™s a hexadecimal value. Thatā€™s why it also detects incorrectly that a hexadecimal value without letters is a decimal value.

I think my solotion of forcing a string is more consistent (for now), that way you can handle the value for what it is and not a string if itā€™s hex with letters, and a number when itā€™s hex without.

Yes, you are right, I didnā€™t read your post before I put mine in though, with my ā€œIā€™ve been trying a somewhat different approachā€ I didnā€™t mean to your suggestion but opposed to my previous approach.

Sorry, I should have read your post before posting something myself.

Because 8E52 is exactly scientific notation and only maybe hexadecimal.

You know itā€™s hexadecimal because you know the source of the data produces hex numbers. The code processing it doesnā€™t know that and so it uses the ā€˜best fitā€™ for the stringā€™s format (scientific notation).

Arguably, there should be some way to indicate to Home Assistant the valueā€™s preferred type as opposed to it inferring the type based on its appearance. Anyway, for now, the technique you are using, prepending a non-numeric string to prevent the result from being interpreted as numeric, is the best recourse.

Yes, Iā€™ve had some issues, but queued seems to fix that, thanks.
I also had the same translation issue again when detecting against the code, thatā€™s why it was not working when I tested against the received code and I had to hardcode it to get a correct value.

Iā€™m still testing, but as far as I see now I only get 1 MQTT transmission every time, this is my setup:

- id: '1606319294282'
  alias: Reset LastCode
  description: ''
  trigger:
  - platform: state
    entity_id: input_text.lastcode
    from: code000000
    for: 00:00:01
  condition: []
  action:
  - service: input_text.set_value
    data:
      entity_id: input_text.lastcode
      value: code000000
  mode: single
- id: '1590752641349'
  alias: RF Bridge Demultiplexer
  description: ''
  trigger:
  - platform: mqtt
    topic: RFBridge/tele/RESULT
  - platform: mqtt
    topic: RFBridge2/tele/RESULT
  condition:
  - condition: not
    conditions:
    - condition: state
      entity_id: input_text.lastcode
      state: code{{trigger.payload_json.RfReceived.Data}}
  action:
  - service: input_text.set_value
    data:
      entity_id: input_text.lastcode
      value: code{{trigger.payload_json.RfReceived.Data}}
  - data_template:
      payload: code{{trigger.payload_json.RfReceived.Data}}
    service: python_script.rfcodes
  mode: queued
  max: 10
1 Like

You probably only need to prepend a single character to prevent the string from being converted to an integer. It would simply need to be a non-hex character, any letter above F or perhaps a non-alphabetic character like # or punctuation like !.

Yes, I thought about that too, but I donā€™t know what that will do in other interpretations, in HTML # means HEX, and in Delphi/Pascal $ means HEX and ! often means NOT.
Iā€™m not at all sure about python or yaml interpretations so I think ā€œcodeā€ is not a reserved word/character and it describes the value pretty well. :slight_smile:

Strange thing now, it was working perfectly before, and just after I posted my code it started giving double MQTT messages again :frowning:

@123 I think it takes too long to set the value, Iā€™ve split up the automation into 2: 1 checking code 2 and 2 checking code 1, it works sometimes (I only see a code 1 one of the viarables) but sometimes I see the code in both the variables.
The triggers on the bridges are almost simultatious so it could happen that automation 1 is setting the code in the variable just after automation 2 is reading it to check.
I donā€™t know much about python in combination with home assistant, but would it be possible to check the input_text in the python code just before sending the MQTT message?

In my opinion we must try to do everything in the same automation, but the problem would remain if the parallel is used

I think Iā€™m going to make it easy on myself as I only have 1 sensor with this issue.
Iā€™ll make 2 automations with 2 python scripts and I add the code for that sensor only in the python script of the RFbridge closest tot the sensor.

just implemented this, seems like the easiest and most straight forward way to at least solve this unnecessary issue for now

I hope you donā€™t mind but I will be asking the moderators to move your post to its own thread. This topic is for the discussion of what was presented in the first post and not every possible variation of how to receive data from a Sonoff RF Bridge. Thank you for your understanding.

BTW, what you presented looks good and merits its own topic as opposed to being the 336th post of this very long thread. :slight_smile:

2 Likes

I withdrew the post and moved it myself. Thanks for the inspiration.

2 Likes

Hi,
I too am ā€œplaguedā€ by this. I have 2 Sonoff Bridges with same topic (as I have more than 30 sensors and using just one - did not seem to work ok - as it did not pick up all sensors), and used your method in order not to convert to str . And however, I still receive in logs the following:

Logger: homeassistant.components.python_script.rfbridge_demux.py
Source: rfbridge_demux.py:41
Integration: Python Scripts (documentation, issues)
First occurred: 10:25:49 AM (9 occurrences)
Last logged: 10:26:23 AM

<rfbridge_demux> Received unknown RF command: codeAD6B06

where the py script is:

d = { 
      'codeAD6B06':['livingroom_presence','ON','false'],
    }

p = data.get('payload')
#p = str(data.get('payload'))

if p is not None:
  if p in d.keys():
    service_data = {'topic':'home/{}'.format(d[p][0]), 'payload':'{}'.format(d[p][1]), 'qos':0, 'retain':'{}'.format(d[p][2])}
  else:
    service_data = {'topic':'home/unknown', 'payload':'{}'.format(p), 'qos':0, 'retain':'false'}
    logger.warning('<rfbridge_demux> Received unknown RF command: {}'.format(p))
  hass.services.call('mqtt', 'publish', service_data, False)

and the automation is:

alias: rfbridge_demultiplexer
description: ''
trigger:
  - platform: mqtt
    topic: tele/sonoff/RESULT
condition: []
action:
  - service: python_script.rfbridge_demux
    data_template:
      payload: 'code{{trigger.payload_json.RfReceived.Data}}'
mode: single

And I also keep receiving in logs the following:

Logger: homeassistant.components.automation.rfbridge_demultiplexer
Source: helpers/script.py:1138
Integration: Automation (documentation, issues)
First occurred: 10:36:48 AM (4 occurrences)
Last logged: 10:37:04 AM

rfbridge_demultiplexer: Already running

Any ideas?

you have your automation on mode: single that means only 1 instance of the automation can fire at the time, and your 2 bridges will fire almost simultatious, that will give the ā€œalready Runningā€ error.
Maybe not a problem for you, you could change it to queued then it will wait for the first one to finish and then goes on with the 2nd.

In your example you fill the database ā€œdā€ with the code, but you end that with a ā€œ,ā€ now a 2nd line is expected but not there, I think you removed the other codes for this post and forgot to remove the ā€œ,ā€ if not, that may be your problem.

Iā€™ve stepped off from using 1 demuxer, I made 2 demuxers, and 2 topics for the bridges both handle all the codes except the one I only want once (toggle switch) that I just handle with the closest bridge.
They do both translate to the same MQTT topic in the end, in your case ā€˜home/livingroom_presenceā€™

Hope this helps you in any way.

1 Like

Iā€™m confused, is method 1 or 2 still preferred?

I am just configuring the device in the configuration.yaml, like this (working perfectly for 5 Govee leak sensors):

binary_sensor:
  - platform: mqtt
    name: "Water Heater Leak Detector"
    unique_id: "binary_sensor.water_heater_leak_detector"
    payload_on: "A123FB"
    payload_off: "A123FA"
    device_class: moisture
    state_topic: "tele/tasmota_XXXXXX/RESULT"
    value_template: "{{ value_json.RfReceived.Data }}"
    availability_topic: "tele/tasmota_XXXXXX/LWT"
    payload_available: "Online"
    payload_not_available: "Offline"

This seems extremely easy, scalable, and requires zero scripting.
Big thanks to @kosherPowerhaus for the tip.