Proposal: improving the mechanisms for door locks

@April Please call this to the attention of the proper ST person.

I’m basing this off the existing “z-wave door lock” device type. In that case, when a PIN code is used to unlock a door, the event setting to the “lock” attribute to “unlocked” also sets the events to a map containing [usedCode: x] (where “x” is the index of the PIN code used. 1 for the first PIN, 2 for the second, etc.)
Example: = "lock"
map.value = "unlocked" = cmd.eventParameter[0]

The same mechanism is used when a door is locked with a PIN code.

However, this mechanism is NOT used when a door is locked/unlocked by some other means (such as auto (un)locking, manual (un)locking, and single button (un)locking.) I’d like to see ST adopt using the “usedCode” mechanism for those other means of (un)locking a door.

I know I can do this for my own device types, but if smartApp’s are to take advantage of this type of system, it must use a consistent standard (and ST is the body that should dictate that by example in their pre-existing device types.) (Otherwise, specific device types must be paired with specific smartApps, instead of having smartApps that can take advantage of ANY of a class of devices.)

  • For manual: = [ usedCode: “manual” ]
  • auto: = [usedCode: “auto” ]
  • from the keypad (but not with a PIN) such as the “Schalge” button on schlage locks: [ usedCode = 0 ]
  • from anything else: [usedCode : null ] (or simply not set)

Note that there’s a special case for locking from the keypad… in that case, it’s similar to a PIN entry (as it’s using the keypad), but no actual code was entered (hence it’s assigned a numeric value, but the index is 0.) As well, this keeps it consistent with the messages passed from the door lock to the device type.

If this is done, a smartApp can easily determine HOW a door was locked or unlocked - which is often as important as IF a door was locked or unlocked.

Example code for parsing:

def lockHandler(evt)
  def usedCode = null
  if ( != null)
    usedCode = parseJson(
  // if a usedCode was set, check that for the method used to unlock
  if (usedCode == null)
    usedCode = "Other/Unknown"
    log.debug "Lock was locked/unlocked via code $usedCode"

Edit: I just want to add that, as far as I can tell, there’s only a single existing device type (from ST) that this would impact: “z-wave lock”. The changes in there would be trivial to do.


FYI, if ST agrees to this, I’d be willing to make the needed modifications to “z-wave lock” and submit it back to ST. Keep in mind, though, that I only have a Schlage Touchscreen lock to test against, so some of the work would be incomplete. (Obviously, if I do that, someone like @Tyler would have to review my submission to get it in-place.)

(In particular, I could do the parts that use the z-wave alarm/notification v2 command class, and the parts using alarm/notification v1 that Schlage uses. In addition, I can do parts I found documented for a kwikset lock (only uses alarm/notification v1), and other things that are obvious from source. That’s not a complete list, but comes close.)

This is a good idea, though I would prefer to separate the code number and the lock/unlock mechanism. Something like

data: [ method: "code", usedCode: "1" ]
data: [ method: "manual" ]

There’s also the problem of different locks giving different levels of detail. If you had a lock that told you whether the manual unlock was via the thumbturn vs the key, would you want to report different methods for those two and risk SmartApps not understanding it was manual or do something like

data: [ method: "manual", manualMethod: "thumbturn" ]

@duncan, breaking the “method” out of the usedCode is perfectly reasonable and makes sense (and is backwards compatible.)

One thing I don’t want to do is “overthink” this. I’ve seen that happen with the capabilities - which has resulted in (what appears to be) ZERO progress. A reasonable solution that gets implemented is usually better than a perfect solution that’s only talked about.

So, in keeping backwards compatibility, but also trying to think forward AND keeping it simple… I’m not thrilled with the idea of “manualMethod” as it seems like it’s a slipperly slope. Add that, and then the logical next step is going to be adding “keypadMethod”, “autoMethod”, and so on…

What about a generically named submethod? “method” (as you suggested) with “manual”, “keypad”, “auto”, and “submethod” that’s defined based on the method. (manual: key, knob. auto: timer, alarm. … etc…)

So, some typical “data” maps a smartApp might see:

[ method: “manual” ]
[ method: “manual”, submethod: “key”]
[ method: “wireless” ] // zwave door_lock_op command to lock?
[ method: “keypad”, usedCode: 0 ]
[ method: “keypad”, usedCode: 3, submethod: “user” ]
[ method: “auto” ]
[ method: “auto”, submethod: “timer” ]

I think something like this, with only 3 possible indexes (method, submethod, usedCode) gives quite a bit of flexibility, retains compatibility with existing smartApps, and allows growth. (It’d also be somewhat easy to get into the existing device type.)


@duncan , @Tyler , @Ben, etc?

I have a smartapp I’d love to submit to smartthings for door lock/unlock triggers, but one of the primary features is the ability to trigger differently based on mechanism used to lock/unlock the door. I can support some of that with the existing door lock type template (by guessing, searching descriptionText, etc), but not all of it. Adding the “method” data would allow a much more robust implementation.

Again, I’d be happy to modify the existing z-wave door lock code (to the extent that I can test on my own device or derive from documentation) and submit that as well, but I don’t want to start basing things on something that isn’t ever going to happen…

What I really need from ST here is a “go” or “no go”


(Sorry if this adds noise, but I’m thinking out loud…by typing.)

This relates peripherally to the question of why the capability is Lock Codes and not just User Codes, since they are separate z-wave command classes.

The lock capability, separate from code support, could support basic “method” types in data, e.g. “local” and “remote”, and device types implementing other capabilities could further decorate with their specific information. Or, a separate attribute that is associated with the capability would be updated providing the information by that route.

So, if we have:

Capability Lock
attribute: lock [ “locked”, “unlocked” ]
reports change with data element [ method : [ “local”, “auto”, “remote” ]]

Capability UserCode
adds data element [ userCode: userIdentifier ]
(or doesn’t, if it was manual or auto operation)

It feels a little kludgy to put “auto” in with the basic lock capability, when it could be a variation of “local” (as a keypad-entered code would be), but a separate auto capability is too vague.

A SmartApp would then know what values it could expect to find in the change event data based on the advertised capabilities of the device type. I suppose, however, that the same would be true even if multiple capabilities shared data values (like “method”). In both cases, it would a matter of defining what the possible values would be.

I think the basic intent is for the attributes related to each capability to be updated independently, which would accomplish the same thing in a synchronous environment, but because the mechanism for updating the attributes is sending events from the handler, and those events are then passed to the SmartApps, coherence becomes a challenge. (e.g. updating the lock attribute and a codeUsed attribute) So, event data seems to be the way to go.

@llamas, I agree that the entire capability system should probably be re-thought and better structured.

However, that’s not happening in the short term. In the short term, I’m TRYING (unsuccessfully, apparently) to get the ST folks to focus on one thing so I can keep working on it. The “data” map was already being added to the event map in the case of some instances of “lock.locked” (and lock.unlocked), but not all.

Is there a better way? perhaps. Is there a better short-term solution? I haven’t seen one, and rather than get bogged down in long threads discussing as many variations as possible (and there are probably at least 5 possible variations for each interested developer), I grabbed the existing “usedCode” being added to “data” and started with that. Then modified to use “method” attached to data based on @duncan’s suggestion (and a submethod as well!)

I’d LIKE to get this done before the v3 hub (2016? 2017?), understanding that this (and probably everything else) can change between now and then.

I’ve overhauled the base Z-wave lock to support my Yale lock’s features configuration, scheduling, etc., so I know exactly what you mean. I’m resigned, in the short term, to creating a device type that will work only with my smartapp, at least when it comes to added functionality. That’s upside to adding data elements versus changing or removing them; stuff looking for the existing interface will still work.

I think the data hash is the way to go, and I personally don’t have a strong preference in the area of naming. It might be good to provide separate elements per capability, at least for variables that will be expected to have specific values, so that consuming smartapps can word with expected values. That way, (for example) if a smartapp is wants to key off of whether a Lock device was locked locally or remotely, it doesn’t have to know about the additional, more specific sources for the locking action that Lock Code devices support.I think the fact that there are both Lock and Lock Codes capabilities, instead of Lock and User Codes, blurs the lines a little. Of course, you can implement things just as you’ve described, and that can be the Lock Codes data structure; and if someone wants similar Lock structure, it can use a different key.

I wouldn’t wait for them, though. They’ve got so much staffing/catching-up to do that if it’s not on fire and dancing in front of them, it’s not going to get serious attention. That may mean putting off a merge into the default type, but at least it won’t block you.

Oh, my smartapp is already done. I’ve been using it for a couple of days. I’ve also already added the code needed to the generic z-wave lock device type (or, at least to one that’s modified for schlage locks.)

However, I want the app to work with all the locks, not just when people manually install a specific lock device type that’s really only tested for one single lock.

To me, ST is a mainstream failure if a person has to jump through hoops to install custom device types in a code-based IDE for anything to work well. The idea, I’d hope, is that a non-technical person could use this stuff…


I’m with you on those points. Don’t be confused by my thinking out loud. :grinning:

If they don’t have some sort of standard in the works (which is what you were asking them), and we build up a de facto standard, they’ll likely make it official once they have the bandwidth.

My thoughts on the subject center around defining the data elements so the same logic can be applied on any device type we’re working on.

[ Edited ] I just found the isPhysical method on the Event class which provides the local/remote information I desire.

I should add that I’ve been using “userIdentifier” instead of “codeUsed” because the value references the user number (versus the code), and the same name is used in the command classes.

@Tyler? @Ben? @duncan? Bueller? Bueller? Bueller?


@Tyler? @Ben? @duncan? @April?

Sorry, but this isn’t a high priority for us right now. As you mention, it wouldn’t take any time to code, but all changes to the Z-Wave Lock device handler have to be tested against all the models. I’ll try to make sure this at least is part of any upcoming changes to the handler.

@duncan, thanks for responding. More important than a “finished” result here was knowing the direction that it’s going. That allows me to code smartApps to deal with what’s coming, AND to provide temp device types that, while not official, will have the same/similar changes.

So, is the (tentative) plan to go forward as I suggested in message 4 of this thread?


Yes probably I’ll add just method with values "manual", "keypad", "auto", "command". The userCode param will be continue to be absent when a code wasn’t used. Not sure if method will always be present, e.g. in cases of jammed locks the event may not have enough information.


thank you. :smile:

J/w whatever came of this? I’m trying to create a simple piston to turn on a light when door is unlocked via keypad only.

I thought this would do it, but it appears when user #1 is included, manual unlocking (even from inside/thumb turn) also triggers the action. What am I doing wrong?