Is there a way to trigger on any door/window sensor, without updating the automation each time a sensor is added?

So I’m about to add a ton of zigbee door/window contact sensors and want to get some notifications and act on them being opened. I don’t want to use groups - first, the GUI does not support groups (so creating and adding to the groups is a pain in the ass), and second, if a window is ALREADY open, another opening won’t trigger anything.

But I also don’t want to have to update the automation every time I add or change a sensor.

I saw another post here that used a template to count how many people were home using device_tracker. That COULD work - if the # changes. However, I’d like to be able to reference WHICH sensor changed state, not just that A sensor did.

Is there a way to do this through templates or programmatically?

1 Like

I would HIGHLY suggest learning how to use groups. They might not be able to be configured through the UI yet, but the functionality is what you are after. Could you elaborate on your second example? Do you have an automation in mind that would be different when a second or third window is opened?

90% percent of what you want to achieve can be done with a State Trigger.

The 10% that is missing is that you must explicitly list each entity.

The moment you choose another kind of trigger (to avoid listing each entity) you lose visibility of which entity triggered the automation.

Do they share any commonalities in their info (like keywords in entity_ids or other variables)? Then you could try something like the following to pull all related entity_ids:

{{ states.binary_sensor | selectattr('entity_id', 'search', '<KEYWORD>') | map(attribute='entity_id') | list }}

How would that template be used in an automation?

I think I have seen you give pretty good advice when it comes to filtering through states like that, so you are probably a better source for what is actually feasible. I did just take a look at what is allowed in limited templates, and it doesn’t seem like there are any tricky ways to provide a generated list of entity IDs for triggers. The only thing I could think of only helps if they want to use the same group of entities in multiple automations, involves throwing out that template, and still requires manually entering the entity IDs one time.

Ultimately, this is kind of a weird ask, and I was just trying to introduce potentially unfamiliar tools that might get the OP a step closer to their goal. However, it may be a bit fruitless if they consider creating a group a pain in the ass…

Personally, I would just add one more entity to the watch list for a state change trigger, like you mentioned.

Thinking on it some more:

  • First, the count and names of currently open doors/windows could be stored in an entity.
  • Then, using a template trigger, the automation could fire when the current count is different than the stored count value.
  • The stored count is then decremented and the current list of open doors/windows is compared against the stored list, where the first non-match is popped and handled.
  • Finally, repeat to keep popping entities out of the list until the counts match.

In short, pretty much try to create a group that can change states when any member changes states.

In the first step, what initiates it?

Not sure I get the question. If, for example, a number helper or sensor is used to store the last recorded number of open entities, it would be instantiated by HA with a default value of zero.

The incrementing and decrementing of this variable would be handled by the automation, so the state wouldn’t need to be defined by a template. Something like the following:

automation:
  trigger:
    - platform: template
      value_template: "{{ states.binary_sensor | selectattr('entity_id', 'search', '<KEYWORD>') | selectattr('state', 'eq', 'on') | list | count != states('input_number.open_sensors') | int(0) }}"
  variables:
    current_open_count: "{{ states.binary_sensor | selectattr('entity_id', 'search', '<KEYWORD>') | selectattr('state', 'eq', 'on') | list | count }}"
    newly_closed_entities: >
      {{ states.binary_sensor | selectattr('entity_id', 'search', '<KEYWORD>') | selectattr('state', 'eq', 'off') | selectattr('entity_id', 'in', states('input_text.open_entities').split(',')) | map(attribute='entity_id') | list }}
  action:
    - repeat:
        sequence:
          - choose:
              - conditions:
                  - condition: template
                    value_template: '{{ current_open_count < states(''input_number.open_sensors'') | int(0) }}'
                sequence:
                  - service: input_number.decrement
                    target:
                      entity_id: input_number.open_sensors
                  # Not sure what the OP wants to do at this point, lets say notify
                  - service: notify.phone_id
                    data:
                      message: >
                        {{ newly_closed_entities[repeat.index] }} has closed.
                  - service: input_text.set_value
                    data:
                      # Wouldn't be surprised if there is a better way to pull a value out of the list, but I don't feel like finding it for this example
                      value: "{{ newly_closed_entities | rejectattr('entity_id', 'eq', newly_closed_entities[repeat.index] | join(',') }}"
              - conditions:
                  - condition: template
                    value_template: '{{ current_open_count > states(''input_number.open_sensors'') | int(0) }}'
                sequence:
                  # Just copy the above, but opposite
                  # Increment, notify opened, add entity to list
        until:
          - condition: template
            value_template: '{{ current_open_count == states(''input_number.open_sensors'') | int(0) }}'

The above assumes there are two helpers, input_number.open_sensors and input_text. open_entities. These can be instantiated as zero and an empty string, respectively, and the above should handle the population, I think. Also, I’m sure there are plenty of mistakes in there, I couldn’t actually test anything other than some of the templates and I got tired of writing it :sweat_smile: but I’m hoping it’ll still get the point across.

Am I incorrect in thinking something like the above could theoretically handle an unknown list of sensors?

What I meant was what initializes and sets the count?

From your example I now see how it is set. However, it appears the initialization process is manual, meaning that when the proposed system is first implemented, you have to make sure all door/window sensors are off so that the initial value of the input_number (zero) correctly reflects their state (and the initially empty input_text). Otherwise, if three windows are already open and input_number is 0 and input_text is blank, the automation might not work as intended.

Regarding the input_text used to store entity_ids, don’t forget that any entity’s state cannot store more than 255 characters. The topic’s author stated “about to add a ton of zigbee door/window contact sensors”.

I was unsure about this. Since the automation handles setting the helpers, as long as something triggers it, it should properly populate the helpers until the stored count matches the current count. I am just unsure if that trigger will immediately fire upon creation if the values don’t match. I feel like it should, but it is not a situation I have encountered before.

If this does pose a problem, it should only be a problem initially. Meaning, once everything is set up correctly, it should proceed correctly from there on.

Very good point. I went with two helpers in the example for simplicity’s sake, but would probably try to set them up as attributes on the same entity if I was going to do it for real.

Thanks for the input :slight_smile: I got interested in the conversation and invested more time than expected. Now lets see if the OP still cares about this thread…

You’re referring to the automation’s ongoing operation. I’m referring to the initial moment when the automation (and its associated input_number and input_text) are first created.

The input_number is zero and the input_text is blank … but the user already has three windows open (they forgot to close them before installing your proposed system). Now they close one of the three windows and the automation decrements the input_number to … well it can’t decrement it because it’s already zero.

That’s what I meant by initialization and, in this proposed system, it must be performed manually. The user should close all windows and doors before implementing the system, or manually set the value of the input_number to match the number of open windows and doors. Once this initialization is performed, the system will take care of the rest and increment/decrement the input_number as doors and windows are opened/closed (as long as none are open/closed while Home Assistant is offline).

Anyway, the limitation remains the 255 character ceiling. There’s insufficient space to store a “ton” of entity_ids. I suppose one trick would be to store the entity_id without its “binary_sensor” domain.

I have no doubt there’s a way to make this happen but it seems like a lot of additional work (and inconvenience) compared to just listing the required entities in a State Trigger.

No, I’m also talking about initializing the automation.

Since the trigger is just a discrepancy between the stored value and the current number, if the stored value starts at zero and the current value starts at three, I’m unsure if the automation would trigger the minute it was created. I don’t think it would, but I wasn’t sure. I certainly agree that it would be a problem that would require manual intervention, but that could just be running the actions manually after creation.

Certainly, I think we’ve both agreed that this is a complicated solution to a nearly nonexistent problem. It just piqued my interest.

It won’t. The Template Trigger will be evaluated only when one of the eligible binary_sensors changes state. If it changes to on then there will be 4 in total (because 3 were already on in the scenario I described). 4 != 0 so the Template Trigger evaluates to true and fires. The action proceeds to increment the input_number from 0 to 1. Unless there’s manual intervention to correct the input_number, it will continue to misreport the number of open doors/windows.

That’s why I had inquired about this system’s initialization (it requires manual initialization). FWIW, there’s an opportunity to lose synchronization while Home Assistant is offline. If any window or door changes state while Home Assistant is down, on startup the input_number will be off.

One way to mitigate it is with an automation that triggers on startup (possibly even on Reload Automations), computes the number of eligible open doors and windows, and sets the input_number. Now we have automated initialization. However, we also added yet another moving part to this system. All this just to avoid listing entities … :thinking:

FWIW, it’s an interesting exercise but it’s hard to avoid producing anything other than a Rube Goldberg-like contraption.

The repeat should handle this as long as the condition is to continue until the states match, which I believe is how I wrote it in the example. Would still need that initial push though.

Now it’s getting interesting… :laughing:

Couldn’t agree more.

Thanks for all the replies - for some reason I didn’t get notified of them and just logged in to see, and there’s way too much to read through and process at the moment. I’ll hop back in when I get some time go over all the info here.

The one question I saw that I can answer quickly is that it would use the same automation - I still want the alerts if a door/window is opened and another is already open at the time (say a window is left cracked open some, but someone, not seeing that window, happens to poke out a pane of glass and reaches in to unlock a door and let themselves in. Using groups, the state would already be “on” from the open window - I’d want to still know that ANOTHER sensor was opened. A group can’t do that.

Again, thanks for all the replies. I’ll try out some suggestions tomorrow likely.

I missed this point earlier. How are you planning to write to an entity’s attribute?

Be advised the current proposal being discussed has a storage limitation. If you truly have a “ton” of sensors, it’s likely to quickly reach the 255 character limit and fail.

Emphasis on “try”, that was just my initial thought when considering this problem and nothing more went into it. Custom entities via something like a sensor is a new HA concept to me, so I am not aware of the limitations they bring and what you can and can’t write to in what ways.

A quick skim of the services and docs didn’t turn up any easy ways to write to an attribute like that, as you implied. I’d be curious if you could technically “write” to an attribute using yet another helper to temporarily hold a single entity ID that would then be either added or removed from the list with (too much) template logic, depending on the current state of that list…

However, there would probably be more obstacles I can’t foresee, and I’m not even sure if this would fix anything; do attributes have length limits as well?

FWIW, there’s a “set_state” python_script available that lets you write to an entity’s state or attribute. However, whatever value it writes is written in a manner that doesn’t survive a restart.

A far as I know, an attribute’s maximum storage capacity is undocumented and is generally accepted to be “unlimited” (although the host system’s memory capacity probably has a say in that). I can’t recall seeing any posts where someone hit the ceiling but that’s probably because no one attempts to store a lot in them.

Overlooked to mention this:

One way or another, it would require yet another moving part to the ever-growing complexity of this proposal.

1 Like