Schlage BE469 - Zwave binding with security - missing features

So it seems to be as I thought - the lock doesn’t generate any report in this instance -:

Here we see your command at the top to unlock the door. We then see the DOOR_LOCK_SET, and then at the bottom there’s the DOOR_LOCK_REPORT which reports that the lock is unlocked (it reports the state of the handles). This report is used to update the state of the door to unlocked.

I suppose thats a downfall of the lock not reporting when remote operations happen. too bad. Thanks for looking into it.

[Sorry… I typed this out and got distracted with some new bits that arrived for my telescope and never hit send. Looks like Chris got you what you need!]

OK, I misunderstood! There are no codes that come in on the alarm_number channel when the lock_door channel is toggled.

Sorry to bring this back to my selfish agenda, but would this use of the String type mean we could get info about which user code locked the door using the keypad, and also when the alarm is triggered?

If so - I’m certainly on board with this idea!
To know which user code unlocked the door, could this not be a Number channel?
As for when the alarm is triggered, could this be one of the new fangled Trigger channels? I have been playing with these in my own binding dev and they are pretty easy to use. Now I know the BE465 at least has different types of alarm, but since only one can be enabled at a time I think a single ‘Alarm’ Trigger channel would be fine.

@chris How would a string channel, or would a String channel, enable us to add/remove/edit the user codes in the lock? Or is there a plan do do this in another way?

Edit: After thinking about this a bit more, using a Trigger for the Alarm channel may not be the best idea since having a state does make sense, ‘Alarm’/‘OK’ so a switch channel is probably best for this.

To get round this limitation I created this rule:

rule "Door Lock 1"
when
	Item myDoorLock_Proxy received command
then
	myDoorLock_Lock.sendCommand(receivedCommand)
	val notificationNumber = if (receivedCommand == ON) 3 else 4
	myDoorLock_AccessControlNotification.postUpdate(notificationNumber)
	
end

As you can see I use a proxy item to represent the physical state of the lock. I then set the myDoorLock_AccessControlNotification item to 3 or 4 if the lock is locked via this proxy so that I have one Item, myDoorLock_AccessControlNotification that always represents the most recent action. (I consider 3 to be ‘Locked Remotely’ and 4 to be ‘Unlocked Remotely’).
I then have another rule that watches the state of this myDoorLock_AccessControlNotification Item and if the door is locked or unlocked manually or via the keypad (all of which can be detected by a change to this Item), then I update the state of the Lock proxy Item.
A bit messy but it all works.

This is similar to the approach linked above by @5iver so thanks to him for his help in the main mega-thread.

Yes, the problem is if the data is distributed across different channels, then somehow you need to (reliably!!) combine this information back into a single event. It’s unclear to me how this can be done reliably. Maybe the system ensures that all events retain their order and you can assume that when a code arrives, it’s linked to the last state, and not the next state. With multi-threading though, it’s unclear to me that this order will be retained - if it’s not reliable, then to me it’s pointless.

To me, data associated with a single event needs to be clearly linked together somehow. If they are in different channels, that’s fine but there should be some sort of “event ID” to show allow correlation. Alternatively, my thought was to have the primary channel information (eg lock state - OPEN/CLOSED, On/Off…), and then have attributes linked to the channel (eg user=1, time=2…). Unfortunately neither is possible.

I think setting of user codes is a different question - it can be added relatively easily I think. The only issue I see is exactly how to format the channel - we could have a separate channel per code, but that might be messy with locks with lots of codes, or, we could have a single channel and embed the channel number into the value.

Probably a single channel per code is best, but we can’t have 250 channels being added as I think that will cause other problems.

This is super awesome! Thank you so much. I’m going to put it all together below to help any future users out to get past this limitation as it works really well:

Items:

Switch	 	vGarageLock					"Garage Lock  [MAP(lock.map):%s]"   <lock>			(gLocks_Garage)		{channel="zwave:device:159a54632e2:node24:lock_door"}
Switch		vGarageLock_Proxy			"Garage Lock Proxy  [MAP(lock.map):%s]"
Number		vGarageLock_Alarm			"Garage Lock Alarm [MAP(lock_alarm.map):%s]"			<lock>			(gLock_Status)		{channel="zwave:device:159a54632e2:node24:alarm_number"}

Transform: lock_alarm.map:

1=Locked manually
2=Unlocked manually
3=Locked Remotely
4=Unlocked Remotely
5=Locked with keypad
6=Unlocked with keypad
9=Auto lock
11=Jammed

Rules:

rule "vGarageLock Proxy Status Updates"
when
	Item vGarageLock_Proxy received command
then
	logInfo("RULE.LOCK.Garage", "### vGarageLock Proxy Status Updates ###")

{
	vGarageLock.sendCommand(receivedCommand)
	val notificationNumber = if (receivedCommand == ON) 3 else 4
	vGarageLock_Alarm.postUpdate(notificationNumber)
	pushover("Garage Door: "+ vGarageLock_Proxy.state +".")
}	
end


rule "Lock: Update lock states after alarm events (vGarageLock)"
when
	Item vGarageLock_Alarm received update
then
	logInfo("RULE.LOCK.Garage", "### Lock: Update lock states after alarm events (vGarageLock) ###")
{
    if (vGarageLock_Alarm.state == 1 || vGarageLock_Alarm.state == 5 || vGarageLock_Alarm.state == 3) {
		vGarageLock_Proxy.postUpdate(ON)
        logInfo("RULE.LOCK.Garage", "--> Lock: Alarm events: vGarageLock updated to ON (locked)")
    }
    else if (vGarageLock_Alarm.state == 2 || vGarageLock_Alarm.state == 6 || vGarageLock_Alarm.state == 4) {
        vGarageLock_Proxy.postUpdate(OFF)
		logInfo("RULE.LOCK.Garage", "--> Lock: Alarm events: vGarageLock updated to OFF (unlocked)")
	}
    else if (vGarageLock_Alarm.state == 11) {
        pushover("vGarageLock is jammed")
    }
}
end

Sitemap:

Text label="Lock Control" icon="lock" {
				Frame label="Garage Main Door" {
					Switch item=vGarageLock_Proxy label="Lock Proxy Control"  mappings=[ON=Lock, OFF=Unlock]
					Text item=vGarageLock_Alarm
				}	
			}

The sitemap will look like this, and thanks to the transformation map it will tell you how it was locked/unlocked:

2 Likes

I understand your concern and agree that leaving it to chance is not a good strategy. I have recently been experimenting with triggers in binding development and wondered if they could help solve this problem.
For example, using the case of knowing the user code that unlocked the door -
There could be a number channel that displays the id of the user that last unlocked the door with the keypad. There could also be a trigger channel that fires an event whenever the state of the lock changes. So when the user unlocks the door with the keypad, the number channel is first updated and then a ‘UNLOCKED_REMOTELY’ event could be sent to the trigger channel. If the trigger event is used in the when clause of a rule, the user code channel could then be checked and hopefully safely be assumed to have been updated to the correct user code.

Now, I realise this may not actually solve the uncertainty of the order in which the events fire but it would give some clarity to the user as to what is supposed to happen. i.e. Use trigger channels in the when clause of rules and then check the ‘status’ channel(s) for any associated data.
Is it possible to find out from the core devs if the order of events forwarded to channels is guaranteed per individual Thing?

Sorry to bug you on this one - I like this idea and I think I saw some mention of this in the megathread but I am not sure if any plan was agreed on for it’s implementation.
I for one would be happy with a nominal limit on the number of user code channels, 10 seems like more than enough although others may disagree.
Could we start with 10 or even 5 just to get the functionality going and then allow people to argue for an increase?

@Python This stuff looks very cool. I have a Schlage BE469 that thanks to Chris’ 0808 SNAPSHOT binding, I’ve been able to include it in my massive 2 node Z-wave network. LOL. That’s after I figured out I had to click on the magnifying glass in HABmin and not the plus sign. I had my Z-stick held next to the lock, and did the discovery using my iPad and I just couldn’t get the system to find the lock after I told it to turn on it’s Z-wave radio. It’s now included and I have Z-wave DEBUG turned on so the logs show the activity.

So thank you for sharing your solution. The question I have is, exactly what do I with the various parts to get them into my OH2 system. So far, I haven’t found any text files for most things that I’ve defined using either the Paper UI or HABmin.

For example. Do I create a lock_alarm.map file with those entries and put it … where? Same for the other files. Not sure how to name the files or where they would go.

I thought I read someplace that while OH1 relied a lot on text files, OH2 doesn’t use or doesn’t like them.

Also, I’m not sure about 11=Jammed. I’ve seen 1-6 in the logs doing some tests, but I got an 11 when I entered a bogus code. The deadbolt’s working perfectly and has never jammed. So maybe it’s got two meanings.

One of the main reasons I decided to try openHAB is that I want to be able to keep a log/record of what user codes are used and when. But it looks like we don’t have that functionality yet for the Schlage BE469 Touchscreen Deadbolt. It seems like a great lock and communication with an HA systems was why I bought it. I just don’t want to rely on a cloud-based solution or crazy stuff like will.i.am, an American musician buying Wink and then doing who knows what with it.

Thanks,
Mark

I’ve been stumbling around and finding where some things are and hopefully where they go.

@Python I see the lock_alarm.map but not your lock.map which you reference in your Items. Would you please post how that’s defined?

Thanks,
Mark

I have a similar setup and my lock.map file looks like this:

ON=Closed
OFF=Open

This will transform the ‘switch’ ON/OFF to the Open/Closed that is supposed to drive the dynamic padlock icon. I say supposed because for some reason on my setup it is not working - the transform is happening but the icon is not reacting, but that is likely an issue with my system, hopefully you will have more luck.

User code monitoring should now be available. I’ll be testing tonight.

1 Like

If you’d like to see an example of using alarm_raw, check out this post…
https://community.openhab.org/t/zwave-yale-yrd220-lock/34180/5

2 Likes

Great stuff - thanks for updating this thread with new developments!
I finally got round to switching my code over to the new alarm_raw channel and it is working great including being able to figure out which user code was used to unlock the door.

@5iver Do you know if it is possible to detect a failed user code? There is some chatter about this on the smartthings forum here: https://community.smartthings.com/t/z-wave-lock-with-failed-attempt-alarm/16376/7
I would also like to be able to detect if the alert ‘alarm’ is tripped (I currently have all my locks set to Alarm Mode: Alert), but I am not getting any change to the alarm_raw value when the alert is triggered.

Is this a case of adding more properties to the alarm_raw message?

…maybe I should ask @chris :slight_smile:

Edit:
Was re-reading some old posts and spotted this debug entry from @5iver
NODE 183: Updating channel state zwave:device:07cb40a2:node183:alarm_raw to {"notification":"BURGLAR__TAMPER_UNKNOWN","type":"BURGLAR","event":"2","status":"255"} [StringType]

Maybe the ‘Alert’ setting never triggers an event but ‘Forced Entry’ and ‘Tamper’ settings do?

Based on the info on SmartThings, type=6, event = 16, this would give a notification ACCESS_CONTROL__KEYPAD_TEMPORARILY_DISABLED.

In my notes, I have a V1 code of 161 for failed user code attempt (maybe for a different lock) and code 16 for wrong code entered too many times. I do not see alarms after a single bad user code entry, but after 4 the siren on the lock turns on and the lock sends:

{"notification":"ACCESS_CONTROL__KEYPAD_TEMPORARILY_DISABLED","type":"ACCESS_CONTROL","event":"16","status":"255"}

Hello do you mind sharing how you worked that out or the code for it and also how you setup for the lock to report its status when opened and closed from the key pad.

Disclaimer: most of the clever stuff here is borrowed heavily from @5iver - his rule can be viewed here:

Here is my rule. I too use a lambda since I have multiple locks of the same type:

val Functions$Function3<String, String, SwitchItem, Void> ProcessAlarmRaw = [lockName, alarmRawMessage, remoteLockItem |
	logDebug("Rules-DoorLocks", "Lock: {} updated AlarmRawMessage to: {}", lockName, alarmRawMessage)
	
	val HashMap<Integer, String> userCodeNames = newHashMap(
		1 -> "User1",
		2 -> "User2")
	
	val String typeString = transform("JSONPATH", "$.type", alarmRawMessage)
	switch (typeString) {
		case "BURGLAR" : {
			logDebug("Rules-DoorLocks", "{} sent 'BURGLAR' message: {}", lockName, alarmRawMessage)
			// TODO Sound siren
			// TODO Trigger Elk
			gDoorLocks.sendCommand(ON) // Lock all doors
			val message = "Intruder alert triggered by " + lockName;
			sendBroadcastNotification(message)
			return null
		}
		case "ACCESS_CONTROL" : {
			logDebug("Rules-DoorLocks", "{} sent ACCESS_CONTROL message: {}", lockName, alarmRawMessage)
		}
		default : {
			logDebug("Rules-DoorLocks", "Unknown event with unknown 'type' detected from: {}", lockName)
			return null
		}
	}
	
	val String eventString = transform("JSONPATH", "$.event", alarmRawMessage)
	val Integer eventNumber = Integer::parseInt(eventString)
	
	var String state = UNDEF.toString
	var String userCodeName = null
	switch (eventNumber) {
		case 1,
	//	case 3,
		case 5,
		case 9 : {
			state = ON.toString
		}
		case 2,
	//	case 4,
		case 6 : {
			state = OFF.toString
			if (eventNumber == 6) {
				val String userCodeString = transform("JSONPATH", "$.code", alarmRawMessage)
				val Integer userCodeNumber = Integer::parseInt(userCodeString)
				userCodeName = userCodeNames.getOrDefault(userCodeNumber, "Unknown")
				val String debugMessage = lockName + " granted access to user: " + userCodeName + " with user code index: " + userCodeNumber
				logDebug("Rules-DoorLocks", debugMessage)
				if (userCodeName == "Unknown") {
					sendBroadcastNotification(debugMessage)
				}
			}
		}
		case 11,
		case 16 : {
			val String eventDescription = if (eventNumber == 11) "jammed" else "keypad disabled due to too many failed user code attempts"
			state = UNDEF.toString
			logDebug("Rules-DoorLocks", "{} {}" , lockName, eventDescription)
			sendBroadcastNotification(lockName + " " + eventDescription)
		}
	}
	logDebug("Rules-DoorLocks", "Updating remoteLockItem: {} to {}", remoteLockItem.name, state)	
	remoteLockItem.postUpdate(state)
	
	return null
]


rule "Door Lock - Commanded"
when
	Item Lock1__RemoteLock received command
then
	val notificationNumber = if (receivedCommand == ON) 3 else 4
	Lock1__AccessControlNotification.postUpdate(notificationNumber)	
end

rule "Door Lock - State Changed"
when
	Item Lock1__AlarmRaw received update
then
	ProcessAlarmRaw.apply(
		"Lock1",
		Lock1__AlarmRaw.state.toString,
		Lock1__RemoteLock)
end

Note that you will need an instance of ‘Door Lock - Commanded’ and an instance of ‘Door Lock - State Changed’ for each of your locks.

1 Like

@mcqwerty, I see a risk in your logic. When the TYPE is BURGLAR, there is also an EVENT of 6 and no CODE in the JSON. In that case, your lambda will fail silently when trying to read the CODE (no exceptions thrown from a lambda unless using try/catch), Fortunately, it looks like this will happen BEFORE you unlock the door for the burglar! There was some more discussion of this in the main thread when I realized this was occurring in my own rule before I had implemented alarm_raw. The simple story… keypad unlock and burglar both send EVENT 6, hence the need for alarm_raw and not just notification_access_control or alarm_number (they should now show as deprecated in the database).

Also, I have been periodically updating the lambda I’d posted in the other thread you linked to. The last update includes my handling for when a lock is unjammed, which I do not see in yours.