Feedback for Lights On Count Sensors

Today, I learned how to create sensors that report the number of lights on in each room. Since the code is basically the same except for the room name/entity name, I wanted to minimize the duplication of code. I found a section in the docs on reusable templates so I followed that. Is there a more efficient way to implement this use case? Thanks!

I created a file called sensor.yaml and included in configuation.yaml:

sensor: !include sensor.yaml

I created a file called room_lights_on_count.jinja and put it in the config/custom_templates folder.

{% macro room_lights_on_count(search_area) %}
  {%- set search_state = 'on' %}
  {%- set ns = namespace(lights=[]) %}
  {%- for light in states.light | selectattr('state','eq', search_state) if area_name(light.entity_id) == search_area %}
    {%- set ns.lights = ns.lights + [ light.entity_id ] %}
  {%- endfor %}
  {{ ns.lights | count}}
{% endmacro %}

Here is what is inside the sensor.yaml file. I started with an implementation for two rooms just in case there is a better way.

- platform: template
  sensors:
    dawns_office_lights_on_count:
      friendly_name: Dawns Office Lights On Count
      unit_of_measurement: "on"
      value_template: >
        {% set search_area = "Dawns Office" %}
        {% from 'room_lights_on_count.jinja' import room_lights_on_count %}
        {{ room_lights_on_count(search_area) }}

- platform: template
  sensors:
    deans_office_lights_on_count:
      friendly_name: Deans Office Lights On Count
      unit_of_measurement: "on"
      value_template: >
        {% set search_area = "Deans Office" %}
        {% from 'room_lights_on_count.jinja' import room_lights_on_count %}
        {{ room_lights_on_count(search_area) }}

You should be using the new template format for new template sensors. e.g.

configuration.yaml

template:
  - sensors:
      - name: Dawns Office Lights On Count
        unit_of_measurement: "on"
        state: >
          {% set search_area = "Dawns Office" %}
          {% from 'room_lights_on_count.jinja' import room_lights_on_count %}
          {{ room_lights_on_count(search_area) }}

      - name: Deans Office Lights On Count
        unit_of_measurement: "on"
        state: >
          {% set search_area = "Deans Office" %}
          {% from 'room_lights_on_count.jinja' import room_lights_on_count %}
          {{ room_lights_on_count(search_area) }}
1 Like

You could use YAML anchors to reduce replication
Using the example in the modern template sensor format

template:
  - sensor:
      - name: Dawns Office Lights On Count
        unique_id: 561e1136-539f-4cd5-ba9e-f558527f04db
        <<: &settings
          unit_of_measurement: "on"
          state: &state_template >
            {% set search_area = this.name | replace(" Lights On Count", "") %}
            {% from 'room_lights_on_count.jinja' import room_lights_on_count %}
            {{ room_lights_on_count(search_area) }}

      - name: Deans Office Lights On Count
        unique_id: 29487d5a-500b-4bf5-adfe-7cb660871196
        <<: *settings

I also added a unique_id to each sensor, and corrected sensors: to sensor: :slight_smile:

3 Likes

Ah, with yaml anchors I only have to do the non-unique code once. I like it. I tried using unique_id in a custom component but it wouldn’t stick. Is this going to allow me to assign the sensor to an area? Where did you get the unique id from? Thanks! Lots of good stuff here.

Thanks! Appreciate the help.

1 Like

The unique id will allow you to assign an area. I generated it using https://www.uuidgenerator.net/

It can be anything, as long as it’s unique

1 Like

Additionally, you could prevent a loop in the macro by using


{{ area_entities(search_area) |select('match', 'light') |select('is_state', 'on') |list |count }}

2 Likes

YAML is new to me so I just want to be sure that I am understanding anchors. When I define an anchor with &settings, it sets that anchor to all yaml at the current level and below. Basically, everything up to the next entry that is higher in the hierarchy. I made this assertion because there is not an ending marker for the anchor.

Everything indented under <<: will be included

1 Like