Sonoff RF Bridge. Strategies for receiving data

Thank you so much, this is exactly what I was looking for!

Off topic, sorry.

Your question is about how to interpret battery levels and is not what this topic is all about. Please create a separate topic. Thank you.

Hi Taras.

I can hardly believe that I’ve been using this since May 19, without issue. Such an excellent contribution to HA.

Are we any nearer to understanding the issue with 0.117? I’m itching to upgrade but the demux is too valuable to me to risk it breaking.

I’m on 0.117.6, and the demux still works flawless ?

Glad to hear it. :+1:

I have no idea why some users are experiencing unusual behavior with python 3.9. Given that Home Assistant is not yet using version 3.9, I have not invested much time in investigating the issue.

What I have done is explore how to incorporate the recent automation enhancements to eliminate the need for a python_script. In other words, the goal is to create a single “rfbridge_demultiplexer” automation that operates without the use of the python_script integration.

Based on a few tests, I believe this achieves the goal:

- alias: 'rfbridge_demultiplexer'
  mode: parallel
  variables:
    data: { '2C8D0A':['sensor1','ON','true'],
            '2C8D0E':['sensor1','OFF','true'],
            'E5D30E':['sensor2','ON','false'],
            '30D8A0':['sensor3','ON','false'] }
  trigger:
  - platform: mqtt
    topic: tele/RF_Bridge/RESULT
  condition: '{{ trigger.payload_json is defined }}'
  action:
  - choose:
    - conditions: '{{ trigger.payload_json.RfReceived.Data in data.keys() }}'
      sequence:
      - service: mqtt.publish
        data:
          topic: 'home/{{ data[trigger.payload_json.RfReceived.Data][0] }}'
          payload: '{{ data[trigger.payload_json.RfReceived.Data][1] }}'
          qos: 0
          retain: '{{ data[trigger.payload_json.RfReceived.Data][2] }}'
    default:
    - service: mqtt.publish
      data:
        topic: 'home/unknown'
        payload: '{{ trigger.payload_json.RfReceived.Data }}'
        qos: 0
        retain: false
    - service: persistent_notification.create
      data:
        title: '<rfbridge_demux> Unknown RF code: {{ trigger.payload_json.RfReceived.Data }}'
        message: '{{ now().timestamp()|timestamp_local() }}'

It was successfully tested with 0.117.5 with the default setting (true) for the legacy_templates option.

If at least two other people confirm it works for them, I will amend this thread’s first post and recommend using this automation (and deprecate the references to use a python_script).


EDIT 1

Added a Template Condition to reject received payloads that are not in JSON format.

EDIT 2

Inspired by Sag’s post below, added mode: queued

EDIT 3

Changed to mode: parallel based on Sag’s post below.

3 Likes

Hi Taras,

Thanks indeed for your work. We really appreciate it.
Some of us use Espurna firmware on our RF Bridges. It works flawlessly. In spite Espurna can publish JSON messages, integration with Home Assistant is done using “MQTT platform”, not “MQTT-JSON platform”. Each message is sent to it’s own topic.
Your python script is working great with Espurna using a light “rfbridge_demultiplexer” automation adaptation. Ie:

- id: '1586546570081'
  alias: RF Topic MQTT desmultiplexaciĂłn
  description: Distribuye MQTT recibidos de Espurna RF Bridge en varios topics
  trigger:
  - platform: mqtt
    topic: home/Sonoff-RF-Bridge-1/rfin
  - platform: mqtt
    topic: home/Sonoff-RF-Bridge-2/rfin
  condition: []
  action:
  - data_template:
      payload: '{{ trigger.payload[-6:] }}'
    service: python_script.rfbridge_demux
  mode: queued
  max: 10

What do you think would be our best adaptation to your new script?

I believe you should change the condition so that it ensures the length of the payload is greater than a minimum amount (otherwise the slice [-6:] may fail).

Other than that, I think wherever you see trigger.payload_json.RfReceived.Data used in the automation, it should be replaced by trigger.payload[-6:].

BTW, your usage of mode: queued is a good precaution so I’ve added it to my example (above).

@123

Taras, im now using your automation and confirm it works well for me.

1 Like

Do you mean something like that?

condition: ‘{{ trigger.payload | string | length > 5 }}’

Edit:

IMHO this automation system is less responsive than python script. I tried quite a lot and when some sensors are activated in a short space of time, only first or two first really do. I changed queued mode to parallel and achieved better results.

If someone use Espurna software on RF bridge (not JSON), maybe my working automation could be useful:

- id: '1586546570081'
  alias: RF Topic MQTT desmultiplexaciĂłn
  description: Distribuye MQTT recibidos de Espurna RF Bridge en varios topics
  trigger:
  - platform: mqtt
    topic: home/Sonoff-RF-Bridge-1/rfin
  - platform: mqtt
    topic: home/Sonoff-RF-Bridge-2/rfin
  condition:
  - condition: template
    value_template: '{{ trigger.payload | string | length > 5 }}'
  action:
  - choose:
    - conditions:
      - condition: template
        value_template: '{{ trigger.payload[-6:] in data.keys() }}'
      sequence:
      - service: mqtt.publish
        data:
          topic: home/{{ data[trigger.payload[-6:]][0] }}
          payload: '{{ data[trigger.payload[-6:]][1] }}'
          qos: 0
          retain: '{{ data[trigger.payload[-6:]][2] }}'
    default:
    - service: mqtt.publish
      data:
        topic: home/unknown
        payload: '{{ trigger.payload }}'
        qos: 0
        retain: false
    - service: persistent_notification.create
      data:
        title: '<rfbridge_demux> Unknown RF code: {{ trigger.payload }}'
        message: '{{ now().timestamp()|timestamp_local() }}'
  variables:
    data:
      234567:
      - Puerta_entrada
      - 'ON'
      - 'true'
      123456:
      - Puerta_entrada
      - 'OFF'
      - 'true'
      987654:
      - Batt_Puerta_entrada
      - 'ON'
      - 'true'
      456789:
      - PIR_hacia_entrada
      - 'ON'
      - 'false'
      285683:
      - PIR_hacia_cocina
      - 'ON'
      - 'false'
      194628:
      - PIR_pasillo
      - 'ON'
      - 'false'
      394555:
      - Detector_humo_cocina
      - 'ON'
      - 'false'
      297634:
      - Detector_humo_salon
      - 'ON'
      - 'false'
      671299:
      - Detector_humo_despacho
      - 'ON'
      - 'false'
      999988:
      - Detector_humo_dormitorio
      - 'ON'
      - 'false'
  mode: parallel
  max: 10

If just one more person confirms the new demultiplexer automation works, I’ll proceed to update the first post.

It works rather nice but as already mentioned there is a lag compared to python_script despite running automation in parallel mode. Mostly feelable with e.g. doorbells. Anyway it is OK but for now I continue using script.
Best, JR

1 Like

Given that two out of three users report noticing a “lag”, I think I’ll leave the first post as-is (i.e. use the python_script). If someone encounters a problem using the python_script, they have an alternative available (i.e. use the new ’ all-in-one’ automation).

I have to admit I’m surprised to hear the automation is slower than the python_script. I would have never imagined the performance difference would be so great that it would be detectable through observation and not even requiring any timing tests. Not sure why the automation is so much slower than the python_script. :thinking:

About your new demultiplexer automation (thanks a lot!), I only had to change the initial condition because the original was not working; I changed to:

{{ data[trigger.payload_json.RfReceived.Data] != null }}

With this modification, it’s working pretty well, with no performance issues.

Best

1 Like

This will fail to reject payloads that are not in JSON format:

{{ data[trigger.payload_json.RfReceived.Data] != null }}

If the received payload is an empty string or just any string that’s not in JSON format, Home Assistant will report it as an error because the condition attempts to access keys (.RfReceived.Data) that don’t exist.

Lag is not so big here. It’s working nice in parallel mode, as I told.
I’ll continue with “all in one” for now. I like it and I need more time to evaluate.
Good job mate!

1 Like

I’m now only using the all in one automation in the parallel mode and works very well for me with no noticeable lag.

Thank you

1 Like

I’m now successfully using the demux on 0.118 without any changes.

Hi to all,

thanks a lot for the automation, now i’m using the Taras automation instead the python script.
all works fine, but when i receive a code tha is not present in the variables i receive an error:

2020-11-20 15:43:23 INFO (MainThread) [homeassistant.components.automation.alrm_rf_demux] [ALRM] RF demux: Choose at step 1: default: Running automation actions
2020-11-20 15:43:23 INFO (MainThread) [homeassistant.components.automation.alrm_rf_demux] [ALRM] RF demux: Choose at step 1: default: Executing step call service
2020-11-20 15:41:29 ERROR (MainThread) [homeassistant.components.automation.alrm_rf_demux] [ALRM] RF demux: Choose at step 1: default: Error executing script. Unexpected error for call_service at pos 1: Error rendering data template: UndefinedError: 'dict object' has no attribute 'RfReceived'
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 351, in async_render
    render_result = compiled.render(kwargs)
  File "/usr/local/lib/python3.8/site-packages/jinja2/environment.py", line 1090, in render
    self.environment.handle_exception()
  File "/usr/local/lib/python3.8/site-packages/jinja2/environment.py", line 832, in handle_exception
    reraise(*rewrite_traceback_stack(source=source))
  File "/usr/local/lib/python3.8/site-packages/jinja2/_compat.py", line 28, in reraise
    raise value.with_traceback(tb)
  File "<template>", line 1, in top-level template code
  File "/usr/local/lib/python3.8/site-packages/jinja2/sandbox.py", line 407, in getattr
    value = getattr(obj, attribute)
jinja2.exceptions.UndefinedError: 'dict object' has no attribute 'RfReceived'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 144, in async_prepare_call_from_config
    service_data.update(template.render_complex(config[conf], variables))
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 91, in render_complex
    return {
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 92, in <dictcomp>
    render_complex(key, variables): render_complex(item, variables)
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 96, in render_complex
    return value.async_render(variables)
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 353, in async_render
    raise TemplateError(err) from err
homeassistant.exceptions.TemplateError: UndefinedError: 'dict object' has no attribute 'RfReceived'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 253, in _async_step
    await getattr(
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 432, in _async_call_service_step
    domain, service, service_data = async_prepare_call_from_config(
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 146, in async_prepare_call_from_config
    raise HomeAssistantError(f"Error rendering data template: {ex}") from ex
homeassistant.exceptions.HomeAssistantError: Error rendering data template: UndefinedError: 'dict object' has no attribute 'RfReceived'

this my automation:

  - alias: '[ALRM] RF demux nitghtoff'
    mode: parallel
    variables:
      data: { '0xB24E54':['RC1_NIGHT','OFF','true'], # remote RC su Tasmota
              '0x434454':['RC2_NIGHT','OFF','true'], # remote RC su Tasmota
# remote RC su OMG
              '11685460':['RC1_NIGHT','OFF','true'],
              '4408404':['RC2_NIGHT','OFF','true']
      }
    trigger:
    - platform: mqtt
      topic: tele/RF2/RESULT
    - platform: mqtt
      topic: tele/RF1/RESULT
    - platform: mqtt
      topic: home/OpenMQTTGateway_ESP8266_RF/433toMQTT
    condition: '{{ trigger.payload_json is defined }}'
    action:
    - choose:
      - conditions: '{{ trigger.payload_json.RfReceived.Data in data.keys() }}'
        sequence:
        - service: mqtt.publish
          data:
            topic: 'home/RF433/{{ data[trigger.payload_json.RfReceived.Data][0] }}'
            payload: '{{ data[trigger.payload_json.RfReceived.Data][1] }}'
            qos: 0
            retain: '{{ data[trigger.payload_json.RfReceived.Data][2] }}'
      default:
      - service: mqtt.publish
        data:
          topic: 'home/unknown'
          payload: '{{ trigger.payload_json.RfReceived.Data }}'
          qos: 0
          retain: false

BR

Actually, it’s a bit more severe than a non-existent code. The received payload fails to contain ‘RfReceived’. That’s what this error message is reporting:

UndefinedError: ‘dict object’ has no attribute ‘RfReceived’

I suggest you enhance the condition so it ensures the payload contains the ‘RfReceived’ key.

  condition: >
    {{ trigger.payload_json is defined and
       trigger.payload_json.RfReceived is defined }}

EDIT

Correction. Replaced RFReceived with RfReceived.