Zwave - Yale YRD220 Lock

This was fixed previously, but somehow crept back in. I’ve now added a test to catch it if it changes again!

I’ve been experimenting and trying to get the above Rule to work with my Kwikset lock. I’m not certain if its differences in the lock or perhaps me just not fully understanding the rule.

First my alarm raw only shows a Type and Value, and does not show an “ACCESS_CONTROL” Again, perhaps I’m making it more complicated then it should be. For my lock a Type 19, Value 1 would meant I entered Code 1 on the keypad, and I’m trying to send an notification to my phone when it unlocks.

Currently I’m getting this error in my logs when attempting

16:48:03.674 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Lock: Update lock states after alarm_raw event (Lock_EntranceFront)': Could not invoke method: org.eclipse.smarthome.core.items.GenericItem.getState() on instance: {"type":"21","value":"1"}
2017-11-09 16:48:29.199 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Lock: Update lock states after alarm_raw event (Lock_EntranceFront)': Could not invoke method: org.eclipse.smarthome.core.items.GenericItem.getState() on instance: {"type":"19","value":"1"}
2017-11-09 16:48:36.139 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Lock: Update lock states after alarm_raw event (Lock_EntranceFront)': Could not invoke method: org.eclipse.smarthome.core.items.GenericItem.getState() on instance: {"type":"21","value":"1"}

I did try to modify the rule eliminating ACCESS Control, and changing $.event to $.type where I thought was correct as following, but still get the same error message in the logs.

Which version of OH are you running and what model of Kwikset lock?

I’m on Snapshop/Build 1073 and have the KwikSet 916 Deadbolt. However the OH2 binding see’s it has the 914TRL, although I don’t think that makes a difference as I can control everything. here’s a screenshot of the lock info.

FYI, Type 21, Value 1 is locking the door from the inside on this lock.

I’ve further stripped the rule down to this, but still keep getting the same error. I wonder if its the rule, the import at the top or something else?

import org.eclipse.xtext.xbase.lib.Functions

val Functions$Function2<GenericItem, GenericItem, Boolean> alarmRawParser = [
    lockAlarmRaw,
    lockItem |
    
    logDebug("Rules", "Lock: Alarm events: {}=[{}]",lockItem.getName,lockAlarmRaw.state.toString)
            switch (transform("JSONPATH", "$.type", lockAlarmRaw.state.toString)) {
                case "21" : {
                    lockItem.postUpdate(ON)
                    logDebug("Rules", "Lock: Alarm events: {} updated to ON (locked)",lockItem.getName)
                    sendNotification("xxxxxx@gmail.com", "Front Door Unlocked.")
                }
                case "22" : {
                    lockItem.postUpdate(OFF)
                    logDebug("Rules", "Lock: Alarm events: {} updated to OFF (unlocked)",lockItem.getName)
                    sendNotification("xxxxx@gmail.com", "Front Door locked.")
                }
                case "19" : {
                    val StringBuilder presenceMessage = new StringBuilder
                    switch (transform("JSONPATH", "$.value", lockAlarmRaw.state.toString)) {
                        case "1" : {
                            sendNotification("xxxxx@gmail.com", "Front Door Unlocked.")
                        }
                        case "2" : {
                            sendNotification("xxxxxx@gmail.com", "Front Door Unlocked.")
                        }
                    }
                    lockItem.postUpdate(OFF)
                    logDebug("Rules", "Lock: {}",presenceMessage.toString)
                    //SMS_Notification.sendCommand(presenceMessage.toString)
                }
            }
    true
]

rule "Lock: Update lock states after alarm_raw event (Lock_EntranceFront)"
when
	Item Lock_FrontDoor_Alarm_Raw received update
then
    alarmRawParser.apply(Lock_FrontDoor_Alarm_Raw.state.toString,Lock_FrontDoor,"Lock (Front Entrance)")
end

The Schlage BE469 (which is what I have) and the Yale YRD220 do not automatically report the lock position, which is a big reason for these rules/lambda. In the big zwave thread, you mentioned that your lock reports the state of the lock all on it’s own, so you probably just need a rule for acting on user code entries. You could take out the lines with postUpdate in them, and you probably don’t need to act on type 21 or 22. The database entry on Chris’ site has some other codes you might want to act on though. Your lock also only supports Alarm V1, so your alarm messages are a little different (just type and value, based on this commit).

Did you install the JSONPath Transformation service? That import is required in order to use lambdas, and should be placed at the very top of the file. You can also strip out the three lines with presenceMessage in them.

Yes, the JSON Transformation is installed, and I have the import as the first line in the file. I’ve also stripped out the presenceMessage. You may notice I removed the “ACCESS_CONTROL” and Burglar Case stuff, not sure if that apply’s to my lock or not. And just have the JSONPATH looking at $.type and $.value.

And yea, I had thought perhaps my lock was always reporting back the state, but that does appear to be the case. I remember with WINK, their app somehow got the status update, probably also using the raw alarm info.

So currently, I can control the lock, but anything do manually, either with the keypad or manually turning the deadbolt does not update to OH2 yet.

I’ll get there :slight_smile: so much learning to do!

Latest, stripped down version of the rule and still getting same error

import org.eclipse.xtext.xbase.lib.Functions

val Functions$Function2<GenericItem, GenericItem, Boolean> alarmRawParser = [
    lockAlarmRaw,
    lockItem |
    
    logDebug("Rules", "Lock: Alarm events: {}=[{}]",lockItem.getName,lockAlarmRaw.state.toString)
            switch (transform("JSONPATH", "$.type", lockAlarmRaw.state.toString)) {
                case "21" : {
                    //lockItem.postUpdate(ON)
                    logDebug("Rules", "Lock: Alarm events: {} updated to ON (locked)",lockItem.getName)
                    sendNotification("xxxx@gmail.com", "Front Door Unlocked.")
                }
                case "22" : {
                    //lockItem.postUpdate(OFF)
                    logDebug("Rules", "Lock: Alarm events: {} updated to OFF (unlocked)",lockItem.getName)
                    sendNotification("xxxx@gmail.com", "Front Door locked.")
                }
                case "19" : {
                    switch (transform("JSONPATH", "$.value", lockAlarmRaw.state.toString)) {
                        case "1" : {
                            sendNotification("xxx@gmail.com", "Front Door Unlocked.")
                        }
                        case "2" : {
                            sendNotification("xxx@gmail.com", "Front Door Unlocked.")
                        }
                    }
                }
            }
    true
]

rule "Lock: Update lock states after alarm_raw event (Lock_EntranceFront)"
when
	Item Lock_FrontDoor_Alarm_Raw received update
then
    alarmRawParser.apply(Lock_FrontDoor_Alarm_Raw.state.toString,Lock_FrontDoor,"Lock (Front Entrance)")
end

Hi Paul. I don’t have a Z-Wave lock myself, but from an inspection of your rules, which appear to be a pretty straightforward copy of @5iver’s rules from post 5 of this thread, you are supplying a string object as the first argument to the alarmRawParser lambda, but the definition of that lambda declares the first argument as an object of type GenericItem. That, I think, is the cause of the error you reported.

In your rule “Lock: Update lock states after alarm_raw event (Lock_EntranceFront)”, you should change:

alarmRawParser.apply(Lock_FrontDoor_Alarm_Raw.state.toString,Lock_FrontDoor,"Lock (Front Entrance)")

to:

alarmRawParser.apply(Lock_FrontDoor_Alarm_Raw,Lock_FrontDoor,"Lock (Front Entrance)")

With that change I think the error will be gone.

1 Like

Great catch on that, and now its working. I’ve getting a Notifications now on my phone when the door is unlocked and by who, as well when it is locked.

I’ll probably add a separate rule now to send notice if the door is unlocked after a certain PM night time as well.

That’s embarrassing… when I edited the lambda, I forgot to update the rule! I’ve corrected it now. Thank you!

Sorry for the headache @ptmuldoon!

@5iver

Lol… I was slowly making sense of the rule and how it works and was closing in on it was well.

Anyone who takes the time to help others in their free time is a saint in my book. I know we all have real lives and other commitments.

1 Like

@5iver,
Thanks for the great solution for parsing the raw lock JSON. I’m using it with a YRD446 and it works great!

The one thing I would like to work in my case is which user code is used. It doesn’t tell me which code is called. It only reports code:99 for any keypad unlock.

2018-01-18 20:09:33.873 [DEBUG] [ding.zwave.handler.ZWaveThingHandler] - NODE 10: Updating channel state zwave:device:zwavedev:node10:alarm_raw to {"notification":"ACCESS_CONTROL__KEYPAD_UNLOCK","code":"99","type":"ACCESS_CONTROL","event":"6","status":"255"}

From what I have found here, the alarm_raw channel builds the JSON string from the available data from the zwave device. Is there any thing else that can be captured or is this all of it? There isn’t anything else in the zwave log. Does anyone with a Yale lock have experience with this?

See yale alarm document here.

Perhaps we could also add “level” to the string?

I believe that is what is supposed to come through in alarm_raw for the code key. @chris would have a definitive answer though.

You might want to open an issue for the dev binding on this (see what Chris says). It works well for my Schlage BE469 locks.

This is working for me with a Yale YRD220, see my code below. I simplified the user code parsing by using a map file, rather than needing to update the Lambda if I change the code slot assignments. Note that the alarm codes for the 220 don’t match those in the document linked above

import org.eclipse.xtext.xbase.lib.Functions

val Functions$Function3<GenericItem, GenericItem, GenericItem, Boolean> alarmRawParser = [
    lockAlarmRaw,
    lockItem,
    lockUser |
    
    logDebug("Rules", "Lock: Alarm events: {}=[{}]",lockItem.getName,lockAlarmRaw.state.toString)
    	switch (transform("JSONPATH", "$.type", lockAlarmRaw.state.toString)) {
                case "21" : {  
                    lockItem.postUpdate(ON)
                    logInfo("Rules", "Lock: Alarm events: {} updated to ON (locked)",lockItem.getName)
                }
                case "22" : {
                    lockItem.postUpdate(OFF)
                    logInfo("Rules", "Lock: Alarm events: {} updated to OFF (unlocked)",lockItem.getName)
                }
                case "19" : {
                	lockItem.postUpdate(OFF)                    
                	var codevalue = transform("JSONPATH", "$.value", lockAlarmRaw.state.toString)
                	var codename = transform("MAP", "locks.map", codevalue)
                	lockUser.postUpdate(codename)
                }
            }
    true
]

rule "Lock: Update lock states after alarm_raw event (Lock_FrontDoor)"
when
	Item Lock_FrontDoor_AlarmRaw changed
then
    alarmRawParser.apply(Lock_FrontDoor_AlarmRaw,Lock_FrontDoor,Who_Unlocked_Front_Door_Last)
end

rule "Lock: Update lock states after alarm_raw event (Lock_BackDoor)"
when
	Item Lock_Back_Alarm_Raw changed
then
    alarmRawParser.apply(Lock_Back_Alarm_Raw,Lock_BackDoor,Who_Unlocked_Back_Door_Last)
end

The YRD446 does match that document, I had to change all of the values for the switch function to work. An I have to use the $.event instead of $.type. It appears that $.level would correspond to the code slot (01-max
users) which would work well for me. I’m hoping @chris will be able to shed some light.

I like the map idea, I’ll use that in the future once we can get the codes.

Can you post an example of the json string you get. There are different formats depending on the version of the command class.

{"notification":"ACCESS_CONTROL__KEYPAD_UNLOCK","code":"99","type":"ACCESS_CONTROL","event":"6","status":"255"}

No matter which code is used, it always says ,“code”:“99”

@chris,

Here is a bit more of the log during an unlock using the keypad, I think it might give you more information than just the JSON string.

2018-02-08 12:56:06.623 [DEBUG] [WaveSerialHandler$ZWaveReceiveThread] - Receive Message = REDAC
2018-02-08 12:56:09.718 [DEBUG] [nal.protocol.ZWaveTransactionManager] - processReceiveMessage input 0<>128 : Message: class=SendData[19], type=Request[0], dest=0, callback=9, payload=REDAC
2018-02-08 12:56:09.721 [DEBUG] [nal.protocol.ZWaveTransactionManager] - processReceiveMessage past lock Message: class=SendData[19], type=Request[0], dest=0, callback=9, payload=REDAC
2018-02-08 12:56:09.722 [DEBUG] [nal.protocol.ZWaveTransactionManager] - Received msg (0): Message: class=SendData[19], type=Request[0], dest=0, callback=9, payload=REDAC
2018-02-08 12:56:09.724 [DEBUG] [nal.protocol.ZWaveTransactionManager] - lastTransaction TID 12461: [WAIT_REQUEST] requiresResponse=true callback: 9
2018-02-08 12:56:09.725 [DEBUG] [nal.protocol.ZWaveTransactionManager] - Checking outstanding transactions: 1
2018-02-08 12:56:09.725 [DEBUG] [nal.protocol.ZWaveTransactionManager] - Last transaction: TID 12461: [WAIT_REQUEST] requiresResponse=true callback: 9
2018-02-08 12:56:09.726 [DEBUG] [nal.protocol.ZWaveTransactionManager] - Checking TID 12461: (Callback 9)
2018-02-08 12:56:09.726 [DEBUG] [WaveSerialHandler$ZWaveReceiveThread] - Receive Message = REDAC 
2018-02-08 12:56:09.728 [DEBUG] [.serialmessage.ZWaveCommandProcessor] - Callback match!
2018-02-08 12:56:09.730 [DEBUG] [nal.protocol.ZWaveTransactionManager] - Correlated to TID 12461: callback 9
2018-02-08 12:56:09.733 [DEBUG] [ve.internal.protocol.ZWaveController] - Incoming Message: Message: class=SendData[19], type=Request[0], dest=0, callback=9, payload=REDAC
2018-02-08 12:56:09.736 [DEBUG] [l.serialmessage.SendDataMessageClass] - NODE 116: SendData Request. CallBack ID = 9, Status = Transmission complete and ACK received(0)
2018-02-08 12:56:09.737 [DEBUG] [ng.zwave.internal.protocol.ZWaveNode] - NODE 116: resetResendCount initComplete=true isDead=false
2018-02-08 12:56:09.738 [DEBUG] [e.internal.protocol.ZWaveTransaction] - TID 12461: Transaction COMPLETED
2018-02-08 12:56:09.739 [DEBUG] [e.internal.protocol.ZWaveTransaction] - TID 12461: TransactionAdvance ST: DONE
2018-02-08 12:56:09.743 [DEBUG] [e.internal.protocol.ZWaveTransaction] - TID 12461: TransactionAdvance WT: null {}
2018-02-08 12:56:09.745 [DEBUG] [e.internal.protocol.ZWaveTransaction] - TID 12461: TransactionAdvance RX: Message: class=SendData[19], type=Request[0], dest=0, callback=9, payload=REDAC
2018-02-08 12:56:09.749 [DEBUG] [e.internal.protocol.ZWaveTransaction] - TID 12461: TransactionAdvance TO: DONE
2018-02-08 12:56:09.750 [DEBUG] [nal.protocol.ZWaveTransactionManager] - NODE 116: Response processed after 3248ms
2018-02-08 12:56:09.752 [DEBUG] [nal.protocol.ZWaveTransactionManager] - NODE 116: TID 12461: Transaction completed
2018-02-08 12:56:09.753 [DEBUG] [nal.protocol.ZWaveTransactionManager] - NODE 116: notifyTransactionResponse TID:12461 DONE
2018-02-08 12:56:09.757 [DEBUG] [ve.internal.protocol.ZWaveController] - Notifying event listeners: ZWaveTransactionCompletedEvent
2018-02-08 12:56:09.758 [DEBUG] [ding.zwave.handler.ZWaveThingHandler] - NODE 116: Got an event from Z-Wave network: ZWaveTransactionCompletedEvent
2018-02-08 12:56:09.760 [DEBUG] [nal.protocol.ZWaveTransactionManager] - processReceiveMessage input 0<>128 : Message: class=ApplicationCommandHandler[4], type=Request[0], dest=116, callback=0, payload=REDAC
2018-02-08 12:56:09.762 [DEBUG] [nal.protocol.ZWaveTransactionManager] - processReceiveMessage past lock Message: class=ApplicationCommandHandler[4], type=Request[0], dest=116, callback=0, payload=REDAC
2018-02-08 12:56:09.765 [DEBUG] [WaveSerialHandler$ZWaveReceiveThread] - Receive Message = REDAC
2018-02-08 12:56:09.769 [DEBUG] [nal.protocol.ZWaveTransactionManager] - Received msg (0): Message: class=ApplicationCommandHandler[4], type=Request[0], dest=116, callback=0, payload=REDAC
2018-02-08 12:56:09.770 [DEBUG] [nal.protocol.ZWaveTransactionManager] - lastTransaction null
2018-02-08 12:56:09.773 [DEBUG] [nal.protocol.ZWaveTransactionManager] - NODE 116: Application Command Request (ALIVE:DONE)
2018-02-08 12:56:09.774 [DEBUG] [ng.zwave.internal.protocol.ZWaveNode] - NODE 116: resetResendCount initComplete=true isDead=false
2018-02-08 12:56:09.775 [DEBUG] [ng.zwave.internal.protocol.ZWaveNode] - NODE 116: Decapsulating COMMAND_CLASS_SECURITY
2018-02-08 12:56:09.777 [DEBUG] [mmandclass.ZWaveSecurityCommandClass] - NODE 116: SECURITY_RXD REDAC
2018-02-08 12:56:09.778 [DEBUG] [ng.zwave.internal.protocol.ZWaveNode] - NODE 116: Incoming command class COMMAND_CLASS_ALARM, endpoint 0
2018-02-08 12:56:09.779 [DEBUG] [tocol.commandclass.ZWaveCommandClass] - NODE 116: Received COMMAND_CLASS_ALARM V4 NOTIFICATION_REPORT
2018-02-08 12:56:09.780 [DEBUG] [.commandclass.ZWaveAlarmCommandClass] - NODE 116: NOTIFICATION report - 19 = 1, event=6, status=255, plen=4
2018-02-08 12:56:09.781 [DEBUG] [.commandclass.ZWaveAlarmCommandClass] - NODE 116: Alarm Type = ACCESS_CONTROL (19)
2018-02-08 12:56:09.781 [DEBUG] [ve.internal.protocol.ZWaveController] - Notifying event listeners: ZWaveAlarmValueEvent
2018-02-08 12:56:09.782 [DEBUG] [ding.zwave.handler.ZWaveThingHandler] - NODE 116: Got an event from Z-Wave network: ZWaveAlarmValueEvent
2018-02-08 12:56:09.783 [DEBUG] [ding.zwave.handler.ZWaveThingHandler] - NODE 116: Got a value event from Z-Wave network, endpoint = 0, command class = COMMAND_CLASS_ALARM, value = 255
2018-02-08 12:56:09.785 [DEBUG] [ternal.converter.ZWaveAlarmConverter] - Alarm converter processing NOTIFICATION
2018-02-08 12:56:09.786 [DEBUG] [ternal.converter.ZWaveAlarmConverter] - Alarm converter NOTIFICATION event is 6, type OnOffType
2018-02-08 12:56:09.788 [DEBUG] [ternal.converter.ZWaveAlarmConverter] - Alarm converter NOTIFICATION event is 6, channel alarm_access is not implemented.
2018-02-08 12:56:09.790 [DEBUG] [ternal.converter.ZWaveAlarmConverter] - Alarm converter processing NOTIFICATION
2018-02-08 12:56:09.790 [DEBUG] [nal.protocol.ZWaveTransactionManager] - processReceiveMessage input 0<>128 : Message: class=ApplicationCommandHandler[4], type=Request[0], dest=116, callback=0, payload=REDAC
2018-02-08 12:56:09.791 [DEBUG] [ternal.converter.ZWaveAlarmConverter] - Alarm converter NOTIFICATION event is 6, type OnOffType
2018-02-08 12:56:09.792 [DEBUG] [ternal.converter.ZWaveAlarmConverter] - Alarm converter processing NOTIFICATION
2018-02-08 12:56:09.793 [DEBUG] [ternal.converter.ZWaveAlarmConverter] - Alarm converter NOTIFICATION event is 6, type StringType
2018-02-08 12:56:09.794 [DEBUG] [nal.protocol.ZWaveTransactionManager] - processReceiveMessage past lock Message: class=ApplicationCommandHandler[4], type=Request[0], dest=116, callback=0, payload=REDAC
2018-02-08 12:56:09.796 [DEBUG] [ding.zwave.handler.ZWaveThingHandler] - NODE 116: Updating channel state zwave:device:de0bde91:node116:alarm_raw to {"notification":"ACCESS_CONTROL__KEYPAD_UNLOCK","code":"99","type":"ACCESS_CONTROL","event":"6","status":"255"} [StringType]
2018-02-08 12:56:09.800 [DEBUG] [ternal.converter.ZWaveAlarmConverter] - Alarm converter processing NOTIFICATION
2018-02-08 12:56:09.806 [DEBUG] [ternal.converter.ZWaveAlarmConverter] - Alarm converter NOTIFICATION event is 6, type OnOffType
2018-02-08 12:56:09.807 [DEBUG] [ternal.converter.ZWaveAlarmConverter] - Alarm converter NOTIFICATION event is 6, channel alarm_general is not implemented.
2018-02-08 12:56:09.808 [DEBUG] [nal.protocol.ZWaveTransactionManager] - NODE 116: Commands processed 1.
2018-02-08 12:56:09.809 [DEBUG] [nal.protocol.ZWaveTransactionManager] - NODE 116: Checking command org.openhab.binding.zwave.internal.protocol.ZWaveCommandClassPayload@e5905b.
2018-02-08 12:56:09.810 [DEBUG] [nal.protocol.ZWaveTransactionManager] - Transaction completed - outstandingTransactions 0
2018-02-08 12:56:09.811 [DEBUG] [nal.protocol.ZWaveTransactionManager] - Transaction completed - outstandingTransactions 0
2018-02-08 12:56:09.812 [DEBUG] [nal.protocol.ZWaveTransactionManager] - Received msg (0): Message: class=ApplicationCommandHandler[4], type=Request[0], dest=116, callback=0, payload=REDAC
2018-02-08 12:56:09.813 [DEBUG] [nal.protocol.ZWaveTransactionManager] - lastTransaction null
2018-02-08 12:56:09.814 [DEBUG] [nal.protocol.ZWaveTransactionManager] - NODE 116: Application Command Request (ALIVE:DONE)
2018-02-08 12:56:09.815 [DEBUG] [ng.zwave.internal.protocol.ZWaveNode] - NODE 116: resetResendCount initComplete=true isDead=false
2018-02-08 12:56:09.816 [DEBUG] [ng.zwave.internal.protocol.ZWaveNode] - NODE 116: Decapsulating COMMAND_CLASS_SECURITY
2018-02-08 12:56:09.817 [DEBUG] [mmandclass.ZWaveSecurityCommandClass] - NODE 116: SECURITY_ERR No valid NONCE! null
2018-02-08 12:56:09.818 [DEBUG] [nal.protocol.ZWaveTransactionManager] - ZWaveReceiveThread queue empty
2018-02-08 12:56:09.819 [DEBUG] [nal.protocol.ZWaveTransactionManager] - Transaction SendNextMessage 0 out at start

Just looking at the code here

+            case "alarm_raw":
 +                Map<String, Object> object = new HashMap<String, Object>();
 +                object.put("type", eventAlarm.getAlarmType());
 +                object.put("event", eventAlarm.getAlarmEvent());
 +                object.put("status", eventAlarm.getAlarmStatus());
 +                return new StringType(propertiesToJson(object));

Do you think it would be as easy as adding a line like:

object.put("level", eventAlarm.getAlarmLevel());

I’m fixated on the level because of the column in the Yale support document, see snippet here:

Can you email/PM me the line above from your log please…