Yale real living keyless deadbolt displays incorrect status

does anyone else have this problem with their keyless deadbolt? i have already tried excluding and reincluding device as well as resetting the device to factory defaults. i also have vera as a secondary controller which displays the correct status for the lock.

I had a similar issue with a Yale YRD220-ZW-619 lock. Every time, I would lock it thru smartthings, its status would change from “locked” to “unlocked” in a very short time (about a second) although it was physically locked at the door. The status of the lock was not in sync with the hub. Upon Smartthings support’s recommendations, in order to correct this issue, I tried to exclude the lock and re-insert it into the hub several times without success.

At the end, Smartthings supports referred me to yalerealliving support to update my firmware. After talking with yalerealliving support, they confirmed to me that the real issue was the timeout that is used to interact with the device.

After further testing (many trials and errors), I found out that the issue is within the z-wave lock’s lockandCheck() function.

I created a custom lock device (based on the “lock code change” smartapp developed by a fellow developer, see https://github.com/bigpunk6/device-type.lock) and changed the timeout used by this function from 4200 milliseconds to 2200 and now the lock’s status is correctly reported to the hub. I left the “unlock” timeout unchanged as the problem is only related to the lock event.

This may have to be tested with other types of locks as well. Each lock device may have its own timeout requirements…

You may want to try this with your YALE lock.

3 Likes

Thank you so much for your detailed answer.

If you wouldn’t mind, can you copy paste your code for the custom device here or upload the file to github or dropbox and provide a link so that i may try it?

Thanks

Ok, I can share it, but you may have to tweak it according to your lock’s requirements:

/** 
 * This is a custom version of the Z-Wave Lock Device Type code. This code adds support for user codes with the use of a Smartapp.
 *
 * This Device Type was designed for the Kwikset Deadbolt so might not be compatible with other locks.
 *
 * Installation
 *
 * Create a new device type (https://graph.api.smartthings.com/ide/devices)
 *    Capabilities:
 *        Configuration
 *        Battery
 *        Polling
 *        Lock
 *    Custom Attribute
 *        user1
 *        code1
 *    Custom Command
 *        usercodechange
 */
metadata {
	// Automatically generated. Make future change here.
	definition (name: "Custom Lock Device", author: "yracine@yahoo.com") {
		capability "Lock"
		capability "Polling"
		capability "Configuration"
		capability "Battery"

		attribute "user1", "string"
		attribute "code1", "string"

		command "usercodechange"
	}

	simulator {
		status "locked": "command: 9881, payload: 00 62 03 FF 00 00 FE FE"
		status "unlocked": "command: 9881, payload: 00 62 03 00 00 00 FE FE"

		reply "9881006201FF,delay 4200,9881006202": "command: 9881, payload: 00 62 03 FF 00 00 FE FE"
		reply "988100620100,delay 4200,9881006202": "command: 9881, payload: 00 62 03 00 00 00 FE FE"
	}

	tiles {
		standardTile("toggle", "device.lock", width: 2, height: 2) {
			state "locked", label:'locked', action:"lock.unlock", icon:"st.locks.lock.locked", backgroundColor:"#79b821", nextState:"unlocking"
			state "unlocked", label:'unlocked', action:"lock.lock", icon:"st.locks.lock.unlocked", backgroundColor:"#ffffff", nextState:"locking"
			state "locking", label:'locking', icon:"st.locks.lock.locked", backgroundColor:"#79b821"
			state "unlocking", label:'unlocking', icon:"st.locks.lock.unlocked", backgroundColor:"#ffffff"
		}
		standardTile("lock", "device.lock", inactiveLabel: false, decoration: "flat") {
			state "default", label:'lock', action:"lock.lock", icon:"st.locks.lock.locked", nextState:"locking"
		}
		standardTile("unlock", "device.lock", inactiveLabel: false, decoration: "flat") {
			state "default", label:'unlock', action:"lock.unlock", icon:"st.locks.lock.unlocked", nextState:"unlocking"
		}
		valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") {
            state "battery", label:'${currentValue}% battery', action:"batteryupdate", unit:""
        }
        valueTile("usercode", "device.usercode", inactiveLabel: false, decoration: "flat") {
			state "usercode", label:'${currentValue}', unit:""
		}
		standardTile("refresh", "device.lock", inactiveLabel: false, decoration: "flat") {
			state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
		}
		standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat") {
			state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure"
		}

		main "toggle"
		details(["toggle", "lock", "unlock", "battery", "usercode", "configure", "refresh"])
	}
}

import physicalgraph.zwave.commands.doorlockv1.*

//parse
def parse(String description) {
	def result = null
	if (description.startsWith("Err")) {
	    result = createEvent(descriptionText:description, displayed:true)
	} else {
		def cmd = zwave.parse(description, [ 0x98: 1])
		if (cmd) {
			result = zwaveEvent(cmd)
		}
	}
	log.debug "\"$description\" parsed to ${result.inspect()}"
    log.debug "Parse result $result"
	result
}

def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
	def encapsulatedCommand = cmd.encapsulatedCommand([0x20: 1,0x62: 1, 0x63: 1, 0x70: 1, 0x71: 2, 0x75: 1, 0x80:1, 0x85: 2, 0x4E: 2, 0x4C: 1, 0x8B: 1, 0x5D: 2])
	log.debug "encapsulated: $encapsulatedCommand"
	if (encapsulatedCommand) {
		zwaveEvent(encapsulatedCommand)
	}
}

def zwaveEvent(DoorLockOperationReport cmd) {
	def map = [ name: "lock" ]
	if (cmd.doorLockMode == 0xFF) {
		map.value = "locked"
	} else if (cmd.doorLockMode >= 0x40) {
		map.value = "unknown"
	} else if (cmd.doorLockMode & 1) {
		map.value = "unlocked with timeout"
	} else {
		map.value = "unlocked"
	}
	createEvent(map)
}

def zwaveEvent(physicalgraph.zwave.commands.alarmv2.AlarmReport cmd) {
	def map = null
	if (cmd.zwaveAlarmType == 6) {
		if (1 <= cmd.zwaveAlarmEvent && cmd.zwaveAlarmEvent < 10) {
			map = [ name: "lock", value: (cmd.zwaveAlarmEvent & 1) ? "locked" : "unlocked" ]
		}
		switch(cmd.zwaveAlarmEvent) {
			case 1:
				map.descriptionText = "$device.displayName was manually locked"
				break
			case 2:
				map.descriptionText = "$device.displayName was manually unlocked"
				break
			case 5:
				if (cmd.eventParameter) {
					map.descriptionText = "$device.displayName was locked with code ${cmd.eventParameter.first()}"
				}
				break
			case 6:
				if (cmd.eventParameter) {
					map.descriptionText = "$device.displayName was unlocked with code ${cmd.eventParameter.first()} zwaveAlarmEvent"
				}
				break
			case 9:
				map.descriptionText = "$device.displayName was autolocked"
				break
			case 7:
			case 8:
			case 0xA:
				map = [ name: "lock", value: "unknown", descriptionText: "$device.displayName was not locked fully" ]
				break
			case 0xB:
				map = [ name: "lock", value: "unknown", descriptionText: "$device.displayName is jammed" ]
				break
			case 0xC:
				map = [ descriptionText: "$device.displayName: all user codes deleted", display: true ]
				break
			case 0xD:
				map = [ descriptionText: "$device.displayName: user code deleted", display: true ]
				break
			case 0xE:
				map = [ descriptionText: "$device.displayName: user code added", display: true ]
				break
			default:
				map = map ?: [ descriptionText: "$device.displayName: alarm event $cmd.zwaveAlarmEvent", display: false ]
				break
		}
	} else switch(cmd.alarmType) {
        case 17:
			map = [ name: "lock", value: "unknown" ]
				map.descriptionText = "$device.displayName Secured at Keypad – Bolt Jammed"
			break
        case 18:
			map = [ name: "lock", value: "locked" ]
            if(cmd.alarmLevel) {
				map.descriptionText = "$device.displayName Secured by User ${cmd.alarmLevel} at Keypad"
                map = [ name: "code", value: ${cmd.alarmLevel} ]
            }
			break
		case 19:
			map = [ name: "lock", value: "unlocked" ]
			if(cmd.alarmLevel) {
				map.descriptionText = "$device.displayName Un-Secured by User ${cmd.alarmLevel} at Keypad"
			}
			break
        case 21:
			map = [ name: "lock", value: "locked" ]
				map.descriptionText = "$device.displayName Secured using Keyed cylinder or inside thumb-turn"
			break
        case 22:
			map = [ name: "lock", value: "unlocked" ]
				map.descriptionText = "$device.displayName Un-Secured using Keyed cylinder or inside thumb-turn"
			break
        case 23:
			map = [ name: "lock", value: "unknown" ]
				map.descriptionText = "$device.displayName Secured by Controller – Bolt Jammed"
			break
        case 24:
			map = [ name: "lock", value: "locked" ]
				map.descriptionText = "$device.displayName Secured by Controller"
			break
        case 25:
			map = [ name: "lock", value: "unlocked" ]
				map.descriptionText = "$device.displayName Un-Secured by Controller"
			break
        case 26:
			map = [ name: "lock", value: "unknown" ]
				map.descriptionText = "$device.displayName Lock Auto Secured – Bolt Jammed"
			break
        case 27:
			map = [ name: "lock", value: "locked" ]
				map.descriptionText = "$device.displayName Lock Auto Secured"
			break
        case 32:
			map = [ name: "lock", value: "unknown" ]
				map.descriptionText = "All User Codes deleted from $device.displayName"
			break
        case 33:
			map = [ name: "lock", value: "unknown" ]
				map.descriptionText = "User ${cmd.alarmLevel} deleted from $device.displayName"
			break
       case 112:
			map = [ name: "lock", value: "unknown" ]
			if(cmd.alarmLevel) {
				map.descriptionText = "New User: ${cmd.alarmLevel} added to $device.displayName"
			}
			break
       case 161:
			map = [ name: "lock", value: "unknown" ]
				map.descriptionText = "Failed User Code attempt at Keypad on $device.displayName"
			break
       case 162:
			map = [ name: "lock", value: "unknown" ]
			if(cmd.alarmLevel) {
				map.descriptionText = "Attempted access by user ${cmd.alarmLevel} outside of scheduled on $device.displayName"
			}
			break
        case 167:
			map = [ name: "lock", value: "unknown" ]
				map.descriptionText = "Low battery level on $device.displayName"
			break
       case 168:
			map = [ name: "lock", value: "unknown" ]
				map.descriptionText = "Critical battery level on $device.displayName"
			break
       case 169:
			map = [ name: "lock", value: "unknown" ]
				map.descriptionText = "Battery level too low to operate $device.displayName"
			break
		default:
			map = [ displayed: false, descriptionText: "$device.displayName: $cmd" ]
	}
	createEvent(map)
}

def zwaveEvent(physicalgraph.zwave.commands.associationv2.AssociationReport cmd) {
	def result = []
	state.associationQuery = null
	if (cmd.nodeId.any { it == zwaveHubNodeId }) {
		log.debug "$device.displayName is associated to $zwaveHubNodeId"
		state.assoc = zwaveHubNodeId
	} else {
		result << response(secure(zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:zwaveHubNodeId)))
	}
	result
}

//battery
def batteryupdate() {
    def result = secure(zwave.batteryV1.batteryGet())
    log.debug "battery $result"
    result
}

def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
	def map = [ name: "battery", unit: "%" ]
	if (cmd.batteryLevel == 0xFF) {
		map.value = 1
		map.descriptionText = "$device.displayName has a low battery"
	} else {
		map.value = cmd.batteryLevel
	}
	createEvent(map)
}

//User
def usercodechange(user1, code1, idstatus1) {
    log.debug "Set $code1 for User $user1"
    log.debug "Set User ID Status to $idstatus1"
    secureSequence([
        zwave.userCodeV1.userCodeSet(userIdentifier: user1, userIdStatus: idstatus1, code: code1),
        zwave.userCodeV1.userCodeGet(userIdentifier: user1)
    ], 4200)
}

def zwaveEvent(physicalgraph.zwave.commands.usercodev1.UserCodeReport cmd) {
    log.debug "$cmd"
    def map = [ name: "usercode" ]
    map.value = cmd.code
    createEvent(map)
}

//Configuration
def configupdate() {
    secure(zwave.configurationV1.configurationGet(parameterNumber: 1))
}

def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) {
    log.debug "$cmd"
    def map = [ name: "config", value:  cmd.configurationValue]
    if (cmd.configurationValue) {
        switch(cmd.configurationValue) {
			case "[1]":
				map.descriptionText = "User $cmd.parameterNumber is Type: Owner (Default)"
                log.debug "Owner"
				break
			case "[3]":
				map.descriptionText = "User $cmd.parameterNumber is Type: Guest (Required for Year Day Schedules)"
				break
            case "[4]":
				map.descriptionText = "User $cmd.parameterNumber is Type: Worker (Required for Week Day Schedules)"
				break
            case "[255]":
				map.descriptionText = "User $cmd.parameterNumber not found"
				break
            default:
			    map = [ displayed: false, descriptionText: "$device.displayName: $cmd" ]
            }
    }
    createEvent(map)
}


def zwaveEvent(physicalgraph.zwave.Command cmd) {
    log.warn "Unexpected zwave command $cmd"
    createEvent(displayed: false, descriptionText: "$device.displayName: $cmd")
}

def lockAndCheck(doorLockMode, delay=2200) {
    secureSequence([
        zwave.doorLockV1.doorLockOperationSet(doorLockMode: doorLockMode),
        zwave.doorLockV1.doorLockOperationGet()
    ], delay)
}

def lock() {
    lockAndCheck(DoorLockOperationSet.DOOR_LOCK_MODE_DOOR_SECURED)

}

def unlock() {
    lockAndCheck(DoorLockOperationSet.DOOR_LOCK_MODE_DOOR_UNSECURED,4200)

}

def unlockwtimeout() {
    lockAndCheck(DoorLockOperationSet.DOOR_LOCK_MODE_DOOR_UNSECURED_WITH_TIMEOUT,4200)
}

def refresh() {
	def result = [secure(zwave.doorLockV1.doorLockOperationGet())]
	if (state.assoc == zwaveHubNodeId) {
		//log.debug "$device.displayName is associated to ${state.assoc}"
	} else if (!state.associationQuery) {
		log.debug "checking association"
		result << "delay 4200"
		result << zwave.associationV1.associationGet(groupingIdentifier:2).format()  // old Schlage locks use group 2 and don't secure the Association CC
		result << secure(zwave.associationV1.associationGet(groupingIdentifier:1))
		state.associationQuery = new Date().time
	} else if (new Date().time - state.associationQuery.toLong() > 9000) {
		log.debug "setting association"
		result << "delay 6000"
		result << zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId).format()
		result << secure(zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:zwaveHubNodeId))
		result << zwave.associationV1.associationGet(groupingIdentifier:2).format()
		result << secure(zwave.associationV1.associationGet(groupingIdentifier:1))
		state.associationQuery = new Date().time
	}
	result
}

def updated() {

}

def secure(physicalgraph.zwave.Command cmd) {
    def result = zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
    log.debug "Result $result"
    result
}

def secureSequence(commands, delay=4200) {
	delayBetween(commands.collect{ secure(it) }, delay)
}

Sorry, the code and paste didn’t work as expected (formatting issues).

Here is the code within github. You’ll see some instructions (readme) on how to create your own custom lock device.

P.S. As I said earlier, you may have to tweak the timeout (value=2200 ms for the moment) in the lockAndCheck() function according to your own lock’s requirements.
Regards.

1 Like

Just did this. My Yale deadbolt would only work if I never touched the lock manually, and now it works every time! Thanks Yves!

Sorry for bringing back an old topic, but I have some additional info that may help others with this issue. In addition to using the timeout fix outlined above, you need to be sure that the deadbolt is able to FULLY extend. It seems like a bug in the lock, but it IS possible for the deadbolt to operate normally while in fact the bolt is slightly less than full stroke. The only indication of a problem is that the Z-wave status is always wrong. In my case there was a small steel plate on the outside of the frame that was obstructing the bolt from completing its travel. The deadbolt was working fine when controlled through the touch interface, and the ST app could lock/unlock it. However, 1-2 seconds after locking it would always switch states back to “unlocked”. I hope this helps others, as this is an otherwise great lock!

I’m having the same problem. Lock worked until 4 months ago. Now reports unlocked status on app when lo led using the app even though the door is locked. Works fine when locked manually and with the touch pad.

I had the lock manager installed by Samsung but support hasn’t been able to resolve the problem. Yale hasn’t either. I’m not sufficiently computer literate to follow what you did. Any suggestions?

Hi,

If you need more assistance, please purchase my support package at my store.

Regards.

P.S. I’d need to log on to your ST account and check your configuration.

Thanks! Working for me on Yale YRD240.

Thank you!! This appears to have resolved the issue with my YRD210 :smile:

I have a Yale YRD220 and this code worked perfectly for me. You are a genius

Thank you very much

A paypal donation would be appreciated:

Regards.

Well, I noticed another behavior now. The status is reported correctly but for an hour only. For some reason the z-wave reports “unlocked” after exactly an hour, even if the lock has been locked all this time (no lock/unlock has happened during that hour) So not sure if there is any other line I need to modify to allow the zwave update Smartthings hub every hour with curren status?

Do you know of this is happening with Zigbee protocol? I am thinking to migrate to it :thinking:

Hi,
Did you try to repair your lock within few feet of your hub?

As far as zigbee is concerned, I cannot tell you as I don’t have any zigbee locks.
Regards.

Hi,

The distance between the Hub v2 and the Lock is exactly 4 meters (13 feet away). Unfortunately, I cannot repair it closer than 3 meters (11 feet). Do you think that can cause this issue? Do I need a repeater or is better to move to Zigbee as I do have smartthings things all around

Also, When I perform “lock” via the custom device handler it locks fine and status remains, but what I have noticed is that when you manually do Poll, Refresh, Ping (health check) via the custom device handler reports the device as unlocked even when it’s locked. So no matter if is locked and remain locked, once something request an update, it will report it as unlocked.

All the functionality works fine (automation), but I do really want to see the real status at any time.

Usually, when you have persistent status issues, the only thing to try is to re-pair within few feet (much less than 11 feet). You need to bring your ST hub really close (using a power cord extension & long ethernet wire), exclude it and re-pair it.

That’s my last tip on the topic.
Regards.

1 Like

Well, I found the way to have the hub closer (3 feet) and it seems is fixing the issue so far. I will wait for an hour with the hub that close and see if the status change, if doesn’t change, then I will move the hub to the original location and test too. I am not longer using the custom device handler and the Lock status remained for more than 10 mins (something was not happening before).

Thank you very much for your time and advice. I will let you know how the TESTs goes.

Thanks again

Wanted to see how this was working for folks, as I think I am experiencing something similar with my new Yale YRD446 (z-wave/BT)

Basically when it gets polled it reports being unlocked (even though I know it is locked).

I’m going to try to do a factory reset on the device, and I will also try moving my hob very close while I do the pairing.

I’ve seen folks refer to “exclude” before repair, but I am not sure what is meant by that.

Also, I am using this device handler:

See this page 17:

Option No 7 -> Exit the network, this is exclusion.

To do this, Open your SmartThings Mobile app, open your device, click on the gear icon (preferences) and scroll down and click on Remove. Then follow the instructions (don’t Force Remove it). After it starts the removing process you’ll have to follow the instruction from the manual above to complete the exclusion process (option 7 -> 3)

Once excluded, then reset the lock and then pair it again (option 7 -> 1)