Create sensors from 16 bit value

I wan’t to create sensors from MQTT float value for every bit reading relaystatus from a node.
In forum I’ve found a number of examples to convert to binary but unable to get it work when testing in developer. Not that I’m lazy but for a newbie there is so much information to process so I have cheated and code below are “autogenerated” just to get something to start with.

#test convert relaystatus to variables
  - platform: template
    sensors:
      binary_value:
        friendly_name: "FDRS Node 31 binary"
        value_template: >
         
            {% set binary = states('sensor.fdrs_node_31_data') | int(0) | format('016b') %}
            {% for i in range(16) %}
              {% set bit = binary[i] %}
              {% set var_name = 'Node31_bit_' ~ i %}
              {% set var_value = '1' if bit == '1' else '0' %}
              {% set _ = states('input_text.' ~ var_name) | int %}
              {% set _ = states('input_text.' ~ var_name, var_value) %}
            {% endfor %}
              

Tried to change things back and fourth but get different errors. Last one:
`Logger: homeassistant.helpers.template
Source: helpers/template.py:2318
First occurred: 08:58:46 (238 occurrences)
Last logged: 09:41:18

Template variable error: No first item, sequence was empty. when rendering ‘{{ (value_json | selectattr(‘id’,‘eq’,31) | list | first).data}}’`

I understand that there is no data to process and tried with different variant’s with if - then - else providing a default value but don’t work.

Can someone give me a hint. Is this approach completely wrong, workaround ?

Best Regards

 {% set binary = "{0:016b}".format(states('input_number.test_mode') | int(0)) %}

The error you received is from the node 31 sensor config, not from the code in this post. See my other post for the solution to that error (the one where you said node 31 sensor was fine :wink: ).

Strongly recommend you develop the template in the Template Editor rather than in sensor configs to start with, to get it working.

Also recommend using modern configuration for template sensors: you’re using legacy format. See the docs.

Your template also doesn’t have an output, but if that’s ChatGPT then no surprise.

If you want a string output of 0s and 1s as a representation of a binary number from 0 to decimal 65535, then @koying’s solution is easiest.

{{ '{0:016b}'.format('65535'|int) }}   # returns 1111111111111111

Good catch :rofl::rofl::rofl:

Thank’s both for answers. When runnung code in Template Editor the only ?! error now is 'this' is undefined

mqtt:
  sensor:

#mcp23017 node 31
    - name: "FDRS Node 31 data"
      state_topic: "fdrs/data"
      value_template: >
        {% set fdrs_list = value_json | selectattr('id', 'eq', 31) | list %}
        {% if fdrs_list %}
          {{ fdrs_list[0]['data'] }}
        {% else %}
          {{ this.state }}
        {% endif %}




#test convert relaystatus to variables
  - platform: template
    sensors:
      binary_value:
        friendly_name: "FDRS Node 31 binary"
        value_template: >
         
            {% set binary = "{0:016b}".format(states('sensor.fdrs_node_31_data') | int(0)) %}
            {% for i in range(16) %}
              {% set bit = binary[i] %}
              {% set var_name = 'Node31_bit_' ~ i %}
              {% set var_value = '1' if bit == '1' else '0' %}
              {% set _ = states('input_text.' ~ var_name) | int %}
              {% set _ = states('input_text.' ~ var_name, var_value) %}
            {% endfor %}
          
      

In Log there are ERROR: Template error: int got invalid input 'unknown' when rendering template '{% set binary.......

Unknown input despice implemented Your code in node 31. What’s missing now ?

I will read documentation for better understanding what’s going on but nice to have a working example to work on.

Yeah, you can’t use this in the Template Editor: it’s only defined within a sensor.

The editor is for trying out templates (the Jinja bit) not the entire YAML configuration.

That error occurs when you don’t specify a default value for int, which will correspond to your first AI-vomited {% set _ = line. It is not related to the state of the node 31 sensor.

My code relies on a valid prior value to avoid it getting overwritten.

So once you’ve fixed the sensor and are getting decent values from it you could try something like this in the editor:

Node 31 sensor state: {{ states('sensor.fdrs_node_31_binary') }}
Binary version: {{ '{0:016b}'.format(states('sensor.fdrs_node_31_binary')|int(0)) }} 

then if that returns reasonable output, put the binary converter template (second line, between and including the {{...}}) as the state: template for your modern-format template sensor.

Sensor data incoming ok now without errors.
I’ve made several attemps to create sensor’s for each bit,

template:
  - binary_sensor:
    {% for i in range(16) %}
    - name: "Node31_bit_{{i}}"
      state: "{{ '{0:016b}'.format(states('sensor.fdrs_node_31_data') | int) [i] == '1' }}"
    {% endfor %}

work ok in Developer but error ‘missing comma’ in config file. I’ve seen in forum that this approach are not allowed so for now I’m using the brutal/nonelegant way without error and values for each bit are changed in Developer but there are no sensor’s created.

template:
sensors:
  - binary_sensor:

    - name: "Node31_relay_{{0}}"
      state: "{{ '{0:016b}'.format(states('sensor.fdrs_node_31_data') | int) [0] == '1' }}"
    - name: "Node31_relay_{{1}}"
      state: "{{ '{0:016b}'.format(states('sensor.fdrs_node_31_data') | int) [1] == '1' }}"
    - name: "Node31_relay_{{2}}"
      state: "{{ '{0:016b}'.format(states('sensor.fdrs_node_31_data') | int) [2] == '1' }}"
    - name: "Node31_relay_{{3}}"
      state: "{{ '{0:016b}'.format(states('sensor.fdrs_node_31_data') | int) [3] == '1' }}"
etc. etc.

If I understand You right, this.state should be replaced by {{ '{0:016b}'.format(states('sensor.fdrs_node_31_binary')|int(0)) }} ?

If I do that sensor value shows incoming data and '00000…´ periodically, with
this.state instead data is shown and change as expected.

Almost there BUT sensor’s for each bit not created. What am I missing ? Wrong approach ?

Best Regards

It’s no that, it is that what you want is “meta” templating, i.e. templates to create entities. That’s just a feature that doesn’t exist.

Why?

    - name: "Node31_relay_0"

So in conclusion there is no way to create sensors that I want ?

Of course there is, Chris was just pointing out that what you have tried is not valid.

You cannot use Jinja templates to create YAML configuration at runtime.

For very repetitive configurations, you could create the YAML in the template editor and copy/paste it into your config, but it has to be valid.

I’d do it like this, where the bit 0 sensor is the most-significant bit: swap the numbers around if that’s not what you want. First sensor is the 16-bit binary string; then you have 16 binary sensors reading off that.

template:
  - sensor:
      - name: FDRS 31 in binary
        state: "{{ '{0:016b}'.format(states('sensor.fdrs_node_31_data')|int(0)) }}"
  - binary_sensor:
      - name: FDRS 31 bit 0
        state: "{{ states('sensor.fdrs_31_in_binary')[0] == '1' }}"
      - name: FDRS 31 bit 1
        state: "{{ states('sensor.fdrs_31_in_binary')[1] == '1' }}"
      - name: FDRS 31 bit 2
        state: "{{ states('sensor.fdrs_31_in_binary')[2] == '1' }}"
      - name: FDRS 31 bit 3
        state: "{{ states('sensor.fdrs_31_in_binary')[3] == '1' }}"
      - name: FDRS 31 bit 4
        state: "{{ states('sensor.fdrs_31_in_binary')[4] == '1' }}"
      - name: FDRS 31 bit 5
        state: "{{ states('sensor.fdrs_31_in_binary')[5] == '1' }}"
      - name: FDRS 31 bit 6
        state: "{{ states('sensor.fdrs_31_in_binary')[6] == '1' }}"
      - name: FDRS 31 bit 7
        state: "{{ states('sensor.fdrs_31_in_binary')[7] == '1' }}"
      - name: FDRS 31 bit 8
        state: "{{ states('sensor.fdrs_31_in_binary')[8] == '1' }}"
      - name: FDRS 31 bit 9
        state: "{{ states('sensor.fdrs_31_in_binary')[9] == '1' }}"
      - name: FDRS 31 bit 10
        state: "{{ states('sensor.fdrs_31_in_binary')[10] == '1' }}"
      - name: FDRS 31 bit 11
        state: "{{ states('sensor.fdrs_31_in_binary')[11] == '1' }}"
      - name: FDRS 31 bit 12
        state: "{{ states('sensor.fdrs_31_in_binary')[12] == '1' }}"
      - name: FDRS 31 bit 13
        state: "{{ states('sensor.fdrs_31_in_binary')[13] == '1' }}"
      - name: FDRS 31 bit 14
        state: "{{ states('sensor.fdrs_31_in_binary')[14] == '1' }}"
      - name: FDRS 31 bit 15
        state: "{{ states('sensor.fdrs_31_in_binary')[15] == '1' }}"

If you are desperate to generate your YAML configuration, I actually had a use case and use gomplate for this.

I didn’t document this, nor did I intend to do so, but in a nutshell:

  • Have a GO template (Using Go Templates | Gopher Academy Blog)
  • Have a JSON describin the entities
  • Run gomplate (when launching HA in my case) to generate YAML files
  • include those YAML through include_dir_merge_list

Examples:

Template

## gomplate template
## install:
##   go install github.com/hairyhenderson/gomplate/v4/cmd/gomplate@latest
## docker:
##   docker run -v .:/config hairyhenderson/gomplate:stable -d 'data=file:///config/gomplate/templates_calendar.json' -f /config/gomplate/templates_calendar.tmpl -o /config/platforms/templates/templates_calendar.yaml
## run: 
##   cat gomplate/templates_calendar.json | gomplate -d 'data=stdin:?type=application/array%2Bjson' -f gomplate/templates_calendar.tmpl -o platforms/templates/templates_calendar.yaml

- sensor:

{{- range  $c := (ds "data") }}

  - name: "{{ $c.name }}"
    unique_id: "{{ $c.uid }}"
    state: >
      {% from 'next_cal.jinja' import next_cal_state %}
      {{ "{{" }} next_cal_state([ {{ $c.calendars }} ]) {{ "}}" }}
    attributes:
      all_day: >
        {% from 'next_cal.jinja' import next_cal_allday %}
        {{ "{{" }} next_cal_allday([ {{ $c.calendars }} ]) {{ "}}" }}
      start_time: >
        {% from 'next_cal.jinja' import next_cal_startdate %}
        {{ "{{" }} next_cal_startdate([ {{ $c.calendars }} ]) {{ "}}" }}
      end_time: >
        {% from 'next_cal.jinja' import next_cal_enddate %}
        {{ "{{" }} next_cal_enddate([ {{ $c.calendars }} ]) {{ "}}" }}

{{- end }}

JSON

[
  {
    "name": "Next calendar event: Chris",
    "uid": "next_calendar_event_chris",
    "calendars": "states.calendar.default_calendar, states.calendar.business, states.calendar.famille"
  },
  {
    "name": "Next calendar event: Chouchou pour Chris",
    "uid": "next_calendar_event_chouchou_for_chris",
    "calendars": "states.calendar.chouchou"
  },
  {
    "name": "Next calendar event: Chouchou",
    "uid": "next_calendar_event_chouchou",
    "calendars": "states.calendar.chouchou, states.calendar.famille"
  },
  {
    "name": "Next calendar event: Birthdays",
    "uid": "next_calendar_birthday",
    "calendars": "states.calendar.contact_birthdays"
  }
]

Command (in docker-compose.yml)

    gomplate_tmpl_calendars:
        image: hairyhenderson/gomplate:stable
        volumes:
            - ${HA_PATH}/config:/config
        command: -d 'data=file:///config/gomplate/templates_calendar.json' -f /config/gomplate/templates_calendar.tmpl -o /config/platforms/templates/gmp_calendars.yaml

Generated

## gomplate template
## install:
##   go install github.com/hairyhenderson/gomplate/v4/cmd/gomplate@latest
## docker:
##   docker run -v .:/config hairyhenderson/gomplate:stable -d 'data=file:///config/gomplate/templates_calendar.json' -f /config/gomplate/templates_calendar.tmpl -o /config/platforms/templates/templates_calendar.yaml
## run: 
##   cat gomplate/templates_calendar.json | gomplate -d 'data=stdin:?type=application/array%2Bjson' -f gomplate/templates_calendar.tmpl -o platforms/templates/templates_calendar.yaml

- sensor:

  - name: "Next calendar event: Chris"
    unique_id: "next_calendar_event_chris"
    state: >
      {% from 'next_cal.jinja' import next_cal_state %}
      {{ next_cal_state([ states.calendar.default_calendar, states.calendar.business, states.calendar.famille ]) }}
    attributes:
      all_day: >
        {% from 'next_cal.jinja' import next_cal_allday %}
        {{ next_cal_allday([ states.calendar.default_calendar, states.calendar.business, states.calendar.famille ]) }}
      start_time: >
        {% from 'next_cal.jinja' import next_cal_startdate %}
        {{ next_cal_startdate([ states.calendar.default_calendar, states.calendar.business, states.calendar.famille ]) }}
      end_time: >
        {% from 'next_cal.jinja' import next_cal_enddate %}
        {{ next_cal_enddate([ states.calendar.default_calendar, states.calendar.business, states.calendar.famille ]) }}

  - name: "Next calendar event: Chouchou pour Chris"
    unique_id: "next_calendar_event_chouchou_for_chris"
    state: >
      {% from 'next_cal.jinja' import next_cal_state %}
      {{ next_cal_state([ states.calendar.chouchou ]) }}
    attributes:
      all_day: >
        {% from 'next_cal.jinja' import next_cal_allday %}
        {{ next_cal_allday([ states.calendar.chouchou ]) }}
      start_time: >
        {% from 'next_cal.jinja' import next_cal_startdate %}
        {{ next_cal_startdate([ states.calendar.chouchou ]) }}
      end_time: >
        {% from 'next_cal.jinja' import next_cal_enddate %}
        {{ next_cal_enddate([ states.calendar.chouchou ]) }}

  - name: "Next calendar event: Chouchou"
    unique_id: "next_calendar_event_chouchou"
    state: >
      {% from 'next_cal.jinja' import next_cal_state %}
      {{ next_cal_state([ states.calendar.chouchou, states.calendar.famille ]) }}
    attributes:
      all_day: >
        {% from 'next_cal.jinja' import next_cal_allday %}
        {{ next_cal_allday([ states.calendar.chouchou, states.calendar.famille ]) }}
      start_time: >
        {% from 'next_cal.jinja' import next_cal_startdate %}
        {{ next_cal_startdate([ states.calendar.chouchou, states.calendar.famille ]) }}
      end_time: >
        {% from 'next_cal.jinja' import next_cal_enddate %}
        {{ next_cal_enddate([ states.calendar.chouchou, states.calendar.famille ]) }}

  - name: "Next calendar event: Birthdays"
    unique_id: "next_calendar_birthday"
    state: >
      {% from 'next_cal.jinja' import next_cal_state %}
      {{ next_cal_state([ states.calendar.contact_birthdays ]) }}
    attributes:
      all_day: >
        {% from 'next_cal.jinja' import next_cal_allday %}
        {{ next_cal_allday([ states.calendar.contact_birthdays ]) }}
      start_time: >
        {% from 'next_cal.jinja' import next_cal_startdate %}
        {{ next_cal_startdate([ states.calendar.contact_birthdays ]) }}
      end_time: >
        {% from 'next_cal.jinja' import next_cal_enddate %}
        {{ next_cal_enddate([ states.calendar.contact_birthdays ]) }}

Thank’s. I’ll give it a trial :+1:
Best Regards
Håkan