HSM and Custom Keypad Device Drivers

This is just to document how Hubitat Safety Monitor (HSM) and Security Keypads communicate so if you need to make your own device driver (or troubleshoot someone else's driver), you can at least know where to start.

Keypads have 2 ways of controlling HSM :
Note for both methods : the hsmSetArm command needs to match what is in the developer documentation, except for 'cancelAlerts' which starts with a lower case 'c'

  • The sendLocationEvent method
    sendLocationEvent (name: "hsmSetArm", value: “[hsmSetArm command]”)
  • The sendEvent method
    sendEvent(name:"armingIn", value: "[-literally anything but null-]", data:[armCmd: "[hsmSetArm command]"])
    ****Note 1: the 'value' here can be anything, I'd recommend the [hsmSetArm command]
    ****Note 2: HSM will only trigger for a state change. If the VALUE doesn't change (it doesn't care about the data:[..] ), then HSM won't trigger. You can force a trigger by using the following parameter in the sendEvent: isStateChange:true

HSM controls the state of the Keypad by calling the following Methods within the keypad's Device Driver anytime there is a change in the HSM armed state :

  • armAway(delay)
  • armHome(delay)
  • armNight(delay)
  • disarm(delay)
    -- delay for disarm will always be 0
  • setExitDelay(delayMap)
    -- Map has 3 keys, each with a number value. Ex : [nightDelay:7, homeDelay:6, awayDelay:5]
    -- Note : This method & associated delay settings don't really have to be used since the delays are sent with the arm___ methods.
  • entry(delay)
    -- This gets called during an intrusion delay. Without this, the delay won't start & the alerts won't trigger.
    -- this needs to be listed as command "entry" as well as being a method

In order to use any PINs (including the app 'Lock Code Manager') you'll need the following Methods : (save PINs to device.currentValue("lockCodes"))

  • setCode(codeposition, pincode, name)
  • deleteCode(codeposition)
  • getCodes()

I do not believe the following Methods have any real impact when using HSM or Lock Code manager. You'd use them within the Keypad driver as you see fit only :

  • setEntryDelay (entrancedelay)
  • setCodeLength(pincodelength)

Notes :

  • Whenever the driver is driven by an App, an event is created for the command executed. For example : If HSM drove the driver to execute the "armAway" command/method, an event would be made with the following : (example) bolded for emphasis
    -- Event Data : [digital:false, locationId:null, date:[date], id:3159904, hubId:null, location:[hub name], descriptionText:Command called: armAway, archivable:true, isStateChange:false, class:class com.hubitat.hub.domain.Event, integerValue:0, source:DEVICE, displayName:[display name], deviceId:[Dev ID], unixTime:[time], jsonData:[:], triggeredListeners:null, name:command-armAway, physical:false, device:[name], value:null, translatable:false, type:command, installedAppId:null, unit:null, longValue:0, displayed:true, data:null, description:null, producedBy:APP-4, linkText:[name]]
  • PINs should be saved to device.currentValue("lockCodes"), otherwise 'Lock Code Manager' loops, retrying the Method execution.
  • If you don't have all required Methods noted above, you'll throw errors when using the device with HSM and it either won't arm or won't give alerts upon intrusion.
  • HSM sometimes calls the 'setExitDelay' method every second of a delay, but not always. Why is unknown.
  • You'll need to tell HSM to use that keypad for control (in HSM options), or else it won't look for the "armingIn" event, or pass the arm/disarm commands to the device driver's methods.
    -- HSM subscribes to the 'armingIn' attribute of the keypad
  • HSM doesn't care about any delays put into the keypad's device driver. It will always use its own delays (put into its Options menu), and tell the keypad those delays upon delay start.
  • HSM doesn't seem to actually 'Disarm All' when you choose that in the options. You can, though, opt to have the Device Driver actually send the 'disarmAll' command if you want it to actually Disarm All.
  • In order to not have looping logic (or out of sync status; HSM should dictate status) upon arming/disarming via Keypad, I'd implement the following logic
    -- Have the button to arm/disarm on your keypad call a method in your device driver that tells HSM to arm/disarm. Note this must not be the same as the 5 drivers HSM calls above.
    -- HSM will then trigger the appropriate method in your device driver (5 possibilities listed above) for the arm/disarm
    -- Have your Keypad then react appropriately (delay, chime, change state, etc.) within that method
  • HSM will take a command to arm into a state while not Disarmed. This would mean that a "exit delay" starts while not disarmed. All rules of the original armed state will be enforced until the Exit Delay finishes and the new Armed State is active. This can confuse the user who will see the "Exit Delay" and believe it is safe to exit without causing an intrusion alert.
    -- Recommendation is to either not allow arming into a state unless HSM is disarmed OR having the keypad disarm HSM and then go into the Exit Delay of the new armed state (keep in mind there should be a slight delay between the Disarm & re-arm commands so they don't overlap due to millisecond delays in HSM's subscription triggers)
    -- Note that using armingIn() without the attribute 'isStateChange:true' could help since it won't trigger HSM if armingIn hasn't changed values. You should then ensure armingIn tracks changes made via HSM so it's always aligned.
  • Due to how Hubitat Hubs process script, if an arming/disarming method in your Keypad's driver is triggered, you won't be able to immediately (within your arming/disarming method) check to see HSM's new hsmStatus (if it was triggered by HSM), or if the command event that triggered the method was "producedBy" the HSM app, the button in Device Details, or a Rule (via 'run custom action').
    -- In order to fix this, you'll need to make a new method to check this, and use the following : runInMillis (1, "methodName", misfire: "ignore"]).... What this does is tell the hub to finish all other actions (including updating hsmStatus & storing the event data that triggered your arming/disarming command method) and then come back to do this method as soon as it possibly can. That way, hsmStatus & the event data will be readable by your driver.

I hope this helps someone. I figured this out in order to troubleshoot a Keypad Device Driver that was giving me problems. Happy coding!

Edit : as of 23 Dec 2024, Platform version 2.3.9.201, HSM sends the arm/disarm commands at the beginning & end of the delay (2 back to back for Disarm), as well as the setExitDelay ~1/sec during any exit delay. Make sure your Keypad Drivers can handle that.

2 Likes