Hope someone here could help me with a contact sensor/ lock automation (all doors in 1 automation if possible)

In my instance all doors that have a lock, also have a binary contact sensor on them.
So, I would be lying to you if I said I knew what I was doing. I know very little programming and it’s one of those, I’m doing the best I can do at my ability level.

Could you show me what you mean by this in a short example?

Thank you for showing me this automation as something to learn from. This is the only way I’m going to get better at this stuff. I tend to do well with examples of things. That’s really cool on the proper grammar situation. I have now read the rest of your post, this is great. Thank you so much for showing me this! Thank you again @123

Assuming all the binary_sensors that represent doors have their device_class set to door, you can use the following template to report a list of all entity_id’s of doors.

{{ states.binary_sensor
  | selectattr('attributes.device_class', 'defined')
  | selectattr('attributes.device_class', 'eq', 'door')
  | map(attribute='entity_id') | list }}

This would report only closed doors.

{{ states.binary_sensor
  | selectattr('attributes.device_class', 'defined')
  | selectattr('attributes.device_class', 'eq', 'door')
  | selectattr('state', 'eq', 'off')
  | map(attribute='entity_id') | list }}

I understand these examples, thank you for them.

@123 @calisro

So, I ended up screwing up and got a message this morning which was the first test of the messaging of the below automation (same one we have discussed on this thread)

I endedup up learning that there have been three shadow locks created on my home assistant setup by a integration/ add in called keymaster.-- It helps set door code schedules etc.

Their naming conventions are as below. From my understanding they essentially mirror the actual lock position. They’re entity ids are named as below (I ended up find this out because they got listed in the push notification also). So this is really what my home assistant instance had with regards to locks and door contact sensors.

Lock entities:
lock.front_door_lock
lock.back_door_lock
lock.garage_entry_door_lock
lock.boltchecked_front_door
lock.boltchecked_back_door
lock.boltchecked_garage_entry

**I am willing to change the name of the boltchecked ones if completely necessary.

contact sensor that I have placed on the doors:
binary_sensor.front_door
binary_sensor.back_door
binary_sensor.garage_entry_door

1.) Is there a way to ignore entities with “boltchecked” in the entity id in the below code? I don’t fully understand the below code but I understand most of it. (I think it may be causing duplication in both sides of the choose action.

2.) Additionally is there a way to have the below code send the “friendly name” in the notification rather than the entity ids.

3.) Lastly and probably more importantly, will this code work properly if both sides of the choose need to be executed? As is, if I have a door open in the house AND I have a door closed but unlocked. Will this report to me both of those issues?

@123 Am I better off switching to your code? Or do you think the below is fixable without a ton of effort. #3 above concerns me if it is the opposite of what we would prefer.
CODE EDITED 6-9-22 12:30 PM

alias: (ACTION- AUTOMATIC- SECURITY- NOTIFICATION) Doors lock when Away
description: ''
trigger:
  - platform: state
    entity_id:
      - group.family
    from: home
    to: not_home
action:
  - choose:
      - conditions:
          - condition: template
            value_template: "{{ open_doors | count > 0 }}"
        sequence:
          - service: notify.mobile_app_weston
            data:
              title: DOORS ARE OPEN
              message: "The following doors are open: {{ open_doors | join('\n- ') }}"
      - conditions:
          - condition: template
            value_template:  "{{ unlocked_closed_doors | count > 0 }}"
        sequence:
          - service: notify.mobile_app_weston
            data:
              title: DOORS ARE UNLOCKED (AWAY LOCK)
              message: "The following doors were left unlocked: {{ unlocked_closed_doors | join('\n- ') }}"
          - service: lock.lock
            target:
              entity_id: "{{ unlocked_closed_doors }}"
mode: single
variables:
  open_doors: |
    {{ expand(states.lock
      | map(attribute='entity_id')
      | map('replace', 'lock.', 'binary_sensor.')
      | map('replace', '_lock', ''))
      | selectattr('state', 'eq', 'on')
      | map(attribute='entity_id')
      | map('replace', 'binary_sensor.', 'lock.')
      | map('regex_replace', '$', '_lock')
      | list
    }}
  unlocked_closed_doors: |
    {{ states.lock
      | selectattr('state', 'eq', 'unlocked') 
      | map(attribute='entity_id')
      | reject('in', open_doors)
      | list }}

Like I explained in my previous post, I used two consecutive if to avoid the situation you have encountered with choose. In addition, the version I posted already reports the entity’s friendly name.

Yes, it’s possible to modify the template so it rejects any object_id containing the word “boltchecked”. However, the resulting template increases in complexity so it may be more efficient to use the other technique I mentioned. Do all three binary_sensor entities, representing your doors, have a device_class attribute set to door?

If they don’t, it can be added manually however that might break one of the rules you stipulated in your first post (where newly added doors and locks are automatically handled by the automation).

I understand and follow.

In my instance, the binary sensors representing the doors are device class “opening”. I don’t really know how to do/ or use what you are thinking. I am very new to Home Assistant. I just recently came over from smartthings.

I don’t think I fully understand this. Added manually?

I also found this about the boltchecked entity that was created by the keymaster add-in/ integration. Could this help my situation in any way? It sounds like the boltchecked shadow lock could make things easier for me but I would still rather do this without taking advantage of it. The biggest problem is, things are working physically (the locks are closing) but when the notification comes through, it is throwing in those additional shadow lock entities with “boltchecked” in their names.

‘’’

OK, that’s fine. We can use that (instead of “door”) as long as all three of the doors have the same value for their device_class and no other binary_sensors have it. I’ll wait for you to confirm that before I proceed to suggest how to modify the template to take advantage of it.

Yes, it’s possible to manually add attributes to an existing entity. For example, the integration that created the binary_sensors shown in your screenshot didn’t create a device_class for some of them. That was the decision of the integration’s author. However it’s possible to manually add it and any other custom attribute you want … but it’s a manual step and wouldn’t happen automatically if the integration were to add an additional door lock.

@123 Thank you for the clarification. I understand, yes, so to me, that makes my code attempt no good.

I will end up moving to yours as this is a big issue to me.

So the question now becomes since the boltchecked locks are named as below (to me these are virtual/ shadow locks):
lock.boltchecked_front_door
lock.boltchecked_back_door
lock.boltchecked_garage_entry

and the actual physical locks are named as below:
lock.front_door_lock
lock.back_door_lock
lock.garage_entry_door_lock

For clarity for other reading this thread after us. Will my boltchecked entities cause issues for when using your code? Or since they are not followed by _lock, I should be fine.

I have a feeling, I know what you are thinking about now. I will say that at some point, I think it is possible that I will add window sensors to my Home Assistant setup and I imagine they will be the standard contact sensors that will probably come into Home Assistant as the “opening” device class. (Entity id will always contain “window” as the last word of the entity, more than likely) Would now be the time to start doing what you are thinking and assigning different device classes to entities? Or could I make it work in the future just based off of proper entity naming.–> I’m sorry that I don’t know very much so all I’m really able to do is tell someone what I see/ am thinking on my end and hopefully learn from what they do or show me.

Oh Lord, I didn’t even know that was possible but I see what you are talking about now.

I follow you, well to be honest, I don’t (for now at least) expect to use any of the entities created by the keymaster integration in any automations. So below are screenshots of the vanilla (expected things I would use in an automation surrounding the doors)

So I have 3 doors. A front door, back door and garage entry door. Below are screenshots of my states tab that I believe will help you know what is in my setup. The “boltchecked” lock entities, I really don’t want to be used or “hit”/ affected by any automations. The only reason, I really added the keymaster integration was so that I could schedule codes from home assistant to the app but I’m afraid that the “boltchecked” lock is integrated in other ways that I don’t know of so I’m afraid to go nuclear and just delete it.

@123 Thank you for your help once we realized my attempt was a pumpkin. :frowning:

The existence of any entity whose object_id ends with _lock will be included by the template that produces the doors variable in my example. That means the entities with “boltchecked” will also be included and that’s undesirable for this application.

That’s why I asked my previous question. I need to know if the three binary_sensors we want to use (representing the doors) all have opening for their device_class and no other entity has the same value for its device_class.

That’s a reasonable assumption but, as you may already know, presents a problem for complying with one of your design requirements. You don’t want to tweak this automation every time you add a new door lock or window or whatever. That means we can’t simply select entities based on the value “opening” because it might use windows too.

It might also mean that rejecting locks containing “boltchecked” might be insufficient in the future? Perhaps some other ‘sibling’ entity will be created containing yet another phrase that will need to be rejected.

I realize you don’t want to hard-code the doors and locks into the automation but I can tell you it helps to simplify it substantially. Besides, just how many more door locks do you plan to add in the future?

They do and yes, no other entity in my HA setup right now has “opening” has it’s device class.

Now I follow you and agree.

I am seeing what you are saying.

Currently, none. Where I am new to HA, I honestly thought HA was powerful enough to build things that could self “heal” ( as in using a variable to design for future possibilities, etc.). That was my biggest reason for the potential requirements. Also, in my short time with home assistant, I have seen myself making a change to an entity id in the GUI to then find out that the change didn’t automatically go into every instance in which I had used it in a GUI automation and propagate the entity id change automatically for me (I just figured it would, maybe that is wrong of me). I believe that is what has me want to build everything modularly at this point. Can doors/ locks be added to a group and then a person would only have to modify information about the group in order to fix all of the automations that have been created with those items? – I guess I am just trying to make things where at the most, I have to modify a file in 1 place rather than have to go through and modify a bunch of individual automations etc.

I am ok with whatever ideas you have, I was just hoping to make maintaining things a one place change situation.

Thank you for the conversation. I believe I follow you on everything. Hope you can give me your thoughts on the above.

The boltchecked items don’t end with “_lock” but I follow you in general on everything you’ve said. (And in all honesty, they probably should have, I just named them stupidly, so this is a void comment anyway)

It is but it may require careful consideration to make it completely predictable regardless of what new entities may be added in the future. The challenge here is that your application relies on pairs of entities (binary_sensor and lock) and the only tenuous connection between them is that a portion of their names are identical. A fair bit of string filtering is needed to ensure it rejects unwanted entities (which complicates the template).

It definitely won’t do that. You’re changing what’s used to refer to the entity and it doesn’t ripple through everywhere it may be referenced in automations, scripts, scenes, etc.

Sorry, I explained that incorrectly; it’s a lock entity so it’ll get included by a template that uses states.lock (like the one that reports doors by basing itself on locks). The template would need to filter out any entity whose object_id started with ‘boltchecked’. That would work fine unless, some time in the future, a new lock entity was added, unrelated to doors, that started with some other phrase than ‘boltchecked’.

I understand what you are saying.

I see. I think that was a dream I had. :slight_smile:

Now I follow you.

I think I understand you now.

So then the question for me becomes (based on what was stated in post 15):

What would be my best bet in utilizing your code with the “boltchecked” items existing in my setup (which don’t currently end with “_lock” in the name, but I can change them to end with “_lock” as the last of the name. The problem with this still becomes, I believe the notification will spit these boltchecked items out into the final notification. Or am I wrong with that last statement?

I keep getting the sense that these boltchecked lock items are a pretty big issue with what I am trying to do and I don’t really know how to get your code to ignore them if possible.

Also, you were speaking of I should consider changing the device class of my contact sensors that are currently showing “opening”, how do I do that and what is the purpose? Is that so, they can be more customized to what they do and so that I can access them individually through their own device class). I never really liked how they report on- off, is this also something that can be fixed with your thoughts, as in open-closed. Or I am best to not mess with that?

Repost of code being discussed is below for other visitors:

alias: 'Example of door and lock monitor'
trigger:
- platform: time
  at: '22:00:00'
- platform: state
  entity_id: group.family
  from: 'home'
  to: 'not_home'
  for: '00:00:10'
condition: []
action:
- variables:
    doors: >
      {{ states.lock | map(attribute='object_id')
        | map('regex_replace', '(^.*)_lock$', 'binary_sensor.\\1') | list }}
    open_doors: >
      {{ expand(doors) | selectattr('state', 'eq', 'on')
        | map(attribute='name') | list }}
    closed_doors_unlocked: >
      {{ expand(expand(doors) | selectattr('state', 'eq', 'off')
        | map(attribute='object_id')
        | map('regex_replace', '(^.*$)', 'lock.\\1_lock') | list)
        | selectattr('state', 'eq', 'unlocked')
        | map(attribute='entity_id') | list }}
- if: '{{ open_doors | count > 0 }}'
  then:
  - service: notify.mobile_app_weston
    data:
      title: DOORS ARE OPEN
      message: "The following door{{ iif(open_doors | count > 1, 's are', ' is') }} open: {{ open_doors | join('\n- ') }}"
- if: '{{ closed_doors_unlocked | count > 0 }}'
  then:
  - service: lock.lock
    target:
      entity_id: '{{ closed_doors_unlocked }}'
  - service: notify.mobile_app_weston
    data:
      title: DOORS WERE LEFT UNLOCKED (AWAY LOCK)
      message: "Locked the following: {{ closed_doors_unlocked | map(attribute='name') | list | join('\n- ') }}"

I suggest you change the doors template from this:

- variables:
    doors: >
      {{ states.lock | map(attribute='object_id')
        | map('regex_replace', '(^.*)_lock$', 'binary_sensor.\\1') | list }}

to this:

- variables:
    doors: >
      {{ states.lock | rejectattr('object_id', 'match', 'boltchecked')
        | map(attribute='object_id')
        | map('regex_replace', '(^.*)_lock$', 'binary_sensor.\\1') | list }}

It rejects any lock entity whose object_id begins with ‘boltchecked’. That should be adequate to pare the list of locks down to only the three that you want.

Here’s the entire, revised automation:

alias: 'Example of door and lock monitor'
trigger:
- platform: time
  at: '22:00:00'
- platform: state
  entity_id: group.family
  from: 'home'
  to: 'not_home'
  for: '00:00:10'
condition: []
action:
- variables:
    doors: >
      {{ states.lock | rejectattr('object_id', 'match', 'boltchecked')
        | map(attribute='object_id')
        | map('regex_replace', '(^.*)_lock$', 'binary_sensor.\\1') | list }}
    open_doors: >
      {{ expand(doors) | selectattr('state', 'eq', 'on')
        | map(attribute='name') | list }}
    closed_doors_unlocked: >
      {{ expand(expand(doors) | selectattr('state', 'eq', 'off')
        | map(attribute='object_id')
        | map('regex_replace', '(^.*$)', 'lock.\\1_lock') | list)
        | selectattr('state', 'eq', 'unlocked')
        | map(attribute='entity_id') | list }}
- if: '{{ open_doors | count > 0 }}'
  then:
  - service: notify.mobile_app_weston
    data:
      title: DOORS ARE OPEN
      message: "The following door{{ iif(open_doors | count > 1, 's are', ' is') }} open: {{ open_doors | join('\n- ') }}"
- if: '{{ closed_doors_unlocked | count > 0 }}'
  then:
  - service: lock.lock
    target:
      entity_id: '{{ closed_doors_unlocked }}'
  - service: notify.mobile_app_weston
    data:
      title: DOORS WERE LEFT UNLOCKED (AWAY LOCK)
      message: "Locked the following: {{ closed_doors_unlocked | map(attribute='name') | list | join('\n- ') }}"

EDIT

Correction. Change order of filters in doors variable.

@123 You make things look easy. I didn’t know that you could do a match and reject like that. Again, I’ll be honest. I don’t know much yet when it comes to HA but hopefully I will get there. I am learning more everyday for sure.

This makes sense once I see it.

Thank you for sharing your automations with me and your knowledge of how to get it to work with my setup. I’m sorry, I wasn’t much help but I really do appreciate you helping me with this one.

@123 Could you possibly help me trouble shoot what happened tonight with this automation. It seems the automation ran properly because when I go to my logbook, I have this line item showing (so I had 1 door unlocked tonight apparently):

Garage Entry Door Lock was locked by (ACTION- AUTOMATIC- SECURITY- NOTIFICATION) Doors Lock when Away and at Night
10:00:05 PM - 5 minutes ago

But when the text message came through (all it had was a header with no listing of this lock in the message).

Can you think of anything that could be happening or is there anything else I can get for you to be able to help me troubleshoot it?

Thank you for any help you can provide.

Below is what I’m getting when I paste the doors section of your code into the template editor.

UndefinedError: 'str object' has no attribute 'object_id'

When I pasted what you originally gave me as our first attempt, it returned a list of locks. That makes me think their is an issue with this:

    doors: >
      {{ states.lock | map(attribute='object_id')
        | rejectattr('object_id', 'match', 'boltchecked')
        | map('regex_replace', '(^.*)_lock$', 'binary_sensor.\\1') | list }}

But I don’t know what I’m doing so even if there is, I don’t really know what to look for in order to fix it.

Well that one’s my fault. I added the rejectattr filter in the wrong place. It should be placed immediately after states.lock and not after the map filter. I have corrected the order of the filters in the example posted above.


You can test the automation at any time by clicking the Run Action button located next to the automation’s name in the list of automations. When you do that, it skips the automation’s trigger: and condition: sections and only executes its action: section. That’s fine for this particular automation (but not for one that has conditions or references the trigger variable somewhere in its condition or action because it will be undefined).

Oh, ok, I didn’t know that.

Thank you for letting me know this. I saw it but was afraid to click it. I felt funny waiting until bedtime last night to check it. haha

Thank you helping me with all of this. It was a little too difficult for me right at the moment with my skillset. I have learned alot from you!

No rush on this at all but can you help me understand some of your code? (It is pasted below)

        | map('regex_replace', '(^.*)_lock$', 'binary_sensor.\\1') | list }}

I don’t understand this. The strange syntax, “.\1” and "(^.*$)

How do you know when to use “object_id” rather than “entiity_id” in the maps and filters? I have used entity_id before but never “object_id”.

And the last thing I would like to ask is, what is the best way for me to learn the stuff you used if I am not a programmer but do understand alot of what you’re doing? I don’t feel like I can find any good resources and I don’t feel like perusing the forums is going to be a way for me to learn the generalities quickly (I’m thinking more like school textbook if possible for quick/ condensed learning)

That syntax is indisputably strange and is part of what is known as “regular expression” or the abbreviation “regex”. It’s a very terse (and cryptic) way of expressing commands to manipulate text. The regex_replace filter is for replacing one string of text with something else but with great precision and flexibility.

This is known as a regex pattern

(^.*)_lock$

It is designed to match text that begins with anything but must end with the string _lock.

  • The $ symbol has special meaning (i.e. it doesn’t try to match a literal dollar sign). It means _lock must be located at the end of the string. Regex employs many characters with special meaning.
  • This ^.* means to match any text starting from the beginning of the string.
  • The surrounding parentheses here (^.*) will keep a copy of whatever text it finds using ^.*. It’s called a ‘capture group’.

So if the string is back_door_lock then it will be a match for the given regex pattern and it will keep a copy of back_door.

The second argument in regex_replace is this

binary_sensor.\\1

It represents the text that will be used to replace the matched text found by the regex pattern.

  • This \1 is a reference to the text that was copied by the regex pattern. Think of it like “variable number one” or ‘the first capture group’.
  • The backslash symbol has special meaning for regex. It is used to escape another character’s meaning. For example if I want to match a literal $ character, I have to escape it’s meaning otherwise regex will assume I want to use it to indicate the end of the string. To escape its meaning you simply prepend a backslash like this \$ and now the dollar sign is just a dollar sign and no longer means “end of string”.
  • We want regex to understand that \1 represents the first capture group and not an attempt to escape the meaning of the number one. So we prepend a backslash \\1 to make it clear we want the first capture group.

So if the string is back_door_lock it will be replaced by binary_sensor.back_door because the first capture group contains back_door.

Regex is a powerful but complex tool and one of the best ways to learn about it is to experiment with it using an interactive tool like regex101.com.

Given this entity_id:

lock.back_door_lock

Its domain is lock and its object_id is back_door_lock.

If I need to manipulate the text in back_door_lock then it’s more efficient to reference it by object_id rather than by entity_id which contains text (the word lock followed by a period) that I am not interested in using.

You’re ahead of the game if you understand my explanations. :slightly_smiling_face:

It’s difficult to point you to a single comprehensive reference but I suggest starting with the Templating section of the documentation.