Translating a sensor with base64 value to 20 separate decimal sensors

Can someone help me with translating a sensor?

I’ve got a sensor via LocalTuya that gives a base64 value;
the sensor name is: sensor.101
Every some seconds it changes its value, looking like this: AAAAEAAAABIAAAARAAAAFQAAABcAAAAOAAAAEAAAADEAAAFeAAAAAAAAAAAAAAAoAAACNgAAAAAAAAAAAAAAAAAAAAYAAAAOAAAAAAAAAAA=

I don’t have any experience with coding, but on a website i found a way to translate the code, corresponding with parameters that i see in the native tuya app:

This translates the results into 20 numbers, which correspond to parameters from the tuya device (heatpump)

Does anyone know a way to let Home Assistant translate the sensor.101 data into 20 separate sensors with the readings of the 20 parameters as seen in the image above?

Kind regards N

Here’s how to convert that into the list:

{% set s = "AAAAEAAAABIAAAARAAAAFQAAABcAAAAOAAAAEAAAADEAAAFeAAAAAAAAAAAAAAAoAAACNgAAAAAAAAAAAAAAAAAAAAYAAAAOAAAAAAAAAAA=" %}
{% set ns = namespace(s="") -%}
{% for c in s|map('ord')|reject('==',61) -%}
{% set ns.s = ns.s+"{:0=6b}".format(c+{1:-71,c<91:-65,c<58:4,c<48:16,c<44:19}[true]) -%}
{% endfor -%}
{{ ns.s|batch(32)|map('join')|map('int',base=2)|list }}

Note: this creates a 21st, unneeded item that you could trim off if you wanted.

I’d implement this by creating a template sensor with the list as an attribute, which you’ll need to do in YAML. Then, if you need to, you can read each item from the attribute into a separate template sensor without needing to re-do the calculation 20 times:

template:
  - sensor:
      - name: Tuya 101 list
        state: "{{ states['sensor.101']['last_updated'] }}"
        attributes:
          value_list: >
            {% set ns = namespace(s="") -%}
            {% for c in states('sensor.101')|map('ord')|reject('==',61) -%}
            {% set ns.s = ns.s+"{:0=6b}".format(c+{1:-71,c<91:-65,c<58:4,c<48:16,c<44:19}[true]) -%}
            {% endfor -%}
            {{ ns.s|batch(32)|map('join')|map('int',base=2)|list }}

You can create template sensor helpers in the UI with state templates of:

{{ state_attr('sensor.tuya_101_list','value_list')[x] }}

where x is a number from 0 (first) to 19 (last).

If that template looks like Perl or runic incantations, there’s an explanation here.

We definitely need an base32encode function IMO, but FYI there is a base64decode func, this also doesn’t produce the additional 0 that your template has.

{% set s = 'AAAAEAAAABIAAAARAAAAFQAAABcAAAAOAAAAEAAAADEAAAFeAAAAAAAAAAAAAAAoAAACNgAAAAAAAAAAAAAAAAAAAAYAAAAOAAAAAAAAAAA=' %}
{% set ns = namespace(s='') %}
{% for c in s | base64_decode(None) %}
  {% set ns.s = ns.s + '{0:08b}'.format(c) %}
{% endfor %}
{{ ns.s|batch(32)|map('join')|map('int',base=2)|list }} 

EDIT: Suppose you could do it like this too

{% set s = 'AAAAEAAAABIAAAARAAAAFQAAABcAAAAOAAAAEAAAADEAAAFeAAAAAAAAAAAAAAAoAAACNgAAAAAAAAAAAAAAAAAAAAYAAAAOAAAAAAAAAAA=' %}
{% set ns = namespace(items=[]) %}
{% for v in s | base64_decode(None) | batch(4) %}
  {% set ns.items = ns.items + [('{:08b}'*4).format(*v) | int(base=2)] %}
{% endfor %}
{{ ns.items }} 

I know you like 1 liners too

{% set s = 'AAAAEAAAABIAAAARAAAAFQAAABcAAAAOAAAAEAAAADEAAAFeAAAAAAAAAAAAAAAoAAACNgAAAAAAAAAAAAAAAAAAAAYAAAAOAAAAAAAAAAA=' %}
{{ ('{:08b}' * 80).format(*(s | base64_decode(None) | list)) |batch(32)|map('join')|map('int',base=2)|list }}
1 Like

Sweet.

I couldn’t get base64_decode to work in the linked thread, so wrote my own — but a working one-liner always gets my vote.

I was trying to figure out htf you came up with that. I’m so used to using the built-ins for python.

1 Like