Sonoff RF Bridge. Strategies for receiving data

:blush: :innocent: ups, I have since 2 days my automations splitted in mulitples files, so I forgott to delete the hyphen “- alias”… in the separated file…

Automation works now fine :smiley:
and the payload 623476 is with automation not unknown !!
but with pythron script still same issue…

I’ve tested some other devices with a payload only with numbers.
Also these are “unkown”, so it seems, that payload’s only with numbers can’t be anymore proceed corretly by the python script.

Syntax change:

old
‘2C8D0A’:[‘sensor1’,‘ON’,‘true’]

new

2C8D0A:[‘sensor1’,‘ON’,‘true’]

As you the know, the only difference between the two is the first is a string and the second is a hexadecimal number. It shouldn’t make a difference which one is used (to serve as the key for a dict) unless version 0.118 automatically converts the received string to a number.

That’s what might be happening given that another user reported that "67E946" (a string) was interpreted to be a number in scientific notation (67 exponent 946).

Yes, indeed, if I change syntax in the python-script for number-only payloads, they are no longer unknown.

d = { '0CD102':['sonoff_button_home_a','ON','false'],
      '0CD108':['sonoff_button_home_b','ON','false'],
      '0CD101':['sonoff_button_home_c','ON','false'],
      '0CD104':['sonoff_button_home_d','ON','false'],
      'EDB0C1':['sonoff_button_key_M_arm_away','ON','false'],
      'EDB0C2':['sonoff_button_key_M_disarm','ON','false'],
      'EDB0C4':['sonoff_button_key_M_arm_home','ON','false'],
      'EDB0C8':['sonoff_button_key_M_sos','ON','false'],
      'FBFF1E':['sonoff_pir_keller_tuere','ON','true'],
      'FC302E':['sonoff_pir_keller_fenster','ON','true'],
      'D2792E':['sonoff_pir_eingang_aussen','ON','true'],     
      '14CA83':['sonoff_housedoor_lockstatus','ON','true'],
      '14CA89':['sonoff_housedoor_lockstatus','OFF','true'],
      'CA7169':['sonoff_water_waschmaschine','ON','true'],
      623476:['sonoff_fire_waschkueche','ON','true'],
      620602:['somfy_cover_alle_storen_up','ON','false'],
      620604:['somfy_cover_alle_storen_stop','ON','false'],
      620608:['somfy_cover_alle_storen_down','ON','false'],
      620612:['somfy_cover_sitzplatz_up','ON','false'],
      620614:['somfy_cover_sitzplatz_stop','ON','false'],
      620618:['somfy_cover_sitzplatz_down','ON','false'],

but syntax change only for numeric paiyloads, payloads with letters must kept in ’ ', otherwise these payload are not recognized.

This seems to be some sort of new behavior in 0.118 where it automatically converts a string to an integer if the string is numeric. At least that’s my best guess as to what’s going on.

Sorry I can’t be of more help. This new ‘auto-conversion’ behavior in 0.118 is all new to me as well.

1 Like

In python script, use number-to-string conversion

payload = str(data.get(‘payload’))

1 Like

You’re missing the point. Yes, the python_script can cast everything it receives to string. However, ask yourself why that step was not needed in previous versions?

The answer is because 0.118 has implemented automatic type conversions. If a string looks like an integer, it gets converted to an integer (whether you want it or not).

Where is this happening? It’s happening in templates, right here in the rfbridge demultiplexer automation, when it passes the received payload to the python_script:

  - service: python_script.rfbridge_demux
    data_template:
      payload: '{{trigger.payload_json.RfReceived.Data}}'

If trigger.payload_json.RfReceived.Data contains a numeric string, it gets automatically converted to an integer. This is new behavior in 0.118. In my opinion, if it’s a string it should be left as a string and its type should not be automatically converted to integer just because of its contents (‘type inference’).

Unfortunately, we have no control over the automatic type conversion in templates. For example, let’s say I wanted to ensure the value is always handled as a string so I employ the string filter:

      payload: '{{trigger.payload_json.RfReceived.Data | string}}'

However, in 0.118, it ignores the string filter and continues to convert a numeric string to integer.

I know you’re upset about this change but we truly benefit from the enhancement. Hopefully soon you’ll be able to template keys…

service: notify.notify
data: >
  {% set on_dict = {'message': 'foo'} %}
  {% set off_dict = {'message': 'bar', 'title': 'Bar'} %}
  {% if is_state('xxx.xxx','on') %}
    {{ on_dict }}
  {% else %}
    {{ off_dict }}
  {% endif %}

Imagine the possibilities. Please take your blinders off and look to the future and fix the issues with your script and this change.

In the same spirit as your reply, please open your eyes to the possibility of allowing users to decide when a type should be converted and when it should not. Currently, a user has no control over type conversion.

As for the suggestion to “fix the issues with your script”, it can be done in python_script because we still have the ability to control type. However, the new ‘all-in-one’ automation I recently posted cannot be “fixed” because 0.118 gives me no control over type in templates.

The only way to accomodate the new reality is to change the keys in the dict to match the auto-converted type.

Imagine the possibilities if you could control the type in an automation’s template. You could tell it to always treat trigger.payload_json.RfReceived.Data as a string and then you wouldn’t have to modify keys in the dictionary.

:man_shrugging: You’re arguing to the wrong person. I’m simply telling you that the best option is to adapt and overcome. I’m not going to part take in an discussion to add some field for typing, or give the user the ability to strongly type it.

I personally welcome the change and no amount of discussion will change my personal opinion. I also think that all template changes and enhancements should occur in the single template without additional fields. You won’t change my opinion on that matter either.

I agree.

This should be handled as a string:

{{ 123456 | string }}

and this as a float:

{{ '123.456' | float }}

and this as a string (not a list as it currently does):

{{ [ "a", "b", "c" ] | string }}

If that were possible then it would be trivial to fix the all-in-one automation.

the template is not looked at. I don’t know how else to tell you this. As soon as you look at the template things get extremely complicated and wonky. Yeah that might work for a single line template but it won’t for a multiline template. Think of the code like this:

value = template.resolve('{% if .... %}{{ more template crap }}{% endif %}')
try:
  value = int(value)
... etc.

The template is 100% ignored. Only the value is acted on.

That’s clear to me. I understand the template’s result is used to infer type (the template is a ‘black box’). I was simply demonstrating one possible way of declaring type without using a new ‘type’ automation option. However, yes, it would require not treating the template as a ‘black box’. I suspect this presents a level of technical challenge on the order of the new template inspection mechanism recently introduced by Bdraco.

Honestly, a type option isn’t a bad idea. Certainly easier than attempting to inspect the template for certain filters. Not ideal but an improvement over the current situation of having no control over the choice of type.

Based on everything I’ve learned so far concerning 0.118’s new “support for native type”, here’s what I suggest users do.

The RF code strings sent by the Sonoff RF Bridge are received by the demultiplexer automation and forwarded to the python_script via trigger.payload_json.RfReceived.Data.

If the RF code string looks like an integer, such as 606367, it will be automatically converted to an integer. This conversion did not occur in previous versions of Home Assistant but now it does. We must adapt to this new behavior.

One easy way has already been provided by Miroslav_Tlusty. If you are using the original version of Strategy #2 (a combination of an automation and a python_script) you simply need to modify the python_script so that it converts everything it receives into a string.

In rfbridge_demux.py, change this:

p = data.get('payload')

to this:

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

Save the file, execute Reload Python Scripts, and the change will take effect. Now if the received RF code is converted to an integer, the python_script will convert it to a string and ensure it is properly matched with the keys you already have defined in the dictionary.

If you are using the new ‘all-in-one’ automation that I recently posted (it uses a single automation and doesn’t require a python_script) you must do something different. There’s nothing you can change in the automation to ‘force’ RF codes to always be strings. You must change the keys you defined in the dictionary.

This is exactly what wema has done in this post (except in the python_script whereas we are focused on the ‘all-in-one’ automation). If you have any RF codes that are purely numeric, remove their quotes in order to change their type from string to integer. For example, change this:

  variables:
    data: { '2C8D0A':['sensor1','ON','true'],
            '2C8D0E':['sensor1','OFF','true'],
            '626897':['sensor2','ON','false'],
            '626879':['sensor3','ON','false'] }

to this:

  variables:
    data: { '2C8D0A':['sensor1','ON','true'],
            '2C8D0E':['sensor1','OFF','true'],
            626897:['sensor2','ON','false'],
            626879:['sensor3','ON','false'] }

Save the automation, run Check Configuration, if it passes execute Reload Automations to make the change take effect.

3 Likes

Thank you for taking the time to do this. I appreciate it.

1 Like

Hi,

Thanks for making this, I’ve been using it for some time now, but I found that is stopped working as of 0.118 release, I see your fix for this, and it works for a few of my sensors, but I have some sensors giving me a code starting wit 8Exxx I have 1 sensor starting with 8ExxC that works normally without any changes. but the 8Exxx is converted to a numer 0.00000xxx and I get as code transmitted “inf”

I’ve even tried to change the code to the number (like you did in above example), i.e. 8E7218 to 0.00007218, this also results in "inf’

is there a way to force the payload to send as string?

EDIT
solved it:

Just add a word in front of your code and test for that in the pyton script, no conversion needed.

Like in the automation:

data_template:
  payload: 'code{{trigger.payload_json.RfReceived.Data}}'

then in the python test for the code ‘code’ like this:

d = { 'code24CF0A':['sensor1','ON','true'],
      'code24CF0E':['sensor1','OFF','true']
}

no str() conversion needed.

Hi,

I’m using the automation made by Taras
Tasmota send the code 4 times because my PIR sensor send the code 4 times sequentially.
Is it possible to elaborate only the first code and ignore the the others (duplicated) in time of range of 0,5 seconds?

thanks a lot

I now have the same issue (sort of) I have 2 RF bridges and I have a water sensor that sends a code when it detects water, but also when the water is gone it sends the same code. So a toggle… easy, but both the RF bridges pick up the sensor so the script is ran twice… making the binary sensor toggle on and off instantly.

Can’t fix that with an off-delay or something. We would need a viariable that stores the last code and time and test that against the current code and time and send MQTT if it was more than X-amount of time ago…

Although this is a creative way to avoid having the string converted to an integer (a very large integer), it skirts the underlying problem in 0.118 that it incorrectly interprets the string as being in scientific notation.

It is a known problem and a PR was submitted to correct it but I don’t think it was ever incorporated into a release version:

You may wish to either support the PR or report the problem as an Issue in the GitHub Core repository (because it shouldn’t be necessary to ‘just add a word in front of your code’).

What is the negative effect of receiving the same command more than once?