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

Is it the expected behavior that the lastCodeName event fires ONLY for unlock operation? I do not see it fire for lock operation.

LastCodeName can't fire on a lock event since locks don't lock with pin codes.

The Schlage locks do lock with pin codes. It's a daily occurrence. The piston I posted sets keypad_user for both lock and unlock events using the keypad. (and the door physically locks/unlocks using a keypad code).

Sure, but the code isn't sent to the driver, that was my point.

2 Likes

I'm also trying on similar solution for my Schlage Lock to use with Echo Speak making annoucement of the person arriving based on the lastCodeName.

Yes, lastCodeName event is only generated when keypad is used but on my Schlage Lock, the following event is lock event with the value "unlock" and type "physical". Meaning the keypad unlock is treated as a physical unlock.

So technically checking for the lastCodeName event would cover all unlock events using the keypad.

May be able to use the $currentEventDescription with the lock event to grab it.

As you noted, the locks don't send the keypad code to the drive when unlocked.

However, I believe you do get a notificationv8.NotificationReport with cmd.NotificationType == 6 (Access Control), where the cmd.event == 6 (Keypad unlock) where cmd.notificationStatus then tells you the code position (though not the code itself).

I hadn't noticed before, but there is no defined attribute to convey this. I understand you are adding new attributes in 2.2.6, so with this in mind, I think it would add a lot of functionality if there were a defined attribute like "lastUnlockCode" which is then just the position # of the code used for the last unlock. I.e., code #1, or #2. One could then use that in rules (i.e., if code #1 is entered, send text that child #1 arrived home, if code #2 entered send text that child #2 is home, if code #99 is entered, send "panic code" alert). It might also be helpful to expand the lock attributes to include "unlocked by keypad".

1 Like

I created a Global Variable to capture the lastCodeName, whenever it is changed. And use the Global Variable in the rules.

Sorry to revive an old reply, but can you tell me how you captured the lastCodeName?

Thanks.

Rule Manager. For example:
IF (Last lock code entered on Front Door Lock: Debby(F) [FALSE]) THEN

I see.

I’m just getting my toes wet in more advanced coding since Hubitat is a little more “coding friendly” and was hoping for a Webcore variable using the $currentDevice function. I can see the lastCodeName entry in the Name field in the event list, and I can snag other fields per entry, but not sure what calls the entry in the Name field.

I've made some changes after upgrading of Rule Machine. The steps are as follows:

  1. Define a new Rule under Rule Machine.
  2. Create a local variable, personName, or something you prefer.
  3. Set Trigger Event to "Lock code entered on YourDoorLock: Any Lock Codes"
  4. Set Actions as below:
    Set personName to YourDoorLock LastCodeName
    ** you can use the variable "personName" for any other action after that.
    Set personName to ""
    ** This is to remove the name from the variable.

Before you can use the lastCodeName from the Lock device, you've to setup them up on the Device using the Command Set Code.

Hope this helps and happy holidays.

3 Likes

It does, thank you. I’ll play around with it.

Ended up finding a different way to do what I wanted using contains($currentEventDescription, “was locked by”) but wouldn’t mind having a solid variable to pull from.

Thanks again!

I haven't used Webcore in a long time but is there no way to grab a value from a state?

I don't think there's record on the Code used for locking the door, unless you setup on the Lock itself that locking action requires a Code entry.

For Kwikset locks (of which I have 3), no, a code isn’t required to lock. And I don’t really care about that, anyway. Just more interested in who unlocked the door when I’m away.

Far as I can tell with my very limited knowledge using Webcore, there’s no way to search/call the Name field (specifically looking for lastCodeName) and return the Description associated with it. So, instead, I had to find a distinct set of words to get the unique record.

Well in that case.....I wrote an app for that.

/*
 *	Lock Code Notify
 *
 *	Author: J.R. Farrar
 * 
 * 
 * 
 */

definition(
  name: "Lock Code Notify Child",
  namespace: "jrfarrar",
  author: "J.R. Farrar",
  description: "Lock Code Notify",
  iconUrl: "",
  iconX2Url: "",
  iconX3Url: "",
  importUrl: ""
)

preferences {
page(name: "pageConfig")
}

def pageConfig() {
dynamicPage(name: "", title: "", install: true, uninstall: true, refreshInterval:0) { 
    
  section(getFormat("header-green", "Devices")) {
		  paragraph "Notify when door lock code is entered."
          input (name: "lock", type: "capability.lock", title: "Lock", submitOnChange: true, required: true)
          input ("sendPushMessage", "capability.notification", title: "Notification device", multiple: true, required: true, submitOnChange: true)
          //if (sendPushMessage) input ("message", "text", title: "Message to send?", required: false)
    }
    
    
    section(getFormat("header-green", "LOGGING")){                       
			input(name: "logLevel",title: "IDE logging level",multiple: false,required: true,type: "enum",options: getLogLevels(),submitOnChange : false,defaultValue : "1")
    }
    section(getFormat("header-green", "APP NAME")){
        input (name: "thisName", type: "text", title: "App Name", submitOnChange: true)
	    if(thisName) app.updateLabel("$thisName") else app.updateSetting("thisName", "Lock Code Notify")
        //if(state.appname) app.updateLabel("${state.appname}") else {if (dehumidifierSwitch) app.updateSetting("thisName", "Humidity Control - $dehumidifierSwitch")}
    }
  }  
} 

def installed() {
  infolog "installed"
  initialize()
}

def updated() {
  infolog "updated"
  initialize()
}

def initialize() {
  infolog "initialize"
  //unschedule all jobs and unsubscribe all events
  unschedule() 
  unsubscribe()
  //subscribe to events for chosen devices
  subscribeToEvents()
}

def uninstalled() {
  unschedule()
  unsubscribe()
  log.debug "uninstalled"
}

def subscribeToEvents() {
    if(lock) {
    subscribe(lock, "lastCodeName", lastCodeHandler, ["filterEvents": false])
    subscribe(lock, "lock.unlocked", lockHandler)    
    //subscribe(lock, "lastCodeName", lockHandler)            
    }
}


def lockHandler(evt) {
    //debuglog "Unlock event: ${evt.name} : ${evt.descriptionText}"
    lastName = lock.currentValue("lastCodeName")

    if (evt.descriptionText.contains("unlocked by")) {
        infolog "$lock.displayName was unlocked by: $lastName (using description text)"
    } else {
        infolog "$lock.displayName was unlocked manually or electronically (using description text)"
    }

}

def lastCodeHandler(evt) {
    debuglog "Unlock event: ${evt.name} : ${evt.descriptionText}"
    lastName = lock.currentValue("lastCodeName")
    debuglog "lastCodeName: ${lastName}" 
    infolog "$lock.displayName was unlocked by: $lastName"
    sendPushMessage.deviceNotification("$lock.displayName was unlocked by: $lastName")
    app.updateLabel("$thisName <span style=\"color:black;\">(${lastName})</span>")        
}



def getFormat(type, myText=""){			// Modified from @Stephack Code   
	if(type == "header-green") return "<div style='color:#ffffff;font-weight: bold;background-color:#81BC00;border: 1px solid;box-shadow: 2px 3px #A9A9A9'>${myText}</div>"
    if(type == "line") return "<hr style='background-color:#1A77C9; height: 1px; border: 0;'>"
    if(type == "title") return "<h2 style='color:#1A77C9;font-weight: bold'>${myText}</h2>"
    if(type == "title2") return "<div style='color:#1A77C9;font-weight: bold'>${myText}</div>"
}

def debuglog(statement)
{   
	def logL = 0
    if (logLevel) logL = logLevel.toInteger()
    if (logL == 0) {return}//bail
    else if (logL >= 2)
	{
		log.debug("$thisName: " + statement)
	}
}
def infolog(statement)
{       
	def logL = 0
    if (logLevel) logL = logLevel.toInteger()
    if (logL == 0) {return}//bail
    else if (logL >= 1)
	{
		log.info("$thisName: " + statement)
	}
}
def getLogLevels(){
    return [["0":"None"],["1":"Running"],["2":"NeedHelp"]]
}

Very nice!

But pardon my ignorance as I’m new to Hubitat; would that be installed as a New App in Apps code? Just paste in the code and save?

I got used to the “plug and play” and “cookie cutter code” from the ST platform so this is fairly new to me, (though I have been in the HA game for about 5 years starting with Wink, Stringify, and IFTTT so I have some clue) so I appreciate y’all taking time out to help a newbie out over here!

https://docs.hubitat.com/index.php?title=How_to_Install_Custom_Apps

1 Like