KeyMaster Z-Wave lock manager and scheduler

Yes, I believe that’s the one. It’s what tells you the code is in the lock or not, right?

Yeah, this is the special sauce that makes this package work. A code slot is “active” meaning the lock is “hosting” a PIN that will control the lock. A lock has a file for each code slot. For example, frontdoor_lock_manager_1.yaml is for the code slot #1 for the front door. Let’s look at it:

    active_frontdoor_1:
      friendly_name: "Status"
      value_template: >-
         {{
            is_state('binary_sensor.enabled_frontdoor_1', 'on')  and  
            is_state('binary_sensor.access_count_frontdoor_1', 'on')  and  
            is_state('binary_sensor.daterange_frontdoor_1', 'on') and
            is_state('binary_sensor.smtwtfs_frontdoor_1', 'on')  
         }}
      device_class: connectivity

So in order for a slot to be active, four binary sensors need to be true. Let’s look at the first sensor binary_sensor.enabled_frontdoor_1 Search for that sensor definition and you will see:

    enabled_frontdoor_1:
      value_template: "{{ is_state('input_boolean.enabled_frontdoor_1', 'on') }}"

So “enabled” means that input_boolean is on. I didn’t need to create a sensor to check if the input_boolean was turned on, but I did it for consistency. By creating a lot of binary sensors, I can “add” them together to determine the status of the code slot. Let’s look at the smtwtfs_frontdoor_1 sensor. What does this mean?

    smtwtfs_frontdoor_1:
      friendly_name: "Status"
      value_template: >-
         {{
            is_state('binary_sensor.sun_frontdoor_1', 'on')  or  
            is_state('binary_sensor.mon_frontdoor_1', 'on')  or  
            is_state('binary_sensor.tue_frontdoor_1', 'on')  or  
            is_state('binary_sensor.wed_frontdoor_1', 'on')  or  
            is_state('binary_sensor.thu_frontdoor_1', 'on')  or  
            is_state('binary_sensor.fri_frontdoor_1', 'on')  or  
            is_state('binary_sensor.sat_frontdoor_1', 'on')   
         }}

Ok, this is a little different. This is doing an OR operation on that slot’s “day” sensor’s for every day of the week. Once again, what does this mean? Well, go find the code to see:

    sun_frontdoor_1:
      entity_id:
        - sensor.time
        - input_datetime.sun_start_date_frontdoor_1
        - input_datetime.sun_end_date_frontdoor_1
      value_template: "{{ ((is_state('input_boolean.sun_frontdoor_1', 'on'))) and (strptime(states('sensor.date'), '%Y-%m-%d').strftime('%A') == 'Sunday') and ((states.input_datetime.sun_start_date_frontdoor_1.state  == states.input_datetime.sun_end_date_frontdoor_1.state) or ((states('sensor.time') >= states('input_datetime.sun_start_date_frontdoor_1')[0:5]) and (states('sensor.time') <= states('input_datetime.sun_end_date_frontdoor_1')[0:5]))) }}"

So the “Sunday” sensor returns true if the Sunday input boolean is turned on AND the current system time falls in between the times specified in the UI. Every Code slot defaults to every day’s boolean being on and the time range being 00:00-00:00, which means every minute of the day of the week is included. So to limit codes from being on, you exclude them from days of the week and/or times as well. The access_count, and date range “exclusion” UI features work in a similar fashion.

So the “active” status is those four “big” sensors added together, and those sensors are comprised of “smaller” sensors, which may be comprised of even smaller sensors, but eventually they are defined by UI elements and/or system states.

Once you understand this concept, it’s not hard to expand upon it. Let’s say you want to use this package so people (code slots) can only access a lock on business days, during business hours. You would disable the Saturday and Sunday input booleans so those codes would be removed whenever the system time changes to either of those days. You would also change the time ranges to 09:00-17:00 for Monday-Friday, so the code (PIN) is added to the lock when the system time changes inside that range and is removed outside that range.

Now let’s say that you want to add a feature that a slot is inactive on Federal holidays. you would need to add an input boolean to turn this feature on/off. You would add this to lovelace.head file and add the sensors to lock_manager.txt file. The setup.sh script takes these files to construct the <lockname>_lock_manager_X.yaml files. (The setup script is also a big part of the “special sauce”, so you don’t have to create many files and modify them by hand).

When you are adding this new “Federal Holiday” feature, you’re going to add new binary sensors to lock_manager.txt file. We already determined we need an input_boolean to determine if this feature will be on/off for a code slot. So this sensor would return “true” if the input_boolean is on (to exclude holidays) and if today is a federal holiday.

You might add something to lockmanager.txt like:

    exclude_federal_holiday_LOCKNAME_TEMPLATENUM:
      friendly_name: "Exclude Federal Holiday"
      entity_id:
        - sensor.time
      value_template: >-
         {{
            (is_state('input_boolean.exclude_fedholiday_LOCKNAME_TEMPLATENUM', 'off'))  and  
            ( pseudocode to return TRUE if  the current system time (as expressed in states('sensor.time') is on the date of a federal holiday)
         }}

So now when you enable that slot’s input boolean for Federal Holiday, it will remove the code (or prevent it from being added) if the system time falls on a federal holiday.

1 Like

Other than the gawk issue I think all the indexes should be able to be set to -1 (could be wrong I didn’t review ALL the bits). That was the other fix for a major portion of people posting.

I don’t follow. The indexes for what?

Here’s the snippet:

      action:
        - service: lock.set_usercode
          data_template:
            node_id: >- 
                {{states.lock.schlage_allegion_be469_touchscreen_deadbolt_backdoor.attributes.node_id}}
            code_slot: >-
                {% set object_id = trigger.to_state.object_id %}
                {% set index = -1 %}
                {% set code_slot = object_id[index:] %}
                {{ code_slot  }}
            usercode: >-
                {% set object_id = trigger.to_state.object_id %}
                {% set index = -1 %}
                {% set code_slot = object_id[index:] %}    
                {% set codetext = 'backdoor_pin_' + code_slot | string %}
                {% set code = states['input_text'][codetext].state %}
                {{ code | string }}

The set index = -1 part :slight_smile:

Not sure why this is cropping up, unless a sensor name got changed. Regardless, using -1 shouldn’t work. The point of setting the index is to get the slot number, which is found by examining the name of the object that triggered the automation. I believe those object names were always 14 and 17 long, so I hard coded it. I modified the code to set the index to position of the rightmost underscore plus 1, so it should get the correct slot number now.

But I don’t know what to do in order to test it using the “wrong” lock names you chose. So perhaps you can use test it with this file:

You will need to run setup.sh again, of course. If that works, I’ll merge the change into the master branch.

Thanks for the full details. Greatly appreciated. I’m doing something similiar with multiple input booleans. The issue I’ve noticed is that once in a while the lock failed to complete the zwave command and the input booleans have no way of knowing that. So the status is code is in the door, but it really is not. Or the opposite, the code does not get removed. This does not happen to often, but it does occasionally. For me at home, it’s no biggie, but for scheduled codes or maybe a vacation rental home, it would be a bigger deal, if a code failed to load or remove. I’d love to be able to get a zwave status update back saying, command completed successfully.

would love to see @ptdalen and and @FutureTense join their efforts so we can have two amazing devs working on one project to make it even better :slight_smile:

2 Likes

I’d like to see this become a HACS integration. I’ve gotten this working only partially a couple times and then completely break it trying to figure out the issue; but a fully working manager continues to elude me. I think that would make this much more user friendly and leave less room for error if the install was made more fool proof. Perhaps this would also reduce the number of people bombarding these awesome devs with questions. I can see the potential and I appreciate the work you all have done!

I don’t see that happening anytime soon. To embed this into HA would require a GUI editor to add/remove locks. If someone else is comfortable doing this, I’d be willing to work with them in getting started — or even passing ownership of the project to them.

Do you have a list of lock related zwave functions and their status? For example, the “delete code” function (to my knowledge) doesn’t work. This is why I use a random number to “delete” a slot by overwriting it. Is there a function that reliably retrieves a code? If so, it should be simple to add the checks you are trying to add.

There is but it only dumps it to the log if I recall, so not really useful. Here’s hoping the OZW 1.6 has some updated features to allow better lock handling.

There are a lot of possible codes, here is a super long document

This is from page 219

The issue is that either OWZ 1.4 does handle all these codes, or not all locks report these codes. My Schlages do not report any of the code values, but if everything worked as it shows in the document, the alarm_type sensor would report code changes, deleted, etc.

1 Like

Yes, without accurate reporting from zwave, there isn’t much we can do.

What this package does is fairly simple. It lets you define sensors for when a lock-code should be active. When a lock-code sensor turns true/false the code should be entered/deleted from the lock. Then through the setup script, it will configure a lock with as many code slots as you define in the .ini file, in addition to generating the lovelace for that lock.

1 Like

Hey guys,

I’m extremely close to getting this working, but I have one nagging error I can’t resolve. When entering my scripts, HA doesn’t appear to see my input_boolean.yaml file. It will not auto-populate when I start typing input_boolean in the “Name of the automation to turn on” field. When I manually type out “input_boolean.allow_automation_execution” in that field and check the scripts.yaml file, I don’t see an id number like I do in automation or in the examples of scripts.yaml posted in this thread. In my configurations.yam. file, I have “input_boolean: !include input_boolean.yaml” which I would think is all that is needed for HA to see the .yaml file.

Here is the error I’m receiving:

unable to find referenced entities input_boolean.allow_automation_execution
Unable to find referenced entities input_boolean.system_ready

Just playing around with a log parsing. I found that If I ran this from a command line

grep "Node104, Value::Set - COMMAND_CLASS_USER_CODE" OZW_Log.txt -A 17 >
lock_details.txt

where my lock node ID is 104 for my lock, the last line (line 17) always is the same when I have a good code sent event. Trying to get a bad send so I can compare

This is what looks to be the send code event.

2020-05-26 14:15:23.024 Info, Node104, Value::Set - COMMAND_CLASS_USER_CODE - Code 1: - 1 - 1 - 0x31 0x38 0x35 0x32
2020-05-26 14:15:23.024 Detail, Node104, Setting Encryption Flag on Message For Command Class COMMAND_CLASS_USER_CODE
2020-05-26 14:15:23.024 Detail, Node104, Queuing (Send) UserCodeCmd_Set (Node=104): 0x01, 0x0f, 0x00, 0x13, 0x68, 0x08, 0x63, 0x01, 0x01, 0x01, 0x31, 0x38, 0x35, 0x32, 0x25, 0x26, 0xec
2020-05-26 14:15:23.024 Detail, Node104, Setting Encryption Flag on Message For Command Class COMMAND_CLASS_USER_CODE
2020-05-26 14:15:23.024 Detail, Node104, Queuing (Send) UserCodeCmd_Get (Node=104): 0x01, 0x0a, 0x00, 0x13, 0x68, 0x03, 0x63, 0x02, 0x01, 0x25, 0x27, 0xef
2020-05-26 14:15:23.024 Detail, 
2020-05-26 14:15:23.024 Info, Node104, Processing (Send) Nonce Request message (Callback ID=0x26, Expected Reply=0x13)
2020-05-26 14:15:23.024 Info, Node104, Sending (Send) message (Callback ID=0x26, Expected Reply=0x13) - Nonce_Get(UserCodeCmd_Set) - 0x01, 0x09, 0x00, 0x13, 0x68, 0x02, 0x98, 0x40, 0x05, 0x02:
2020-05-26 14:15:23.029 Detail, Node104,   Received: 0x01, 0x04, 0x01, 0x13, 0x01, 0xe8
2020-05-26 14:15:23.029 Detail, Node104,   ZW_SEND_DATA delivered to Z-Wave stack
2020-05-26 14:15:24.459 Detail, Node104,   Received: 0x01, 0x05, 0x00, 0x13, 0x02, 0x00, 0xeb
2020-05-26 14:15:24.460 Detail, Node104,   ZW_SEND_DATA Request with callback ID 0x02 received (expected 0x02)
2020-05-26 14:15:24.460 Info, Node104, Request RTT 1435 Average Request RTT 1012
2020-05-26 14:15:24.512 Detail, Node104,   Received: 0x01, 0x10, 0x00, 0x04, 0x00, 0x68, 0x0a, 0x98, 0x80, 0x55, 0x5e, 0xa9, 0x4e, 0xea, 0x63, 0xa0, 0xa6, 0xf2
2020-05-26 14:15:24.512 Info, Node104, Received SecurityCmd_NonceReport from node 104
2020-05-26 14:15:24.512 Info, Node104, Sending (Send) message (Callback ID=0x28, Expected Reply=0x13) - UserCodeCmd_Set (Node=104): 0x01, 0x0f, 0x00, 0x13, 0x68, 0x08, 0x63, 0x01, 0x01, 0x01, 0x31, 0x38, 0x35, 0x32, 0x25, 0x28, 0xe2
2020-05-26 14:15:24.522 Detail, Node104,   Received: 0x01, 0x04, 0x01, 0x13, 0x01, 0xe8
2020-05-26 14:15:24.522 Detail, Node104,   ZW_SEND_DATA delivered to Z-Wave stack

I bet with a little bit of work I could create a command line to do this after code is sent and notify if the expected outcome was not received. Still thinking through the details right now

So still just on a command line, but I’ve found that if I run this

grep "Node104" OZW_Log.txt | grep "Node104, Value::Set - COMMAND_CLASS_US
ER_CODE" -B 0 -A 16 | tail -1 > lock_details.txt

after setting a code I received this output
2020-05-26 14:15:24.522 Detail, Node104, ZW_SEND_DATA delivered to Z-Wave stack

Again, Node104 is my lock.

Delivered, but not verified. Do you know how to create a sensor out of this? Like binary_sensor.LockNode104_code_delivered?

You’d need to make a command line sensor.

Ahh true, not verified, just delivered. I still need to get a failed attempt to see how that looks.