How to easily define 10 identical sensors

I have 10 identical BLE temp/RH sensors for which I need to add code to sensors.yaml and configuration.yaml

Is there a way to make one generic sensor definition for all 10 sensors? I’d like to avoid copy/pasting this 10 times.

What I have now is:

sensors.yaml

- platform: template
  sensors:
    in100_batt:
      friendly_name: "IN100 Battery"
      device_class: battery
      unit_of_measurement: "v"
      value_template: >-
        {{states('sensor.bthome_sensor_0001_count') | float / 32}}

configuration.yaml

template:
  - sensor:
      - name: "Battery"
        unit_of_measurement: "%"
        device_class: battery
        availability: "{{ states('sensor.in100_batt')|is_number }}"
        state: >
          {% set batt_volts = states('sensor.in100_batt')|float(0) %}
          {% set batt_pct = 55.55 * batt_volts - 83.31 %} {# calculate percent from the voltage #}
          {% set batt_pct_clamped = ([0, batt_pct, 100]|sort)[1]|int %} {# clamp the output to a 0-100% range #}

The sensor name sensor.bthome_sensor_0001_count is created by BTHome . The second is, ovbiously, named sensor.bthome_sensor_0002_count.
Is there a way to use the 000? numbering as a variable for the sensor definition in the yamls? I guess there is some scripting involved, but since I have zero scripting skills help from the community is highly appreciated :slight_smile:
Or is it just copy/paste this 10 times and edit them accordingly.

yes, use an attribute on the unique feature, call it ‘id’ , use that in the complete template you have, and throw the rest of the config in an & anchor and copy that using the *

example:

      - unique_id: marijn_background_color
        <<: &background_color
          state: >
            {% set id = this.attributes.get('id') %}
            {% set state= states('person.' ~ id) %}
            {% set activity = states('sensor.' ~ id ~ '_activity') %}
            {% set cc =
                 state_attr('sensor.' ~ id ~ '_geocoded_location','ISO Country Code') %}
            {% set zones = states.zone|map(attribute='name')|list %}

            {%- if state == 'home' %} green
            {%- elif 'bij' in state %} gold
            {%- elif cc and cc|lower != 'nl' %} white
            {%- elif state|lower in zones|lower %} mediumslateblue
            {%- elif activity in ['Automotive','Cycling','Walking'] %} orange
            {%- else %} dimgray
            {% endif %}
        attributes:
          id: marijn

      - unique_id: partner_background_color
        <<: *background_color
        attributes:
          id: partner

I use that all over the place, and it really cuts on Yaml, also its way easier to maintain

Could you translate that to something that reflects my use case? Tbh, I have no idea how to use anchors. A link to relevant docs are also welcomed. I find the HA docs usually too technical for beginners like me :wink:

Yaml anchors are a part of yaml, not HA. The docs won’t cover them. Simply google “yaml anchors” and choose your tutorial.

Will do.
@Mariusthvdb Thanks for the example code

here’s a small first go:

template:

  - sensor:
      - unique_id: battery_test_anchor_kelder_aanbouw
        attributes:
          id: kelder_aanbouw
        <<: &batt_sensor
          name: >
            Battery id: {{this.attributes.get('id')}}
          unit_of_measurement: '%'
          device_class: battery
          availability: >
            {{has_value(this)}}
          state: >
            {% set id = this.attributes.get('id') %}
            {% set batt_volts = states('sensor.'~id~'_hygro_temp_voltage')|float(0) %}
            {% set batt_pct = 55.55 * batt_volts - 83.31 %} {# calculate percent from the voltage #}
            {% set batt_pct_clamped = ([0, batt_pct, 100]|sort)[1]|int %} {# clamp the output to a 0-100% range #}
            {{batt_pct_clamped}}

note I changed the availability template, because the is_number doesnt work on the state like that.

It has to do with the order of evaluation (I think, Petro will know for sure), but, since in those state templates the defaults guard the template for incorrect input, this might do as well. Not sure though, as it practically says, I exist, so I am available…

the next sensor would be:

      - unique_id: battery_test_anchor_002
        attributes:
          id: 002
        <<: &batt_sensor

      - unique_id: battery_test_anchor_003
        attributes:
          id: 003
        <<: &batt_sensor

I hope…

ofc adapt the

 {% set batt_volts = states('sensor.'~id~'_hygro_temp_voltage')|float(0)

line according to your source sensors object_id convention

Lastly, depending on your use case, you might not even need all of these sensors in the state machine, but could do with the front-end representation only? Using template-entity-row, and ofc, auto-entities :wink:

lasmost even more powerful:

  - type: custom:auto-entities
    card:
      type: entities
      title: Binaries update available
      state_color: true
    show_empty: false
    filter:
      include:
        - entity_id: binary_sensor.*_update_available
          state: 'on'
          options:
            type: custom:template-entity-row
            name: >
              {% if states[config.entity] is not none %}
              {{state_attr(config.entity,'friendly_name').split(': Update Available')[0]}}
              {% else %} Initializing
              {% endif %}
            state: >
              {% if states[config.entity] is not none %}
                {{iif(states(config.entity) == 'on','Update available','Up to date')}}
              {% else %} Waiting for state
              {% endif %}
            secondary: >
              {% if states[config.entity] is not none %}
                {% set id = states[config.entity].object_id
                  .split('_update_available')[0] %}
                {% if states['sensor.' + id + '_newest_version'] is not none %}
                New: {{states('sensor.' + id + '_newest_version')}} -
                {% endif %}Current:
                {{states('sensor.' + id + '_version')}}
              {% else %} Initializing
              {% endif %}
            active: >
              {{is_state(config.entity,'on')}}

Looks simple, thanks :+1:

@Mariusthvdb

I’ve been playing with it and got it to work. There’s only one thing I’m stuck with; I now have 2 nameless sensors. How can I get them to have a name containing the id?

template:
  - sensor:
      - unique_id: in100_0001_battery
        attributes:
          id: bthome_sensor_0001
        <<: &in100_batt_sensor
          name: >
            Battery: {{this.attributes.get('id')}}
          unit_of_measurement: "%"
          device_class: battery
          state: >
            {% set id = this.attributes.get('id') %}
            {% set batt_volts = states('sensor.'~id~'_count')|float(0)/32 %}
            {% set batt_pct = 55.55 * batt_volts - 83.31 %} 
            {% set batt_pct_clamped = ([0, batt_pct, 100]|sort)[1]|int %} 
            {{batt_pct_clamped}}

      - unique_id: in100_0002_battery
        attributes:
          id: bthome_sensor_0002
        <<: *in100_batt_sensor

I expected to see unique_id: in100_0001_battery and unique_id: in100_0002_battery in Development Tools, States, but that isnt the case. I guess the unique_id’s are for internal reference only.
Also, id: must be a string, a numerical name isnt accepted. Placing i.e. 0001 in single or double quotes throws an error.

no? they have names as is clearly shown in your screenshot?

unique_id indeed is an internal identifier used by the system. as long as its unique, you can make it anything, there are online aid generators you can use, I always like to use the same as my object_id, which is also unique, and makes for clear yaml configs

not sure what you are saying here, because using single or double quotes would make not a string, not a numerical

yaml really only ‘requires’ quotes around boolean values, because is you dont use quotes there, yaml interpreted them as booleans. (on/off, true/false, yes.no)

anything else can be used without quotes. Unless of course inside the jinja templates like the .get('id'). if you’d use .get(id) it would see id as a variable that should have been defined before using that

if you need a number and its the output of a template (which is always a string) you need to ‘cast’ it to |int or |float, to make those numbers again and use numerical operations on them

Let me rephrase;

I’d like the sensors to have a more comprehensive name. So in stead of sensor.battery_id_none I’d like it to be named battery_bthome_sensor_0001, or something that makes it easier to link to the id I set in the sensor definition. Where does this sensor.battery_id_none come from anyway?
Same goes for sensor.battery_none, where is this name set?

As for id:

As per your example I first put id: 0001, but HA didnt like that and returned

image

I’m sure I missed something trivial here, but if you can help me, please do :slight_smile:

that’s not HA that doesn’t like that. That’s whatever addon you’re using. It has no idea what the value should be, ignore it.

Ok, didn’t know that. I use Studio Code Server and thought that it checked the syntax. I’ve set it to 0001 and indeed it works :slight_smile:
Remains the question where the sensor labelcome from. And by that I mean sensor.battery_none, not the friendly name.

it comes from this, because the id doesn’t exist on creation and then creates it with the default output of the .get(), which will be None. That’s then slugified, making it none.

Makes sense. Is there a way to give the sensor a more meaningful name?

it has a unique_id, name it whatever you want in the ui

1 Like

I’m currently in the process of DRYing my packages using YAML anchors.
That works unless I try to reduce the (MQTT) sensor definitions even more by faciliating Mariusattributes way:

mqtt:
  sensor:
# Server & Internet
    - unique_id: nousa101_power
      attributes:
        id: 01
      <<: &power
        object_id: >
          nousa1{{this.attributes.get('id')}}_power
        state_topic: >
          "allg/steckdosen/A1"{{this.attributes.get('id')}}"/tele/SENSOR"
        availability_topic: >
          "allg/steckdosen/A1"{{this.attributes.get('id')}}"/tele/LWT"
        name: power #"nousA101 Power"
        value_template: '{{ value_json["ENERGY"]["Power"] }}'
        unit_of_measurement: "W"
        device_class: power
        state_class: measurement
        payload_available: "Online"
        payload_not_available: "Offline"

Checking my configuration throws this error:
extra keys not allowed @ data[‘mqtt’][0][‘sensor’][0][‘attributes’]. Got {‘id’: 1}
together with other errors because the referenced ‘id’ never got populated.

As @petro stated maybe the ‘id’ isn’t available upon creation of the sensor, but why does Marius’ code work while Patrick’s and mine do not?

At first I suspected this could be because mine are no template sensors but then again, at least Patrick’s should have worked like Marius’.

@Mariusthvdb how would your battery_test_anchor_kelder_aanbouw sensor be named? Perhaps I’m using the Jinja2 {{this.attributes.get('id')}} wrongly?

Because Marius most likely created this entity multiple times and the template integration restored the previous state.

This will not work for the MQTT integration because it does not have attributes as an available key for the yaml configuration. You can’t just make up YAML, you have to follow the documentation’s yaml fields. The error you’re getting is telling you that attributes isn’t valid for MQTT.

You could set that attribute in customize probably, I have that in more than 1 spot where the official integration doesn’t support it

homeassistant:

  customize:

    binary_sensor.watermeter_leak_detected:
      id: watermeter

##########################################################################################
# Binary Mqtt sensor
##########################################################################################

  binary_sensor:

    - unique_id: watermeter_smart_gateways_leak_detect
      state_topic: watermeter/reading/leak_detect
      payload_on: 'true'
      payload_off: 'false'
      device_class: moisture

I managed to customize the id attribute into the sensors and restarted HA but the error stays:
Invalid config for [mqtt]: MQTT topic name/filter must not contain control characters. for dictionary value @ data[‘mqtt’][0][‘sensor’][0][‘availability_topic’]. Got ‘“allg/steckdosen/A1”{{this.attributes.get(‘id’)}}"/tele/LWT"\n’

2 lessons learned:

  1. Petro is right (as nearly always): no attribute in mqtt integration (worth a feature request if you ask me) and
  2. Marius might be a wizard (at least one could get the notion looking at his posts and github).

your issue isnt the id itself, its the fact using those jinja templates in the config like you do. check the docs for usage of templates, your options are not among those…

you can not just copy the template sensor config onto an Mqtt sensor config

you could drop this in an anchor:

        value_template: '{{ value_json["ENERGY"]["Power"] }}'
        unit_of_measurement: "W"
        device_class: power
        state_class: measurement
        payload_available: "Online"
        payload_not_available: "Offline"

on all of the entities that use that

You’d get something like:

homeassistant:

  customize:

##########################################################################################
# Anchors
##########################################################################################

    node.anchors:

      amp: &amp
        unit_of_measurement: A
        device_class: current
        state_class: measurement

      energy: &energy
        unit_of_measurement: kWh
        device_class: energy
        state_class: total_increasing
#         <<: &value
#           value_template: >
#             {{value|round(2,default=none)}}

      power: &power
        unit_of_measurement: W
        device_class: power
        state_class: measurement

      volt: &volt
        unit_of_measurement: V
        device_class: voltage
        state_class: measurement

      kpower: &kpower
        unit_of_measurement: kW
        device_class: power
        state_class: measurement
#         value_template: >
#           {{value|round(3,none)}}

mqtt:

  sensor:

    - unique_id: zp_import
      state_topic: '70:B3:31:F2/energy-solar-sdm630-modbus/f339a2fb/import'
      <<: *energy

I know its not the same, but it does minimize your yaml very nicely