/*
Ring Keypad Gen 2 - Community Driver
Copyright 2020 -> 2021 Hubitat Inc. All Rights Reserved
Special Thanks to Bryan Copeland (@bcopeland) for writing and releasing this code to the community!
1.2.5 - 08/02/22 - Rework Driver to allow options to use Subscription to armingIn device status for apps that support it @mavrrick58
1.2.4 - 08/01/22 - Rollback Changes
1.2.3 - 07/31/22 - remove Redundent calls causing multiple events in HSM. Added Additional Logging. @mavrrick58
1.2.2 - 06/09/22 - @dkilgore90 add "validCode" attribute and "validateCheck" preference
1.2.1 - 04/14/22 - Bug hunting
1.2.0 - 04/04/22 - Fixed Tones
---
1.0.0 - 11/11/21 - Initial Community Release
*/
import groovy.transform.Field
import groovy.json.JsonOutput
def version() {
return "1.2.5"
}
metadata {
definition (name: "Ring Alarm Keypad G2 Community 3", namespace: "hubitat", author: "Community") {
capability "Actuator"
capability "Sensor"
capability "Configuration"
capability "SecurityKeypad"
capability "Battery"
capability "Alarm"
capability "PowerSource"
capability "LockCodes"
capability "Motion Sensor"
capability "PushableButton"
capability "HoldableButton"
command "entry"
command "setArmNightDelay", ["number"]
command "setArmAwayDelay", ["number"]
command "setArmHomeDelay", ["number"]
command "setPartialFunction"
command "resetKeypad"
command "playTone", [[name: "Play Tone", type: "STRING", description: "Tone_1, Tone_2, etc."]]
command "volAnnouncement", [[name:"Announcement Volume", type:"NUMBER", description: "Volume level (1-10)"]]
command "volKeytone", [[name:"Keytone Volume", type:"NUMBER", description: "Volume level (1-10)"]]
command "volSiren", [[name:"Chime Tone Volume", type:"NUMBER", description: "Volume level (1-10)"]]
//command "keyBacklightBrightness", [[name:"Key Backlight Brightness", type:"NUMBER", description: "Level (1-100)"]]
attribute "alarmStatusChangeTime", "STRING"
attribute "alarmStatusChangeEpochms", "NUMBER"
attribute "armingIn", "NUMBER"
attribute "armAwayDelay", "NUMBER"
attribute "armHomeDelay", "NUMBER"
//attribute "keyBacklightBrightness", "NUMBER"
attribute "lastCodeName", "STRING"
attribute "lastCodeTime", "STRING"
attribute "lastCodeEpochms", "NUMBER"
attribute "motion", "STRING"
attribute "validCode", "ENUM", ["true", "false"]
attribute "volAnnouncement", "NUMBER"
attribute "volKeytone", "NUMBER"
attribute "volSiren", "NUMBER"
fingerprint mfr:"0346", prod:"0101", deviceId:"0301", inClusters:"0x5E,0x98,0x9F,0x6C,0x55", deviceJoinName: "Ring Alarm Keypad G2"
}
preferences {
input name: "about", type: "paragraph", element: "paragraph", title: "Ring Alarm Keypad G2 Community Driver", description: "${version()}
Note:
The first 3 Tones are alarm sounds that also flash the Red Indicator Bar on the keypads. The rest are more pleasant sounds that could be used for a variety of things."
configParams.each { input it.value.input }
input name: "theTone", type: "enum", title: "Chime tone", options: [
["Tone_1":"(Tone_1) Siren (default)"],
["Tone_2":"(Tone_2) 3 Beeps"],
["Tone_3":"(Tone_3) 4 Beeps"],
["Tone_4":"(Tone_4) Navi"],
["Tone_5":"(Tone_5) Guitar"],
["Tone_6":"(Tone_6) Windchimes"],
["Tone_7":"(Tone_7) DoorBell 1"],
["Tone_8":"(Tone_8) DoorBell 2"],
["Tone_9":"(Tone_9) Invalid Code Sound"],
], defaultValue: "Tone_1", description: ""
input name: "instantArming", type: "bool", title: "Enable set alarm without code", defaultValue: false, description: ""
input name: "validateCheck", type: "bool", title: "Validate codes submitted with checkmark", defaultValue: false, description: ""
input name: "proximitySensor", type: "bool", title: "Disable the Proximity Sensor", defaultValue: false, description: ""
input name: "optEncrypt", type: "bool", title: "Enable lockCode encryption", defaultValue: false, description: ""
input name: "evtInt", type: "bool", title: "Enable event based integration", defaultValue: false, description: "This should be activated when a security app subscribes to the keypad. (ie HSM)"
input name: "logEnable", type: "bool", title: "Enable debug logging", defaultValue: true
input name: "txtEnable", type: "bool", title: "Enable descriptionText logging", defaultValue: true
}
}
@Field static Map configParams = [
//4: [input: [name: "configParam4", type: "enum", title: "Announcement Volume", description:"", defaultValue:7, options:[0:"0",1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",10:"10"]],parameterSize:1],
//5: [input: [name: "configParam5", type: "enum", title: "Keytone Volume", description:"", defaultValue:6, options:[0:"0",1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",10:"10"]],parameterSize:1],
//6: [input: [name: "configParam6", type: "enum", title: "Siren Volume", description:"", defaultValue:10, options:[0:"0",1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",10:"10"]],parameterSize:1],
7: [input: [name: "configParam7", type: "number", title: "Long press Emergency Duration", description:"", defaultValue: 3, range:"2..5"],parameterSize:1],
8: [input: [name: "configParam8", type: "number", title: "Long press Number pad Duration", description:"", defaultValue: 3, range:"2..5"],parameterSize:1],
12: [input: [name: "configParam12", type: "number", title: "Security Mode Brightness", description:"", defaultValue: 100, range:"0..100"],parameterSize:1],
13: [input: [name: "configParam13", type: "number", title: "Key Backlight Brightness", description:"", defaultValue: 100, range:"0..100"],parameterSize:1],
]
@Field static Map armingStates = [
0x00: [securityKeypadState: "armed night", hsmCmd: "armNight"],
0x02: [securityKeypadState: "disarmed", hsmCmd: "disarm"],
0x0A: [securityKeypadState: "armed home", hsmCmd: "armHome"],
0x0B: [securityKeypadState: "armed away", hsmCmd: "armAway"]
]
@Field static Map CMD_CLASS_VERS=[0x86:2, 0x70:1, 0x20:1, 0x86:3]
void logsOff(){
log.warn "debug logging disabled..."
device.updateSetting("logEnable", [value:"false", type:"bool"])
}
void updated() {
log.info "updated..."
log.warn "debug logging is: ${logEnable == true}"
log.warn "description logging is: ${txtEnable == true}"
log.warn "encryption is: ${optEncrypt == true}"
unschedule()
if (logEnable) runIn(1800,logsOff)
sendToDevice(runConfigs())
updateEncryption()
proximitySensorHandler()
volAnnouncement()
volKeytone()
volSiren()
}
void installed() {
initializeVars()
}
void uninstalled() {
}
void initializeVars() {
// first run only
sendEvent(name:"codeLength", value: 4)
sendEvent(name:"maxCodes", value: 100)
sendEvent(name:"lockCodes", value: "")
sendEvent(name:"armHomeDelay", value: 5)
sendEvent(name:"armAwayDelay", value: 5)
//sendEvent(name:"keyBacklightBrightness", value: 90)
sendEvent(name:"volAnnouncement", value: 7)
sendEvent(name:"volKeytone", value: 5)
sendEvent(name:"volSiren", value: 75)
sendEvent(name:"securityKeypad", value:"disarmed")
state.keypadConfig=[entryDelay:5, exitDelay: 5, armNightDelay:5, armAwayDelay:5, armHomeDelay: 5, codeLength: 4, partialFunction: "armHome"]
state.keypadStatus=2
state.initialized=true
}
void resetKeypad() {
state.initialized=false
configure()
getCodes()
}
void configure() {
if (logEnable) log.debug "configure()"
if (!state.initialized) initializeVars()
if (!state.keypadConfig) initializeVars()
keypadUpdateStatus(state.keypadStatus, state.type, state.code)
runIn(5,pollDeviceData)
}
void pollDeviceData() {
List cmds = []
cmds.add(zwave.versionV3.versionGet().format())
cmds.add(zwave.manufacturerSpecificV2.deviceSpecificGet(deviceIdType: 1).format())
cmds.add(zwave.batteryV1.batteryGet().format())
cmds.add(zwave.notificationV8.notificationGet(notificationType: 8, event: 0).format())
cmds.add(zwave.notificationV8.notificationGet(notificationType: 7, event: 0).format())
cmds.addAll(processAssociations())
sendToDevice(cmds)
}
void keypadUpdateStatus(Integer status,String type="digital", String code) {
sendToDevice(zwave.indicatorV3.indicatorSet(indicatorCount:1, value: 0, indicatorValues:[[indicatorId:status, propertyId:2, value:0xFF]]).format())
state.keypadStatus = status
if (state.code != "") { type = "physical" }
eventProcess(name: "securityKeypad", value: armingStates[status].securityKeypadState, type: type, data: state.code)
state.code = ""
state.type = "digital"
}
void armNight(delay=0) {
if (logEnable) log.debug "In armNight (${version()}) - delay: ${delay}"
def sk = device.currentValue("securityKeypad")
if(sk != "armed night") {
if (delay > 0 ) {
exitDelay(delay)
runIn(delay, armNightEnd)
} else {
runIn(delay, armNightEnd)
}
} else {
if (logEnable) log.debug "In armNight - securityKeypad already set to 'armed night', so skipping."
}
}
void armNightEnd() {
if (!state.code) { state.code = "" }
if (!state.type) { state.type = "physical" }
def sk = device.currentValue("securityKeypad")
if(sk != "armed night") {
//keypadUpdateStatus(0x00, state.type, state.code)
Date now = new Date()
sendLocationEvent (name: "hsmSetArm", value: "armNight")
sendEvent(name:"alarmStatusChangeTime", value: "${now}", isStateChange:true)
long ems = now.getTime()
sendEvent(name:"alarmStatusChangeEpochms", value: "${ems}", isStateChange:true)
}
}
void armAway(delay=state.keypadConfig.armAwayDelay) {
if (evtInt) {
if (logEnable) log.debug "In armAway (${version()}) - delay: ${delay}"
def sk = device.currentValue("securityKeypad")
def al = device.currentValue("alarm") // Allow compareable variable for added conditions.
if (logEnable) log.debug "In armAway (${version()}) - sk: ${sk}"
if(sk != "armed away") {
if (delay > 0 ) {
state.armingIn = state.keypadConfig.armAwayDelay
if (state.type == "digital" && al != "armingAway") { // Added conditions for digital control distinction
if (logEnable) log.debug "In armAway (${version()}) alarm: ${al} - Validation for first digital submit"
sendEvent(name:"armingIn", value: state.keypadConfig.armAwayDelay, data:[armMode: armingStates[0x0B].securityKeypadState, armCmd: armingStates[0x0B].hsmCmd], isStateChange:true) // Event HSM Subscribes too
changeStatus("armingAway") // Set variable to for second digital submit
if (logEnable) log.debug "In armAway (${version()}) - armingIn: ${state.armingIn}"
exitDelay(delay)
runIn(delay, armAwayEnd)
}
if (state.type == "physical" && al != "armingAway") { // Added conditions for digital control distinction
if (logEnable) log.debug "In armAway (${version()}) alarm: ${al} - Validation for first physical submit"
changeStatus("armingAway") // Set variable to for second digital submit
if (logEnable) log.debug "In armAway (${version()}) - armingIn: ${state.armingIn}"
exitDelay(delay)
runIn(delay, armAwayEnd)
} else if (al == "armingAway")
{ if (logEnable) log.debug "In armAway (${version()}) - Second Submission from HSM, not sending HSM update" }
else { //Populate variable to be able to distinquish slarm state thta isn't final
if (logEnable) log.debug "In armAway (${version()}) - No mathing condition. Nothing to execute"
}
} else {
armAwayEnd()
}
} else {
if (logEnable) log.debug "In armAway - securityKeypad already set to 'armed away', so skipping."
}
}
else {
if (logEnable) log.debug "In armAway (${version()}) - delay: ${delay}"
def sk = device.currentValue("securityKeypad")
if(sk != "armed away") {
if (delay > 0 ) {
exitDelay(delay)
runIn(delay, armAwayEnd)
} else {
armAwayEnd()
}
} else {
if (logEnable) log.debug "In armAway - securityKeypad already set to 'armed away', so skipping."
}
}
}
void armAwayEnd() {
if (evtInt) {
if (!state.code) { state.code = "" }
if (!state.type) { state.type = "physical" }
def sk = device.currentValue("securityKeypad")
if (logEnable) log.debug "In armAwayEnd (${version()}) - sk: ${sk} code: ${state.code} type: ${state.type} delay: ${delay}"
if(sk == "exit delay") { // added conditional handeling for Exit Delay status. for sepreate handeling of delayed exit.
if (logEnable) log.debug "In armAwayEnd (${version()}) sk: ${sk} Executing after delayed arming"
Date now = new Date()
keypadUpdateStatus(0x0B, state.type, state.code)
sendEvent(name:"alarmStatusChangeTime", value: "${now}", isStateChange:true)
long ems = now.getTime()
sendEvent(name:"alarmStatusChangeEpochms", value: "${ems}", isStateChange:true)
changeStatus("set")
state.armingIn = 0
}
else if (sk != "armed away") {
if (logEnable) log.debug "In armAwayEnd (${version()}) sk: ${sk} Executing immediate arming"
Date now = new Date()
keypadUpdateStatus(0x0B, state.type, state.code)
if (state.type == "digital") sendEvent(name:"armingIn", value: state.keypadConfig.armAwayDelay, data:[armMode: armingStates[0x0B].securityKeypadState, armCmd: armingStates[0x0B].hsmCmd], isStateChange:true) // Event HSM Subscribes too
sendEvent(name:"alarmStatusChangeTime", value: "${now}", isStateChange:true)
long ems = now.getTime()
sendEvent(name:"alarmStatusChangeEpochms", value: "${ems}", isStateChange:true)
changeStatus("set")
state.armingIn = 0
}
}
else {
if (!state.code) { state.code = "" }
if (!state.type) { state.type = "physical" }
def sk = device.currentValue("securityKeypad")
if(sk != "armed away") {
Date now = new Date()
keypadUpdateStatus(0x0B, state.type, state.code)
sendLocationEvent (name: "hsmSetArm", value: "armAway")
sendEvent(name:"alarmStatusChangeTime", value: "${now}", isStateChange:true)
long ems = now.getTime()
sendEvent(name:"alarmStatusChangeEpochms", value: "${ems}", isStateChange:true)
changeStatus("set")
}
}
}
void armHome(delay=state.keypadConfig.armHomeDelay) {
if (evtInt) {
if (logEnable) log.debug "In armHome (${version()}) - delay: ${delay}"
def sk = device.currentValue("securityKeypad")
def al = device.currentValue("alarm")
if(sk != "armed home") {
if (delay > 0) {
state.armingIn = state.keypadConfig.armHomeDelay
if (state.type == "digital" && al != "armingHome") { // Added conditions for digital control distinction
if (logEnable) log.debug "In armHome (${version()}) alarm: ${al} - Validation for first digital submit"
sendEvent(name:"armingIn", value: state.keypadConfig.armHomeDelay, data:[armMode: armingStates[0x0A].securityKeypadState, armCmd: armingStates[0x0A].hsmCmd], isStateChange:true) // Event HSM Subscribes too
changeStatus("armingHome") // Set variable to for second digital submit
if (logEnable) log.debug "In armHome (${version()}) - armingIn: ${state.armingIn}"
exitDelay(delay)
runIn(delay, armHomeEnd)
}
if (state.type == "physical" && al != "armingHome") { // Added conditions for digital control distinction
if (logEnable) log.debug "In armHome (${version()}) alarm: ${al} - Validation for first physical submit"
changeStatus("armingHome") // Set variable to for second digital submit
if (logEnable) log.debug "In armHome (${version()}) - armingIn: ${state.armingIn}"
exitDelay(delay)
runIn(delay, armHomeEnd)
} else if (al == "armingHome")
{ if (logEnable) log.debug "In armHome (${version()}) - Second Submission from HSM, not sending HSM update" }
else {
if (logEnable) log.debug "In armHome (${version()}) - armingIn: ${state.armingIn}"
}
} else {
armHomeEnd()
}
} else {
if (logEnable) log.debug "In armHome - securityKeypad already set to 'armed home', so skipping."
}
}
else {
if (logEnable) log.debug "In armHome (${version()}) - delay: ${delay}"
def sk = device.currentValue("securityKeypad")
if(sk != "armed home") {
if (delay > 0) {
exitDelay(delay)
runIn(delay, armHomeEnd)
} else {
armHomeEnd()
}
} else {
if (logEnable) log.debug "In armHome - securityKeypad already set to 'armed home', so skipping."
}
}
}
void armHomeEnd() {
if (evtInt) {
if (!state.code) { state.code = "" }
if (!state.type) { state.type = "physical" }
def sk = device.currentValue("securityKeypad")
if (logEnable) log.debug "In armHomeEnd (${version()}) - sk: ${sk} code: ${state.code} type: ${state.type} delay: ${delay}"
if(sk == "exit delay") {
if (logEnable) log.debug "In armHomeEnd (${version()}) sk: ${sk} Executing after delayed arming"
Date now = new Date()
keypadUpdateStatus(0x0A, state.type, state.code)
sendEvent(name:"alarmStatusChangeTime", value: "${now}", isStateChange:true)
long ems = now.getTime()
sendEvent(name:"alarmStatusChangeEpochms", value: "${ems}", isStateChange:true)
changeStatus("set")
state.armingIn = 0
}
else if(sk != "armed home") {
if (logEnable) log.debug "In armHomeEnd (${version()}) sk: ${sk} Executing immediate arming"
Date now = new Date()
keypadUpdateStatus(0x0A, state.type, state.code)
if (state.type == "digital") sendEvent(name:"armingIn", value: state.keypadConfig.armHomeDelay, data:[armMode: armingStates[0x0A].securityKeypadState, armCmd: armingStates[0x0A].hsmCmd], isStateChange:true)
sendEvent(name:"alarmStatusChangeTime", value: "${now}", isStateChange:true)
long ems = now.getTime()
sendEvent(name:"alarmStatusChangeEpochms", value: "${ems}", isStateChange:true)
changeStatus("set")
state.armingIn = 0
}
}
else {
if (!state.code) { state.code = "" }
if (!state.type) { state.type = "physical" }
def sk = device.currentValue("securityKeypad")
if(sk != "armed home") {
Date now = new Date()
keypadUpdateStatus(0x0A, state.type, state.code)
sendLocationEvent (name: "hsmSetArm", value: "armHome")
sendEvent(name:"alarmStatusChangeTime", value: "${now}", isStateChange:true)
long ems = now.getTime()
sendEvent(name:"alarmStatusChangeEpochms", value: "${ems}", isStateChange:true)
changeStatus("set")
}
}
}
void disarm(delay=0) {
if (logEnable) log.debug "In disarm (${version()}) - delay: ${delay}"
def sk = device.currentValue("securityKeypad")
if (logEnable) log.debug "In disarm (${version()}) - sk: ${sk}"
if(sk != "disarmed") {
if (delay > 0 ) {
exitDelay(delay)
runIn(delay, disarmEnd)
} else {
disarmEnd()
}
} else {
if (logEnable) log.debug "In disarm - securityKeypad already set to 'disarmed', so skipping."
}
}
void disarmEnd() {
if (!state.code) { state.code = "" }
if (!state.type) { state.type = "physical" }
def sk = device.currentValue("securityKeypad")
if (logEnable) log.debug "In disarmEnd (${version()}) - sk: ${sk} code: ${state.code} type: ${state.type}"
if(sk != "disarmed") {
Date now = new Date()
keypadUpdateStatus(0x02, state.type, state.code) // Sends status to Keypad
sendLocationEvent (name: "hsmSetArm", value: "disarm")
sendEvent(name:"alarmStatusChangeTime", value: "${now}", isStateChange:true)
long ems = now.getTime()
sendEvent(name:"alarmStatusChangeEpochms", value: "${ems}", isStateChange:true)
changeStatus("off")
state.armingIn = 0
unschedule(armHomeEnd)
unschedule(armAwayEnd)
unschedule(changeStatus)
}
}
void exitDelay(delay){
if (logEnable) log.debug "In exitDelay (${version()}) - delay: ${delay}"
if (delay) {
sendToDevice(zwave.indicatorV3.indicatorSet(indicatorCount:1, value: 0, indicatorValues:[[indicatorId:0x12, propertyId:7, value:delay.toInteger()]]).format())
// update state so that a disarm command during the exit delay resets the indicator lights
state.keypadStatus = "18"
type = state.code != "" ? "physical" : "digital"
eventProcess(name: "securityKeypad", value: "exit delay", type: type, data: state.code)
if (logEnable) log.debug "In exitDelay (${version()}) - type: ${type}"
}
}
def changeStatus(data) {
if (logEnable) log.debug "In changeStatus (${version()}) - data: ${data}"
sendEvent(name: "alarm", value: data, isStateChange: true)
}
void setEntryDelay(delay){
if (logEnable) log.debug "In setEntryDelay (${version()}) - delay: ${delay}"
state.keypadConfig.entryDelay = delay != null ? delay.toInteger() : 0
}
void setExitDelay(Map delays){
if (logEnable) log.debug "In setExitDelay (${version()}) - delay: ${delays}"
state.keypadConfig.exitDelay = (delays?.awayDelay ?: 0).toInteger()
state.keypadConfig.armNightDelay = (delays?.nightDelay ?: 0).toInteger()
state.keypadConfig.armHomeDelay = (delays?.homeDelay ?: 0).toInteger()
state.keypadConfig.armAwayDelay = (delays?.awayDelay ?: 0).toInteger()
}
void setExitDelay(delay){
if (logEnable) log.debug "In setExitDelay (${version()}) - delay: ${delay}"
state.keypadConfig.exitDelay = delay != null ? delay.toInteger() : 0
}
void setArmNightDelay(delay){
if (logEnable) log.debug "In setArmNightDelay (${version()}) - delay: ${delay}"
state.keypadConfig.armNightDelay = delay != null ? delay.toInteger() : 0
}
void setArmAwayDelay(delay){
if (logEnable) log.debug "In setArmAwayDelay (${version()}) - delay: ${delay}"
sendEvent(name:"armAwayDelay", value: delay)
state.keypadConfig.armAwayDelay = delay != null ? delay.toInteger() : 0
}
void setArmHomeDelay(delay){
if (logEnable) log.debug "In setArmHomeDelay (${version()}) - delay: ${delay}"
sendEvent(name:"armHomeDelay", value: delay)
state.keypadConfig.armHomeDelay = delay != null ? delay.toInteger() : 0
}
void setCodeLength(pincodelength) {
if (logEnable) log.debug "In setCodeLength (${version()}) - pincodelength: ${pincodelength}"
eventProcess(name:"codeLength", value: pincodelength, descriptionText: "${device.displayName} codeLength set to ${pincodelength}")
state.keypadConfig.codeLength = pincodelength
// set zwave entry code key buffer
// 6F06XX10
sendToDevice("6F06" + hubitat.helper.HexUtils.integerToHexString(pincodelength.toInteger()+1,1).padLeft(2,'0') + "0F")
}
void setPartialFunction(mode = null) {
if (logEnable) log.debug "In setPartialFucntion (${version()}) - mode: ${mode}"
if (logEnable) log.debug "In setPartialFucntion (${version()}) - armingIn: ${state.armingIn}"
if (state.armingIn > 0) {
state.armingIn = state.armingIn - 1
if (logEnable) log.debug "In setPartialFucntion (${version()}) - armingIn: ${state.armingIn}"
}
if ( !(mode in ["armHome","armNight"]) ) {
if (txtEnable) log.warn "custom command used by HSM"
} else if (mode in ["armHome","armNight"]) {
state.keypadConfig.partialFunction = mode == "armHome" ? "armHome" : "armNight"
}
}
// alarm capability commands
void off() {
if (logEnable) log.debug "In off (${version()})"
eventProcess(name:"alarm", value:"off")
changeStatus("off")
sendToDevice(zwave.indicatorV3.indicatorSet(indicatorCount:1, value: 0, indicatorValues:[[indicatorId:state.keypadStatus, propertyId:2, value:0xFF]]).format())
}
void both() {
if (logEnable) log.debug "In both (${version()})"
siren()
}
void siren() {
if (logEnable) log.debug "In Siren (${version()})"
eventProcess(name:"alarm", value:"siren")
changeStatus("siren")
sendToDevice(zwave.indicatorV3.indicatorSet(indicatorCount:1, value: 0, indicatorValues:[[indicatorId:0x0C, propertyId:2, value:0xFF]]).format())
}
void strobe() {
if (logEnable) log.debug "In strobe (${version()})"
eventProcess(name:"alarm", value:"strobe")
changeStatus("strobe")
List cmds=[]
cmds.add(zwave.indicatorV3.indicatorSet(indicatorCount:1, value: 0, indicatorValues:[[indicatorId:0x0C, propertyId:2, value:0xFF]]).format())
cmds.add(zwave.indicatorV3.indicatorSet(indicatorCount:1, value: 0, indicatorValues:[[indicatorId:0x0C, propertyId:2, value:0x00]]).format())
sendToDevice(cmds)
}
void zwaveEvent(hubitat.zwave.commands.basicv1.BasicReport cmd) {
// this is redundant/ambiguous and I don't care what happens here
}
void parseEntryControl(Short command, List commandBytes) {
if (logEnable) log.debug "In parseEntryControl (${version()})"
//log.debug "parse: ${command}, ${commandBytes}"
if (command == 0x01) {
Map ecn = [:]
ecn.sequenceNumber = commandBytes[0]
ecn.dataType = commandBytes[1]
ecn.eventType = commandBytes[2]
ecn.eventDataLength = commandBytes[3]
def currentStatus = device.currentValue('securityKeypad')
def alarmStatus = device.currentValue('alarm')
String code=""
if (ecn.eventDataLength>0) {
for (int i in 4..(ecn.eventDataLength+3)) {
if (logEnable) log.debug "character ${i}, value ${commandBytes[i]}"
code += (char) commandBytes[i]
}
}
if (logEnable) log.debug "Entry control: ${ecn} keycache: ${code}"
switch (ecn.eventType) {
case 5: // Away Mode Button
if (logEnable) log.debug "In case 5 - Away Mode Button"
if (validatePin(code) || instantArming) {
if(currentStatus == "disarmed") {
if (logEnable) log.debug "In case 5 - Passed - currentStatus: ${currentStatus}"
state.type="physical"
if (!state.keypadConfig.armAwayDelay) { state.keypadConfig.armAwayDelay = 0 }
if (evtInt) {
sendEvent(name:"armingIn", value: state.keypadConfig.armAwayDelay, data:[armMode: armingStates[0x0B].securityKeypadState, armCmd: armingStates[0x0B].hsmCmd], isStateChange:true) // Event HSM Subscribes too
} else {
// sendEvent(name:"armingIn", value: state.keypadConfig.armAwayDelay, data:[armMode: armingStates[0x0B].securityKeypadState, armCmd: armingStates[0x0B].hsmCmd], isStateChange:true) // Event HSM Subscribes too
armAway(state.keypadConfig.armAwayDelay)
}
} else {
if (logEnable) log.debug "In case 5 - Failed - Please Disarm Alarm before changing alarm type - currentStatus: ${currentStatus}"
}
} else {
if (logEnable) log.debug "In case 5 - Failed - Invalid PIN - currentStatus: ${currentStatus}"
sendToDevice(zwave.indicatorV3.indicatorSet(indicatorCount:1, value: 0, indicatorValues:[[indicatorId:0x09, propertyId:2, value:0xFF]]).format())
}
break
case 6: // Home Mode Button
if (logEnable) log.debug "In case 6 - Home Mode Button"
if (validatePin(code) || instantArming) {
if(currentStatus == "disarmed") {
if (logEnable) log.debug "In case 6 - Passed"
state.type="physical"
if(!state.keypadConfig.partialFunction) state.keypadConfig.partialFunction="armHome"
if (state.keypadConfig.partialFunction == "armHome") {
if (logEnable) log.debug "In case 6 - Partial Passed"
if (!state.keypadConfig.armHomeDelay) { state.keypadConfig.armHomeDelay = 0 }
if (evtInt) {
sendEvent(name:"armingIn", value: state.keypadConfig.armHomeDelay, data:[armMode: armingStates[0x0A].securityKeypadState, armCmd: armingStates[0x0A].hsmCmd], isStateChange:true) // Event HSM Subscribes too
} else {
// sendEvent(name:"armingIn", value: state.keypadConfig.armHomeDelay, data:[armMode: armingStates[0x0A].securityKeypadState, armCmd: armingStates[0x0A].hsmCmd], isStateChange:true) // Event HSM Subscribes too
armHome(state.keypadConfig.armHomeDelay) //removed to prevent unneeded calls to HSMas the previous statement starts the physical action.
}
}
} else {
if(alarmStatus == "active") {
if (logEnable) log.debug "In case 6 - Silenced - Alarm will sound again in 10 seconds - currentStatus: ${currentStatus}"
changeStatus("silent")
runIn(10, changeStatus, [data:"active"])
} else {
if (logEnable) log.debug "In case 6 - Failed - Please Disarm Alarm before changing alarm type - currentStatus: ${currentStatus}"
}
}
} else {
if (logEnable) log.debug "In case 6 - Home Mode Failed - Invalid PIN - currentStatus: ${currentStatus}"
sendToDevice(zwave.indicatorV3.indicatorSet(indicatorCount:1, value: 0, indicatorValues:[[indicatorId:0x09, propertyId:2, value:0xFF]]).format())
}
break
case 3: // Disarm Mode Button
if (logEnable) log.debug "In case 3 - Disarm Mode Button"
if (validatePin(code)) {
if (logEnable) log.debug "In case 3 - Code Passed"
state.type="physical"
if (evtInt) {
sendEvent(name:"armingIn", value: 0, data:[armMode: armingStates[0x02].securityKeypadState, armCmd: armingStates[0x02].hsmCmd], isStateChange:true) // Event HSM Subscribes to
keypadUpdateStatus(0x02, state.type, state.code) // Sends status to Keypad to move it to disarmed
Date now = new Date()
sendEvent(name:"alarmStatusChangeTime", value: "${now}", isStateChange:true)
long ems = now.getTime()
sendEvent(name:"alarmStatusChangeEpochms", value: "${ems}", isStateChange:true)
changeStatus("off")
state.armingIn = 0
unschedule(armHomeEnd)
unschedule(armAwayEnd)
unschedule(changeStatus)
} else {
// sendEvent(name:"armingIn", value: 0, data:[armMode: armingStates[0x02].securityKeypadState, armCmd: armingStates[0x02].hsmCmd], isStateChange:true)
// keypadUpdateStatus(0x02, state.type, state.code) // Sends status to Keypad to move it to disarmed
disarm() //removed to prevent unneeded calls to HSMas the previous statement starts the physical action.
}
} else {
if (logEnable) log.debug "In case 3 - Disarm Failed - Invalid PIN - currentStatus: ${currentStatus}"
sendToDevice(zwave.indicatorV3.indicatorSet(indicatorCount:1, value: 0, indicatorValues:[[indicatorId:0x09, propertyId:2, value:0xFF]]).format())
}
break
// Added all buttons
case 2: // Code sent after hitting the Check Mark
state.type="physical"
Date now = new Date()
long ems = now.getTime()
if(!code) code = "check mark"
if (validateCheck) {
if (validatePin(code)) {
if (logEnable) log.debug "In case 2 (check mark) - Code Passed"
} else {
if (logEnable) log.debug "In case 2 (check mark) - Code Failed - Invalid PIN - currentStatus: ${currentStatus}"
sendToDevice(zwave.indicatorV3.indicatorSet(indicatorCount:1, value: 0, indicatorValues:[[indicatorId:0x09, propertyId:2, value:0xFF]]).format())
}
} else {
sendEvent(name:"lastCodeName", value: "${code}", isStateChange:true)
sendEvent(name:"lastCodeTime", value: "${now}", isStateChange:true)
sendEvent(name:"lastCodeEpochms", value: "${ems}", isStateChange:true)
}
break
case 17: // Police Button
state.type="physical"
Date now = new Date()
long ems = now.getTime()
sendEvent(name:"lastCodeName", value: "police", isStateChange:true)
sendEvent(name:"lastCodeTime", value: "${now}", isStateChange:true)
sendEvent(name:"lastCodeEpochms", value: "${ems}", isStateChange:true)
sendEvent(name: "held", value: 11, isStateChange: true)
break
case 16: // Fire Button
state.type="physical"
Date now = new Date()
long ems = now.getTime()
sendEvent(name:"lastCodeName", value: "fire", isStateChange:true)
sendEvent(name:"lastCodeTime", value: "${now}", isStateChange:true)
sendEvent(name:"lastCodeEpochms", value: "${ems}", isStateChange:true)
sendEvent(name: "held", value: 12, isStateChange: true)
break
case 19: // Medical Button
state.type="physical"
Date now = new Date()
long ems = now.getTime()
sendEvent(name:"lastCodeName", value: "medical", isStateChange:true)
sendEvent(name:"lastCodeTime", value: "${now}", isStateChange:true)
sendEvent(name:"lastCodeEpochms", value: "${ems}", isStateChange:true)
sendEvent(name: "held", value: 13, isStateChange: true)
break
case 1: // Button pressed or held, idle timeout reached without explicit submission
state.type="physical"
handleButtons(code)
break
}
}
}
void handleButtons(String code) {
List buttons = code.split('')
for (String btn : buttons) {
try {
int val = Integer.parseInt(btn)
sendEvent(name: "pushed", value: val, isStateChange: true)
} catch (NumberFormatException e) {
// Handle button holds here
char ch = btn
char a = 'A'
int pos = ch - a + 1
sendEvent(name: "held", value: pos, isStateChange: true)
}
}
}
void push(btn) {
state.type = "digital"
sendEvent(name: "pushed", value: btn, isStateChange: true)
}
void hold(btn) {
state.type = "digital"
sendEvent(name: "held", value: btn, isStateChange:true)
switch (btn) {
case 11:
Date now = new Date()
long ems = now.getTime()
sendEvent(name:"lastCodeName", value: "police", isStateChange:true)
sendEvent(name:"lastCodeTime", value: "${now}", isStateChange:true)
sendEvent(name:"lastCodeEpochms", value: "${ems}", isStateChange:true)
break
case 12:
Date now = new Date()
long ems = now.getTime()
sendEvent(name:"lastCodeName", value: "fire", isStateChange:true)
sendEvent(name:"lastCodeTime", value: "${now}", isStateChange:true)
sendEvent(name:"lastCodeEpochms", value: "${ems}", isStateChange:true)
break
case 13:
Date now = new Date()
long ems = now.getTime()
sendEvent(name:"lastCodeName", value: "medical", isStateChange:true)
sendEvent(name:"lastCodeTime", value: "${now}", isStateChange:true)
sendEvent(name:"lastCodeEpochms", value: "${ems}", isStateChange:true)
break
}
}
void zwaveEvent(hubitat.zwave.commands.notificationv8.NotificationReport cmd) {
Map evt = [:]
if (cmd.notificationType == 8) {
// power management
switch (cmd.event) {
case 1:
// Power has been applied
if (txtEnable) log.info "${device.displayName} Power has been applied"
break
case 2:
// AC mains disconnected
evt.name = "powerSource"
evt.value = "battery"
evt.descriptionText = "${device.displayName} AC mains disconnected"
eventProcess(evt)
break
case 3:
// AC mains re-connected
evt.name = "powerSource"
evt.value = "mains"
evt.descriptionText = "${device.displayName} AC mains re-connected"
eventProcess(evt)
break
case 12:
// battery is charging
if (txtEnable) log.info "${device.displayName} Battery is charging"
break
}
}
}
void entry(){
int intDelay = state.keypadConfig.entryDelay ? state.keypadConfig.entryDelay.toInteger() : 0
if (intDelay) entry(intDelay)
}
void entry(entranceDelay){
if (logEnable) log.debug "In entry (${version()}) - delay: ${entranceDelay}"
if (entranceDelay) {
sendToDevice(zwave.indicatorV3.indicatorSet(indicatorCount:1, value: 0, indicatorValues:[[indicatorId:0x11, propertyId:7, value:entranceDelay.toInteger()]]).format())
}
}
void getCodes(){
if (logEnable) log.debug "getCodes()"
updateEncryption()
}
private updateEncryption(){
String lockCodes = device.currentValue("lockCodes") //encrypted or decrypted
if (lockCodes){
if (optEncrypt && lockCodes[0] == "{") { //resend encrypted
sendEvent(name:"lockCodes",value: encrypt(lockCodes), isStateChange:true)
} else if (!optEncrypt && lockCodes[0] != "{") { //resend decrypted
sendEvent(name:"lockCodes", value: decrypt(lockCodes), isStateChange:true)
} else {
sendEvent(name:"lockCodes", value: lockCodes, isStateChange:true)
}
}
}
private Boolean validatePin(String pincode) {
boolean retVal = false
Map lockcodes = [:]
if (optEncrypt) {
try {
lockcodes = parseJson(decrypt(device.currentValue("lockCodes")))
} catch(e) {
log.warn "Ring Alarm Keypad G2 Community - No lock codes found."
}
} else {
try {
lockcodes = parseJson(device.currentValue("lockCodes"))
} catch(e) {
log.warn "Ring Alarm Keypad G2 Community - No lock codes found."
}
}
//log.debug "Lock codes: ${lockcodes}"
if(lockcodes) {
lockcodes.each {
if(it.value["code"] == pincode) {
Date now = new Date()
long ems = now.getTime()
//log.debug "found code: ${pincode} user: ${it.value['name']}"
sendEvent(name:"validCode", value: "true", isStateChange: true)
sendEvent(name:"lastCodeName", value: "${it.value['name']}", isStateChange:true)
sendEvent(name:"lastCodeTime", value: "${now}", isStateChange:true)
sendEvent(name:"lastCodeEpochms", value: "${ems}", isStateChange:true)
retVal=true
String code = JsonOutput.toJson(["${it.key}":["name": "${it.value.name}", "code": "${it.value.code}", "isInitiator": true]])
if (optEncrypt) {
state.code=encrypt(code)
} else {
state.code=code
}
}
}
}
if (!retVal) {
sendEvent(name:"validCode", value: "false", isStateChange: true)
}
return retVal
}
void setCode(codeposition, pincode, name) {
if (logEnable) log.debug "setCode(${codeposition}, ${pincode}, ${name})"
boolean newCode = true
Map lockcodes = [:]
if (device.currentValue("lockCodes") != null) {
if (optEncrypt) {
lockcodes = parseJson(decrypt(device.currentValue("lockCodes")))
} else {
lockcodes = parseJson(device.currentValue("lockCodes"))
}
}
if (lockcodes["${codeposition}"]) { newCode = false }
lockcodes["${codeposition}"] = ["code": "${pincode}", "name": "${name}"]
if (optEncrypt) {
sendEvent(name: "lockCodes", value: encrypt(JsonOutput.toJson(lockcodes)))
} else {
sendEvent(name: "lockCodes", value: JsonOutput.toJson(lockcodes), isStateChange: true)
}
if (newCode) {
sendEvent(name: "codeChanged", value:"added")
} else {
sendEvent(name: "codeChanged", value: "changed")
}
//log.debug "Lock codes: ${lockcodes}"
}
void deleteCode(codeposition) {
if (logEnable) log.debug "deleteCode(${codeposition})"
Map lockcodes=[:]
if (device.currentValue("lockCodes") != null) {
if (optEncrypt) {
lockcodes = parseJson(decrypt(device.currentValue("lockCodes")))
} else {
lockcodes = parseJson(device.currentValue("lockCodes"))
}
}
lockcodes["${codeposition}"] = [:]
lockcodes.remove("${codeposition}")
if (optEncrypt) {
sendEvent(name: "lockCodes", value: encrypt(JsonOutput.toJson(lockcodes)))
} else {
sendEvent(name: "lockCodes", value: JsonOutput.toJson(lockcodes), isStateChange: true)
}
sendEvent(name: "codeChanged", value: "deleted")
//log.debug "remove ${codeposition} Lock codes: ${lockcodes}"
}
void zwaveEvent(hubitat.zwave.commands.indicatorv3.IndicatorReport cmd) {
// Don't need to handle reports
}
// standard config
List runConfigs() {
List cmds = []
configParams.each { param, data ->
if (settings[data.input.name]) {
cmds.addAll(configCmd(param, data.parameterSize, settings[data.input.name]))
}
}
return cmds
}
List pollConfigs() {
List cmds = []
configParams.each { param, data ->
if (settings[data.input.name]) {
cmds.add(zwave.configurationV1.configurationGet(parameterNumber: param.toInteger()).format())
}
}
return cmds
}
List configCmd(parameterNumber, size, scaledConfigurationValue) {
List cmds = []
cmds.add(zwave.configurationV1.configurationSet(parameterNumber: parameterNumber.toInteger(), size: size.toInteger(), scaledConfigurationValue: scaledConfigurationValue.toInteger()).format())
cmds.add(zwave.configurationV1.configurationGet(parameterNumber: parameterNumber.toInteger()).format())
return cmds
}
void zwaveEvent(hubitat.zwave.commands.configurationv1.ConfigurationReport cmd) {
if(configParams[cmd.parameterNumber.toInteger()]) {
Map configParam = configParams[cmd.parameterNumber.toInteger()]
int scaledValue
cmd.configurationValue.reverse().eachWithIndex { v, index ->
scaledValue = scaledValue | v << (8 * index)
}
device.updateSetting(configParam.input.name, [value: "${scaledValue}", type: configParam.input.type])
}
}
// Battery v1
void zwaveEvent(hubitat.zwave.commands.batteryv1.BatteryReport cmd) {
Map evt = [name: "battery", unit: "%"]
if (cmd.batteryLevel == 0xFF) {
evt.descriptionText = "${device.displayName} has a low battery"
evt.value = 1
} else {
evt.value = cmd.batteryLevel
evt.descriptionText = "${device.displayName} battery is ${evt.value}${evt.unit}"
}
evt.isStateChange = true
if (txtEnable && evt.descriptionText) log.info evt.descriptionText
sendEvent(evt)
}
// MSP V2
void zwaveEvent(hubitat.zwave.commands.manufacturerspecificv2.DeviceSpecificReport cmd) {
if (logEnable) log.debug "Device Specific Report - DeviceIdType: ${cmd.deviceIdType}, DeviceIdFormat: ${cmd.deviceIdDataFormat}, Data: ${cmd.deviceIdData}"
if (cmd.deviceIdType == 1) {
String serialNumber = ""
if (cmd.deviceIdDataFormat == 1) {
cmd.deviceIdData.each { serialNumber += hubitat.helper.HexUtils.integerToHexString(it & 0xff,1).padLeft(2, '0')}
} else {
cmd.deviceIdData.each { serialNumber += (char) it }
}
device.updateDataValue("serialNumber", serialNumber)
}
}
// Version V2
void zwaveEvent(hubitat.zwave.commands.versionv3.VersionReport cmd) {
Double firmware0Version = cmd.firmware0Version + (cmd.firmware0SubVersion / 100)
Double protocolVersion = cmd.zWaveProtocolVersion + (cmd.zWaveProtocolSubVersion / 100)
if (logEnable) log.debug "Version Report - FirmwareVersion: ${firmware0Version}, ProtocolVersion: ${protocolVersion}, HardwareVersion: ${cmd.hardwareVersion}"
device.updateDataValue("firmwareVersion", "${firmware0Version}")
device.updateDataValue("protocolVersion", "${protocolVersion}")
device.updateDataValue("hardwareVersion", "${cmd.hardwareVersion}")
if (cmd.firmwareTargets > 0) {
cmd.targetVersions.each { target ->
Double targetVersion = target.version + (target.subVersion / 100)
device.updateDataValue("firmware${target.target}Version", "${targetVersion}")
}
}
}
// Association V2
List setDefaultAssociation() {
List cmds = []
cmds.add(zwave.associationV2.associationSet(groupingIdentifier: 1, nodeId: zwaveHubNodeId).format())
cmds.add(zwave.associationV2.associationGet(groupingIdentifier: 1).format())
return cmds
}
List processAssociations(){
List cmds = []
cmds.addAll(setDefaultAssociation())
return cmds
}
void zwaveEvent(hubitat.zwave.commands.associationv2.AssociationReport cmd) {
List temp = []
if (cmd.nodeId != []) {
cmd.nodeId.each {
temp.add(it.toString().format( '%02x', it.toInteger() ).toUpperCase())
}
}
if (logEnable) log.debug "Association Report - Group: ${cmd.groupingIdentifier}, Nodes: $temp"
}
// event filter
void eventProcess(Map evt) {
if (txtEnable && evt.descriptionText) log.info evt.descriptionText
if (device.currentValue(evt.name).toString() != evt.value.toString()) {
sendEvent(evt)
}
}
// universal
void zwaveEvent(hubitat.zwave.Command cmd) {
if (logEnable) log.debug "skip:${cmd}"
}
void zwaveEvent(hubitat.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
hubitat.zwave.Command encapsulatedCommand = cmd.encapsulatedCommand(CMD_CLASS_VERS)
if (encapsulatedCommand) {
zwaveEvent(encapsulatedCommand)
}
}
void zwaveEvent(hubitat.zwave.commands.supervisionv1.SupervisionGet cmd) {
if (logEnable) log.debug "Supervision Get - SessionID: ${cmd.sessionID}, CC: ${cmd.commandClassIdentifier}, Command: ${cmd.commandIdentifier}"
if (cmd.commandClassIdentifier == 0x6F) {
parseEntryControl(cmd.commandIdentifier, cmd.commandByte)
} else {
hubitat.zwave.Command encapsulatedCommand = cmd.encapsulatedCommand(CMD_CLASS_VERS)
if (encapsulatedCommand) {
zwaveEvent(encapsulatedCommand)
}
}
// device quirk requires this to be unsecure reply
sendToDevice(zwave.supervisionV1.supervisionReport(sessionID: cmd.sessionID, reserved: 0, moreStatusUpdates: false, status: 0xFF, duration: 0).format())
}
void parse(String description) {
if (logEnable) log.debug "parse - ${description}"
ver = getDataValue("firmwareVersion")
if(ver >= "1.18") {
if(description.contains("6C01") && description.contains("FF 07 08 00")) {
sendEvent(name:"motion", value: "active", isStateChange:true)
} else if(description.contains("6C01") && description.contains("FF 07 00 01 08")) {
sendEvent(name:"motion", value: "inactive", isStateChange:true)
}
}
hubitat.zwave.Command cmd = zwave.parse(description, CMD_CLASS_VERS)
if (cmd) {
zwaveEvent(cmd)
}
}
void sendToDevice(List cmds, Long delay=300) {
sendHubCommand(new hubitat.device.HubMultiAction(commands(cmds, delay), hubitat.device.Protocol.ZWAVE))
}
void sendToDevice(String cmd, Long delay=300) {
sendHubCommand(new hubitat.device.HubAction(zwaveSecureEncap(cmd), hubitat.device.Protocol.ZWAVE))
}
List commands(List cmds, Long delay=300) {
return delayBetween(cmds.collect{ zwaveSecureEncap(it) }, delay)
}
void proximitySensorHandler() {
if(proximitySensor) {
if (logEnable) log.debug "Turning the Proximity Sensor OFF"
sendToDevice(new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber: 15, size: 1, scaledConfigurationValue: 0).format())
} else {
if (logEnable) log.debug "Turning the Proximity Sensor ON"
sendToDevice(new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber: 15, size: 1, scaledConfigurationValue: 1).format())
}
}
/*
def keyBacklightBrightness(newVol=null) {
if(newVol) {
def currentVol = device.currentValue('keyBacklightBrightness')
if(newVol.toString() == currentVol.toString()) {
if (logEnable) log.debug "Key Backlight Brightness hasn't changed, so skipping"
} else {
if (logEnable) log.debug "Setting the Key Backlight Brightness to $newVol"
nVol = newVol.toInteger()
sendToDevice(new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber: 13, size: 1, scaledConfigurationValue: nVol).format())
sendEvent(name:"keyBacklightBrightness", value: newVol, isStateChange:true)
}
} else {
if (logEnable) log.debug "Key Backlight Brightness value not specified, so skipping"
}
}
*/
def volAnnouncement(newVol=null) {
if (logEnable) log.debug "In volAnnouncement (${version()}) - newVol: ${newVol}"
if(newVol) {
def currentVol = device.currentValue('volAnnouncement')
if(newVol.toString() == currentVol.toString()) {
if (logEnable) log.debug "Announcement Volume hasn't changed, so skipping"
} else {
if (logEnable) log.debug "Setting the Announcement Volume to $newVol"
nVol = newVol.toInteger()
sendToDevice(new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber: 4, size: 1, scaledConfigurationValue: nVol).format())
sendEvent(name:"volAnnouncement", value: newVol, isStateChange:true)
}
} else {
if (logEnable) log.debug "Announcement value not specified, so skipping"
}
}
def volKeytone(newVol=null) {
if (logEnable) log.debug "In volKeytone (${version()}) - newVol: ${newVol}"
if(newVol) {
def currentVol = device.currentValue('volKeytone')
if(newVol.toString() == currentVol.toString()) {
if (logEnable) log.debug "Keytone Volume hasn't changed, so skipping"
} else {
if (logEnable) log.debug "Setting the Keytone Volume to $newVol"
nVol = newVol.toInteger()
sendToDevice(new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber: 5, size: 1, scaledConfigurationValue: nVol).format())
sendEvent(name:"volKeytone", value: newVol, isStateChange:true)
}
} else {
if (logEnable) log.debug "Keytone value not specified, so skipping"
}
}
def volSiren(newVol=null) {
if (logEnable) log.debug "In volSiren (${version()}) - newVol: ${newVol}"
if(newVol) {
def currentVol = device.currentValue('volSiren')
if(newVol.toString() == currentVol.toString()) {
if (logEnable) log.debug "Siren Volume hasn't changed, so skipping"
def sVol = currentVol.toInteger() * 10
} else {
if (logEnable) log.debug "Setting the Siren Volume to $newVol"
sVol = newVol.toInteger() * 10
sendToDevice(new hubitat.zwave.commands.configurationv1.ConfigurationSet(parameterNumber: 6, size: 1, scaledConfigurationValue: sVol).format())
sendEvent(name:"volSiren", value: newVol, isStateChange:true)
}
} else {
def currentVol = device.currentValue('volSiren')
if(currentVol) {
sVol = currentVol.toInteger() * 10
} else {
sVol = 90
}
}
return sVol
}
def playTone(tone=null) {
volSiren()
if (logEnable) log.debug "In playTone (${version()}) - tone: ${tone} at Volume: ${sVol}"
if(!tone) {
tone = theTone
if (logEnable) log.debug "In playTone - Tone is NULL, so setting tone to theTone: ${tone}"
}
if(tone == "Tone_1") {
if (logEnable) log.debug "In playTone - Tone 1" // Siren
changeStatus("active")
sendToDevice(zwave.indicatorV3.indicatorSet(indicatorCount:1, value: 0, indicatorValues:[[indicatorId:0x0C, propertyId:2, value:sVol]]).format())
} else if(tone == "Tone_2") {
if (logEnable) log.debug "In playTone - Tone 2" // 3 chirps
changeStatus("active")
sendToDevice(zwave.indicatorV3.indicatorSet(indicatorCount:1, value: 0, indicatorValues:[[indicatorId:0x0E, propertyId:2, value:sVol]]).format())
} else if(tone == "Tone_3") {
if (logEnable) log.debug "In playTone - Tone 3" // 4 chirps
changeStatus("active")
sendToDevice(zwave.indicatorV3.indicatorSet(indicatorCount:1, value: 0, indicatorValues:[[indicatorId:0x0F, propertyId:2, value:sVol]]).format())
} else if(tone == "Tone_4") {
if (logEnable) log.debug "In playTone - Tone 4" // Navi
changeStatus("active")
sendToDevice(zwave.indicatorV3.indicatorSet(indicatorCount:1, value: 0, indicatorValues:[[indicatorId:0x60, propertyId:0x09, value:sVol]]).format())
} else if(tone == "Tone_5") {
if (logEnable) log.debug "In playTone - Tone 5" // Guitar
changeStatus("active")
sendToDevice(zwave.indicatorV3.indicatorSet(indicatorCount:1, value: 0, indicatorValues:[[indicatorId:0x61, propertyId:0x09, value:sVol]]).format())
} else if(tone == "Tone_6") {
if (logEnable) log.debug "In playTone - Tone 6" // Windchimes
changeStatus("active")
sendToDevice(zwave.indicatorV3.indicatorSet(indicatorCount:1, value: 0, indicatorValues:[[indicatorId:0x62, propertyId:0x09, value:sVol]]).format())
} else if(tone == "Tone_7") {
if (logEnable) log.debug "In playTone - Tone 7" // Doorbell 1
changeStatus("active")
sendToDevice(zwave.indicatorV3.indicatorSet(indicatorCount:1, value: 0, indicatorValues:[[indicatorId:0x63, propertyId:0x09, value:sVol]]).format())
} else if(tone == "Tone_8") {
if (logEnable) log.debug "In playTone - Tone 8" // Doorbell 2
changeStatus("active")
sendToDevice(zwave.indicatorV3.indicatorSet(indicatorCount:1, value: 0, indicatorValues:[[indicatorId:0x64, propertyId:0x09, value:sVol]]).format())
} else if(tone == "Tone_9") {
if (logEnable) log.debug "In playTone - Tone 9" // Invalid Code Sound
changeStatus("active")
sendToDevice(zwave.indicatorV3.indicatorSet(indicatorCount:1, value: 0, indicatorValues:[[indicatorId:0x09, propertyId:0x01, value:sVol]]).format())
} else if(tone == "test") {
if (logEnable) log.debug "In playTone - test" // test
changeStatus("active")
//sendToDevice(zwave.indicatorV3.indicatorSet(indicatorCount:1, value: 0, indicatorValues:[[indicatorId:0x61, propertyId:0x09, value:0xFF]]).format())
//pauseExecution(5000)
sendToDevice(zwave.indicatorV3.indicatorSet(indicatorCount:1, value: 0, indicatorValues:[[indicatorId:0x61, propertyId:0x09, value:sVol]]).format())
}
}