Getting an event from a lock for ONLY when the lock is unlocked by a code

@bravenel is this possibly something you can help shed some light on?

My Event Engine can do this. You can select a certain code or all codes. Feel free to take a look at the code and use what you want.

In this example, the light will turn on if a selected user inputs their code. Light turns back off when door is locked.

2 Likes

not to knock event engine.. great app, i am using it.. but rule machine rule also works.. I have the following rule and dont get the alert when manually unlocked. At least for kwikset locks

Why don't you simply subscribe separately to the lock being unlocked? Then sort out in your code what to do.

That's the difficulty. I can not figure out how to determine if that unlock event was a code or the turning of the knob. If it was a turning of the knob I still have "lastCodeName" in there which is accurate to the point that WAS the last code that unlocked the door...but not necessarily who or what just unlocked it.

I think this may help. This originally was posted by @rvrolyk and I used it and updated it for my Schlage Lock and this combo works perfect.

https://community.hubitat.com/t/description-text-logging-actionable/17967/4?u=chipworkz

My updated code for my Schlage lock is below. I added the (evt.type == 'digital' && (evt.descriptionText.endsWith('unlocked [digital]') comments to track the difference between a manual and digital unlock event. I then use this Virtual Switch in my If logic in my rule. You will need to see how your Yale lock reports the "Digital" event to see if it is the same as the Schlage or not. I am not a developer, I was just able to tweak this to make it work for me.

/*
Installation Notes:
You must create a Virtual Switch for both the Virtual Lock and Virtual Unlock switches
even if you are not going to use one or the other. The app will not function correctly
if one of the switches are not created.

Schlage Lock Events
Lock name = Front Door Lock. (Varies per installation)

Locked using keypad Schlage button or code.
Lock event: lock : Front Door Lock was locked by keypad [physical]

Locked using inside dial.
Lock event: lock : Front Door Lock was locked by thumb turn [physical]

Locked using automation.
Lock event: lock : Front Door Lock was locked [digital]

Unlocked using code.
Unlock event: lock : Front Door Lock was unlocked by John

Unlocked using inside dial.
Unlock event: lock : Front Door Lock was unlocked by thumb turn [physical]

Unlocked using automation.
Unlock event: lock : Front Door Lock was unlocked [digital]
*/

definition(
name: "Manual Lock Events Monitor",
namespace: "chipworkz",
author: "chipworkz",
original author: "Russ Vrolyk",
description: "Tracks when a lock is manually controlled and updates the virtual switches",
category: "Convenience",
iconUrl: "",
iconX2Url: "",
iconX3Url: "")

def lock = [
name: "lock",
type: "capability.lock",
title: "Lock",
description: "Select the lock to monitor.",
required: true,
multiple: false
]

def virtualLockedSwitch = [
name: "virtualLockedSwitch",
type: "capability.switch",
title: "Virtual Lock Switch",
description: "Virtual switch that should be turned on when lock is manually locked if needed.",
required: true,
multiple: false
]

def virtualUnlockedSwitch = [
name: "virtualUnlockedSwitch",
type: "capability.switch",
title: "Virtual Unlock Switch",
description: "Virtual switch that should be turned on when lock is manually unlocked.",
required: true,
multiple: false
]

def enableLogging = [
name: "enableLogging",
type: "bool",
title: "Enable debug Logging?",
defaultValue: false,
required: true
]

preferences {
page(name: "mainPage", title: "Schlage Lock Events Monitor:", install: true, uninstall: true) {
section("") {
input lock
input virtualLockedSwitch
input virtualUnlockedSwitch
label title: "Assign an app name", required: false
}
section ("Advanced Settings") {
input enableLogging
}
}
}

def installed() {
log.info "Installed with settings: ${settings}"
initialize()
}

def updated() {
log.info "Updated with settings: ${settings}"
unsubscribe()
initialize()
}

def initialize() {
log "Lock status: ${lock.displayName} " + lockStatus()
subscribe(lock, "lock.locked", lockHandler)
subscribe(lock, "lock.unlocked", unlockHandler)
}

def lockStatus() {
return lock.currentValue("lock")
}

def lockHandler(evt) {
log("Lock event: ${evt.name} : ${evt.descriptionText}")
if (evt.type == 'physical' && (evt.descriptionText.endsWith('thumb turn [physical]') || evt.descriptionText.endsWith('keypad [physical]')) || (evt.type == 'digital' && (evt.descriptionText.endsWith('locked [digital]')))) {
log "${lock.displayName} was locked manually"
virtualLockedSwitch.on()
if (virtualUnlockedSwitch) {
virtualUnlockedSwitch.off()
}
} else {
log "${lock.displayName} was locked"
}
}

def unlockHandler(evt) {
log("Unlock event: ${evt.name} : ${evt.descriptionText}")
if (evt.type == 'physical' && evt.descriptionText.endsWith('thumb turn [physical]') || (evt.type == 'digital' && (evt.descriptionText.endsWith('unlocked [digital]')))) {
log "${lock.displayName} was unlocked manually"
virtualLockedSwitch.off()
if (virtualUnlockedSwitch) {
virtualUnlockedSwitch.on()
}
} else {
log "${lock.displayName} was unlocked"
}
}

def log(msg) {
if (enableLogging) {
log.debug msg
}
}

Ahhhh, you've got me much closer. Testing with this I'm seeing a "physical" unlock with a PIN and a "digital" unlock when it's manual. Does that jive with how yours is?

It seems that I can make this work. Is this different for different locks?

This seems to work for me:
image

That debug statement only get triggered if it's unlocked WITH a code. Seems weird that's called "physical" but....

I added my Schlage events to my code for reference. This is how mine reports the events. This is the only lock I have so I cannot say what Yale or other locks do.

1 Like

Thanks, this helped me get there!

HOWEVER... I will make note... even in your code:

subscribe(lock, "lock.unlocked", unlockHandler)

My handler is getting ALL events regardless of what I'm putting for the subscription. So in the example above.. I'm still seeing the lock events also. Something is amiss.

Yes my code is for both lock and unlock events. The virtual switch gets triggered and I am only using the unlock switch in my rule. I don't do anything with the locked virtual switch.

Lock Monitor2

update..spent some time tonight figuring this out...and finally got it.

I got the proper "unlocked" events now from the subscription. Not sure what I missed the first time but I AM only getting unlocked events now with this:

subscribe(lock, "lock.unlocked", lockHandler)

Second, I do NOT get an evt.type I'm guessing this is a driver thing...so that part needed to be removed. My if statement looks like this:

if (evt.descriptionText.endsWith('thumbturn [physical]') || evt.descriptionText.endsWith('command [digital]')) {
    infolog "$lock.displayName was unlocked manually"
} else {
    infolog "$lock.displayName was unlocked by CODE: $lastName"
    sendPushMessage.deviceNotification("$lock.displayName was unlocked by: $lastName")
}

Notice "thumbturn" in my case did NOT have a space like yours did. But updating this here for others in the future. Is there not a more standard way to handle these events for ALL locks? At least the digital/physical/thumbturn/code entered parts? Understand some locks will have different capabilities... either way...got it finally worked out now and FINALLY have a way to notify when a door gets unlocked ONLY by a code.

1 Like

More info for those that might come across this. @bptworld helped me and ultimately came up with code that hopefully covers all lock drivers...or at least most of them? Really think there needs to be more standardization there @mike.maxwell but...

here is the check that Bryan came up with that seems to be working for multiple lock types:

if (evt.descriptionText.contains("unlocked by")) { //lock was unlocked by code}

How the other built in apps are handling this I don't know...but I do know some of them don't work with HubConnect and this method will.

His event log(kwikset):

Mine(yale):

as you can see mine puts [physical] with a valid code, his does not. His doesn't use "thumbturn" it uses "manual" for someone turning the knob. I'm sure there's some other driver out there that uses "unlocked by manual" or "unlocked by thumbturn" or "unlocked by ..." FWIW you are going to have to test. No wonder why I've been having problems with Rule Machine and Notifications...

1 Like

the whole point of the lastCodeName event was so rules didn't have to parse through the description text.
description text is an optional attribute and its content is not defined.
physical/digital is also an optional attribute, and whilst we strive to make it accurate, it isn't always the case, devices in general do not make the distinction in the events they send to us, so we have to sort this out, usually with state flags ect...

the lastCodeName event should only be generated when a lock is unlocked by a pin code, is that not the case?

If not, let me know which lock drivers are in arrears...

That's the case. "Yale Zigbee Lock"

Subscribe to just the lastCodeName events but my simple routine with a debug log shows this:

This could REALLY explain why I've been having issues with RM and Notifications/etc.

ok, not sure I'm following the issue here.
This log shows in general display text if text logging is enabled in the driver, the actual events committed to the database are shown by clicking the events button in the driver...

Are you saying that unlocked by JR and Kyleigh are not generating lastCodeName events in the device events log?

Sorry let me better explain, first here are the actual events from the lock:

What I showed above was that I was writing an app. I wanted to only act on when an actual code was punched into the lock. No other events.

What am I missing about how to determine when ONLY the code has been entered? As you can see above in this thread I don't look alone in having to parse the description to get the desired result.

Again, I am NOT a developer but I think I figured this out. You need to subscribe to the event lastCodeName and not an event type of physical or digital.

def initialize() {
    log "Lock status: ${lock.displayName} " + lockStatus()
	subscribe(lock, "lastCodeName.Staci", unlockHandler2)
def unlockHandler2(evt) {
	log("Unlock event: ${evt.name} : ${evt.descriptionText}")
	if (evt.name == 'lastCodeName') {
		log "${lock.displayName} was unlocked by a Door Code"
		virtualLockedSwitch.off()
		if (virtualUnlockedSwitch) {
			virtualUnlockedSwitch.on()
		}
	} else {
		log "${lock.displayName} was unlocked"
	}
}

I am...but it's looking like it might be due to the HubConnect Lock driver not supporting that event.

Well this was a fun little learning experience. Sorry it isn't working for you but I will go ahead and post this here for anyone following this thread and wants to use this. I simplified my process and created the app specifically for the purpose of triggering for only when a code is used. I do not see a way with only Rule Machine to do this so it takes this extra app and virtual switch to be used within a rule. I know you could do everything within the app but I like to have the actions within a rule so I can do more with it if I want to.

Schalge Lock Reporter3

/*
Installation Notes:
You must create a Virtual Switch to be used in a rule so when it is on, you will perform an action.
The virtual switch should have the "Enable auto off" set to 5 seconds.

Schlage Lock Events for reference
Lock Name = "Front Door Lock" (Varies per installation)
Virtual Switch Name = "Front Door Code Used"  (Varies per installation)

Locked using keypad Schlage button or code.
Lock event: lock : Front Door Lock was locked by keypad [physical]

Locked using inside dial.
Lock event: lock : Front Door Lock was locked by thumb turn [physical]

Locked using automation.
Lock event: lock : Front Door Lock was locked [digital]

Unlocked using code.
Unlock event: lock : Front Door Lock was unlocked by John

Unlocked using inside dial.
Unlock event: lock : Front Door Lock was unlocked by thumb turn [physical]

Unlocked using automation.
Unlock event: lock : Front Door Lock was unlocked [digital]

Credit to @rvrolyk "Russ Vrolyk" for the original code this is based on.
*/


definition(
    name: "Schlage Lock User Code Reporter",
    namespace: "chipworkz",
    author: "chipworkz",
    description: "Triggers when a user code is used to unlock the door",
    category: "Convenience",
	iconUrl: "",
    iconX2Url: "",
    iconX3Url: "")


def lock = [
    name: "lock",
    type: "capability.lock",
    title: "Lock",
    description: "Select the lock to monitor.",
    required: true,
    multiple: false
]

def virtuaCodeUsedSwitch = [
    name: "virtuaCodeUsedSwitch",
    type: "capability.switch",
    title: "Virtual Code Used Switch",
    description: "Virtual switch that should be turned on when a code is used.",
    required: true,
    multiple: false
]

def enableLogging = [
    name:				"enableLogging",
    type:				"bool",
    title:				"Enable debug Logging?",
    defaultValue:		false,
    required:			true
]

preferences {
	page(name: "mainPage", title: "<b>Schlage Lock User Code Reporter:</b>", install: true, uninstall: true) {
		section("") {
			input lock
			input virtuaCodeUsedSwitch
		}
		section ("<b>Advanced Settings</b>") {
			input enableLogging
		}
	}
}

def installed() {
	log.info "Installed with settings: ${settings}"
	initialize()
}

def updated() {
	log.info "Updated with settings: ${settings}"
	unsubscribe()
	initialize()
}

def initialize() {
    log "Lock status: ${lock.displayName} " + lockStatus()
	subscribe(lock, "lastCodeName", unlockHandler)
}

def lockStatus() {
	return lock.currentValue("lock")
}

def unlockHandler(evt) {
	log("Unlock event: ${evt.descriptionText}")
	if (evt.name == 'lastCodeName') {
		virtuaCodeUsedSwitch.on()
		}
}

def log(msg) {
    if (enableLogging) {
        log.debug msg
    }
}

As a follow up...this does NOT work in RM either.

That rule NEVER gets triggered when entering any valid code on the lock.