Compare commits

...

1 Commits

Author SHA1 Message Date
Nowak
215878ddc1 MSA-972: Updated Device Handler for Fibaro Smoke Sensor:
- updated tamper attrbiute,
- removed unused smoke/heat alarm events/states,
- updated tiles,
- corrected parameter values in preferences,
- added handling for more notifications (replace battery soon, system hardware failure),
- added Sensor Alarm Report handling and Sensor Alarm Get on wake up,
- added handling for received CRC16 frames,
- improved sent frame encapsulation (CRC16/Security)
2016-03-21 04:10:27 -05:00

View File

@@ -18,9 +18,10 @@ metadata {
capability "Sensor" capability "Sensor"
capability "Smoke Detector" //attributes: smoke ("detected","clear","tested") capability "Smoke Detector" //attributes: smoke ("detected","clear","tested")
capability "Temperature Measurement" //attributes: temperature capability "Temperature Measurement" //attributes: temperature
attribute "tamper", "enum", ["detected", "clear"] attribute "tamper", "enum", ["active", "inactive"]//capability "Tamper Alert"// <- yields "java.lang.RuntimeException: Metadata Error: Capability 'Tamper Alert' not found" error
attribute "heatAlarm", "enum", ["overheat detected", "clear", "rapid temperature rise", "underheat detected"] attribute "heatAlarm", "enum", ["overheat", "inactive"]
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x86, 0x72, 0x5A, 0x59, 0x85, 0x73, 0x84, 0x80, 0x71, 0x56, 0x70, 0x31, 0x8E, 0x22, 0x9C, 0x98, 0x7A", outClusters: "0x20, 0x8B" fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x86, 0x72, 0x5A, 0x59, 0x85, 0x73, 0x84, 0x80, 0x71, 0x56, 0x70, 0x31, 0x8E, 0x22, 0x9C, 0x98, 0x7A", outClusters: "0x20, 0x8B"
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x86, 0x72, 0x5A, 0x59, 0x85, 0x73, 0x84, 0x80, 0x71, 0x56, 0x70, 0x31, 0x8E, 0x22, 0x9C, 0x98, 0x7A"
} }
simulator { simulator {
//battery //battery
@@ -50,7 +51,7 @@ metadata {
input description: "Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings", input description: "Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings",
title: "Advanced Configuration", displayDuringSetup: true, type: "paragraph", element: "paragraph" title: "Advanced Configuration", displayDuringSetup: true, type: "paragraph", element: "paragraph"
input "smokeSensorSensitivity", "enum", title: "Smoke Sensor Sensitivity", options: ["High","Medium","Low"], defaultValue: "${smokeSensorSensitivity}", displayDuringSetup: true input "smokeSensorSensitivity", "enum", title: "Smoke Sensor Sensitivity", options: ["High","Medium","Low"], defaultValue: "${smokeSensorSensitivity}", displayDuringSetup: true
input "zwaveNotificationStatus", "enum", title: "Notifications Status", options: ["disabled","casing opened","exceeding temperature threshold", "lack of Z-Wave range", "all notifications"], input "zwaveNotificationStatus", "enum", title: "Notifications Status", options: ["disabled","casing opened","exceeding temperature threshold","all notifications"],
defaultValue: "${zwaveNotificationStatus}", displayDuringSetup: true defaultValue: "${zwaveNotificationStatus}", displayDuringSetup: true
input "visualIndicatorNotificationStatus", "enum", title: "Visual Indicator Notifications Status", input "visualIndicatorNotificationStatus", "enum", title: "Visual Indicator Notifications Status",
options: ["disabled","casing opened","exceeding temperature threshold", "lack of Z-Wave range", "all notifications"], options: ["disabled","casing opened","exceeding temperature threshold", "lack of Z-Wave range", "all notifications"],
@@ -61,44 +62,47 @@ metadata {
input "temperatureReportInterval", "enum", title: "Temperature Report Interval", input "temperatureReportInterval", "enum", title: "Temperature Report Interval",
options: ["reports inactive", "5 minutes", "15 minutes", "30 minutes", "1 hour", "6 hours", "12 hours", "18 hours", "24 hours"], defaultValue: "${temperatureReportInterval}", displayDuringSetup: true options: ["reports inactive", "5 minutes", "15 minutes", "30 minutes", "1 hour", "6 hours", "12 hours", "18 hours", "24 hours"], defaultValue: "${temperatureReportInterval}", displayDuringSetup: true
input "temperatureReportHysteresis", "number", title: "Temperature Report Hysteresis", description: "Available settings: 1-100 C", range: "1..100", displayDuringSetup: true input "temperatureReportHysteresis", "number", title: "Temperature Report Hysteresis", description: "Available settings: 1-100 C", range: "1..100", displayDuringSetup: true
input "temperatureThreshold", "number", title: "Overheat Temperature Threshold", description: "Available settings: 0 or 2-100 C", range: "0..100", displayDuringSetup: true input "temperatureThreshold", "number", title: "Overheat Temperature Threshold", description: "Available settings: 1-100 C", range: "1..100", displayDuringSetup: true
input "excessTemperatureSignalingInterval", "enum", title: "Excess Temperature Signaling Interval", input "excessTemperatureSignalingInterval", "enum", title: "Excess Temperature Signaling Interval",
options: ["5 minutes", "15 minutes", "30 minutes", "1 hour", "6 hours", "12 hours", "18 hours", "24 hours"], defaultValue: "${excessTemperatureSignalingInterval}", displayDuringSetup: true options: ["5 minutes", "15 minutes", "30 minutes", "1 hour", "6 hours", "12 hours", "18 hours", "24 hours"], defaultValue: "${excessTemperatureSignalingInterval}", displayDuringSetup: true
input "lackOfZwaveRangeIndicationInterval", "enum", title: "Lack of Z-Wave Range Indication Interval", input "lackOfZwaveRangeIndicationInterval", "enum", title: "Lack of Z-Wave Range Indication Interval",
options: ["5 minutes", "15 minutes", "30 minutes", "1 hour", "6 hours", "12 hours", "18 hours", "24 hours"], defaultValue: "${lackOfZwaveRangeIndicationInterval}", displayDuringSetup: true options: ["5 minutes", "15 minutes", "30 minutes", "1 hour", "6 hours", "12 hours", "18 hours", "24 hours"], defaultValue: "${lackOfZwaveRangeIndicationInterval}", displayDuringSetup: true
} }
tiles (scale: 2){ tiles (scale: 2){
multiAttributeTile(name:"smoke", type: "lighting", width: 6, height: 4){ multiAttributeTile(name:"FGSD", type: "lighting", width: 6, height: 4){
tileAttribute ("device.smoke", key: "PRIMARY_CONTROL") { tileAttribute ("device.smoke", key: "PRIMARY_CONTROL") {
attributeState("clear", label:"CLEAR", icon:"st.alarm.smoke.clear", backgroundColor:"#ffffff") attributeState("clear", label:"CLEAR", icon:"st.alarm.smoke.clear", backgroundColor:"#ffffff")
attributeState("detected", label:"SMOKE", icon:"st.alarm.smoke.smoke", backgroundColor:"#e86d13") attributeState("detected", label:"SMOKE", icon:"st.alarm.smoke.smoke", backgroundColor:"#e86d13")
attributeState("tested", label:"TEST", icon:"st.alarm.smoke.test", backgroundColor:"#e86d13") attributeState("tested", label:"TEST", icon:"st.alarm.smoke.test", backgroundColor:"#e86d13")
attributeState("replacement required", label:"REPLACE", icon:"st.alarm.smoke.test", backgroundColor:"#FFFF66")
attributeState("unknown", label:"UNKNOWN", icon:"st.alarm.smoke.test", backgroundColor:"#ffffff") attributeState("unknown", label:"UNKNOWN", icon:"st.alarm.smoke.test", backgroundColor:"#ffffff")
} }
tileAttribute ("device.battery", key: "SECONDARY_CONTROL") { tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
attributeState "battery", label:'Battery: ${currentValue}%', unit:"%" attributeState("active", label:'tamper active', backgroundColor:"#53a7c0")
} attributeState("inactive", label:'tamper inactive', backgroundColor:"#ffffff")
}
} }
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "battery", label:'${currentValue}% battery', unit:"%" state "battery", label:'${currentValue}% battery', unit:"%"
} }
valueTile("temperature", "device.temperature", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {
state "temperature", label:'${currentValue}°', unit:"C" state "temperature", label:'${currentValue}°',
} backgroundColors:[
valueTile("heatAlarm", "device.heatAlarm", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { [value: 31, color: "#153591"],
state "clear", label:'TEMPERATURE OK', backgroundColor:"#ffffff" [value: 44, color: "#1e9cbb"],
state "overheat detected", label:'OVERHEAT DETECTED', backgroundColor:"#ffffff" [value: 59, color: "#90d2a7"],
state "rapid temperature rise", label:'RAPID TEMP RISE', backgroundColor:"#ffffff" [value: 74, color: "#44b621"],
state "underheat detected", label:'UNDERHEAT DETECTED', backgroundColor:"#ffffff" [value: 84, color: "#f1d801"],
} [value: 95, color: "#d04e00"],
valueTile("tamper", "device.tamper", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { [value: 96, color: "#bc2323"]
state "clear", label:'NO TAMPER', backgroundColor:"#ffffff" ]
state "detected", label:'TAMPER DETECTED', backgroundColor:"#ffffff" }
valueTile("heatAlarm", "device.heatAlarm", inactiveLabel: false, width: 2, height: 2) {
state "inactive", label:'TEMPERATURE OK', backgroundColor:"#ffffff"
state "overheat", label:'OVERHEAT DETECTED', backgroundColor:"#bc2323"
} }
main "smoke" main "FGSD"
details(["smoke","temperature"]) details(["FGSD","temperature", "battery", "heatAlarm"])
} }
} }
@@ -117,7 +121,7 @@ def parse(String description) {
"If you are unable to control it via SmartThings, you must remove it from your network and add it again.") "If you are unable to control it via SmartThings, you must remove it from your network and add it again.")
} else if (description != "updated") { } else if (description != "updated") {
log.debug "parse() >> zwave.parse(description)" log.debug "parse() >> zwave.parse(description)"
def cmd = zwave.parse(description, [0x31: 5, 0x71: 3, 0x84: 1]) def cmd = zwave.parse(description, [0x31: 5, 0x5A: 1, 0x71: 3, 0x72: 2, 0x84: 1, 0x86: 1, 0x8B: 1, 0x9C: 1])
if (cmd) { if (cmd) {
result = zwaveEvent(cmd) result = zwaveEvent(cmd)
} }
@@ -126,14 +130,40 @@ def parse(String description) {
return result return result
} }
def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { //security
log.info "Executing zwaveEvent 86 (VersionV1): 12 (VersionReport) with cmd: $cmd" def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
def fw = "${cmd.applicationVersion}.${cmd.applicationSubVersion}" setSecured()
updateDataValue("fw", fw) def encapsulatedCommand = cmd.encapsulatedCommand([0x31: 5, 0x5A: 1, 0x71: 3, 0x84: 1, 0x9C: 1])
def text = "$device.displayName: firmware version: $fw, Z-Wave version: ${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}" if (encapsulatedCommand) {
createEvent(descriptionText: text, isStateChange: false) log.debug "command: 98 (Security) 81(SecurityMessageEncapsulation) encapsulatedCommand: $encapsulatedCommand"
zwaveEvent(encapsulatedCommand)
} else {
log.warn "Unable to extract encapsulated cmd from $cmd"
createEvent(descriptionText: cmd.toString())
}
} }
//crc16
def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd)
{
def versions = [0x31: 5, 0x72: 2, 0x86: 1, 0x8B: 1]
def version = versions[cmd.commandClass as Integer]
def ccObj = version ? zwave.commandClass(cmd.commandClass, version) : zwave.commandClass(cmd.commandClass)
def encapsulatedCommand = ccObj?.command(cmd.command)?.parse(cmd.data)
if (!encapsulatedCommand) {
log.debug "Could not extract command from $cmd"
} else {
zwaveEvent(encapsulatedCommand)
}
}
def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) {
log.info "Executing zwaveEvent 86 (VersionV1): 12 (VersionReport) with cmd: $cmd"
def version = "${cmd.applicationVersion}.${cmd.applicationSubVersion}"
updateDataValue("version", fw)
def text = "$device.displayName: firmware version: $version, Z-Wave version: ${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}"
createEvent(descriptionText: text, isStateChange: false)
}
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
def map = [ name: "battery", unit: "%" ] def map = [ name: "battery", unit: "%" ]
@@ -161,18 +191,6 @@ def zwaveEvent(physicalgraph.zwave.commands.applicationstatusv1.ApplicationRejec
createEvent(displayed: true, descriptionText: "$device.displayName rejected the last request") createEvent(displayed: true, descriptionText: "$device.displayName rejected the last request")
} }
def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
setSecured()
def encapsulatedCommand = cmd.encapsulatedCommand([0x31: 5, 0x71: 3, 0x84: 1])
if (encapsulatedCommand) {
log.debug "command: 98 (Security) 81(SecurityMessageEncapsulation) encapsulatedCommand: $encapsulatedCommand"
zwaveEvent(encapsulatedCommand)
} else {
log.warn "Unable to extract encapsulated cmd from $cmd"
createEvent(descriptionText: cmd.toString())
}
}
def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) { def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) {
log.info "Executing zwaveEvent 98 (SecurityV1): 03 (SecurityCommandsSupportedReport) with cmd: $cmd" log.info "Executing zwaveEvent 98 (SecurityV1): 03 (SecurityCommandsSupportedReport) with cmd: $cmd"
setSecured() setSecured()
@@ -199,18 +217,31 @@ def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cm
if (cmd.notificationType == 7) { if (cmd.notificationType == 7) {
switch (cmd.event) { switch (cmd.event) {
case 0: case 0:
result << createEvent(name: "tamper", value: "clear", displayed: false) result << createEvent(name: "tamper", value: "inactive", displayed: false)
break break
case 3: case 3:
result << createEvent(name: "tamper", value: "detected", descriptionText: "$device.displayName casing was opened") result << createEvent(name: "tamper", value: "active", descriptionText: "$device.displayName casing was opened")
break break
} }
} else if (cmd.notificationType == 1) { //Smoke Alarm (V2) } else if (cmd.notificationType == 1) { //Smoke Alarm (V2)
log.debug "notificationv3.NotificationReport: for Smoke Alarm (V2)" log.debug "notificationv3.NotificationReport: for Smoke Alarm (V2)"
result << smokeAlarmEvent(cmd.event) result << smokeAlarmEvent(cmd.event)
} else if (cmd.notificationType == 4) { // Heat Alarm (V2) } else if (cmd.notificationType == 4) { // Heat Alarm (V2)
log.debug "notificationv3.NotificationReport: for Heat Alarm (V2)" log.debug "notificationv3.NotificationReport: for Heat Alarm (V2)"
result << heatAlarmEvent(cmd.event) result << heatAlarmEvent(cmd.event)
} else if (cmd.notificationType == 8) {
if (cmd.event == 0x0A) {
def map = [:]
map.name = "battery"
map.value = 1
map.unit = "%"
map.displayed = true
result << createEvent(map)
}
} else if (cmd.notificationType == 9) {
if (cmd.event == 0x01) {
result << createEvent(descriptionText: "Warning: $device.displayName system hardware failure", isStateChange: true)
}
} else { } else {
log.warn "Need to handle this cmd.notificationType: ${cmd.notificationType}" log.warn "Need to handle this cmd.notificationType: ${cmd.notificationType}"
result << createEvent(descriptionText: cmd.toString(), isStateChange: false) result << createEvent(descriptionText: cmd.toString(), isStateChange: false)
@@ -221,7 +252,7 @@ def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cm
def smokeAlarmEvent(value) { def smokeAlarmEvent(value) {
log.debug "smokeAlarmEvent(value): $value" log.debug "smokeAlarmEvent(value): $value"
def map = [name: "smoke"] def map = [name: "smoke"]
if (value == 1 || value == 2) { if (value == 2) {
map.value = "detected" map.value = "detected"
map.descriptionText = "$device.displayName detected smoke" map.descriptionText = "$device.displayName detected smoke"
} else if (value == 0) { } else if (value == 0) {
@@ -230,9 +261,6 @@ def smokeAlarmEvent(value) {
} else if (value == 3) { } else if (value == 3) {
map.value = "tested" map.value = "tested"
map.descriptionText = "$device.displayName smoke alarm test" map.descriptionText = "$device.displayName smoke alarm test"
} else if (value == 4) {
map.value = "replacement required"
map.descriptionText = "$device.displayName replacement required"
} else { } else {
map.value = "unknown" map.value = "unknown"
map.descriptionText = "$device.displayName unknown event" map.descriptionText = "$device.displayName unknown event"
@@ -243,18 +271,12 @@ def smokeAlarmEvent(value) {
def heatAlarmEvent(value) { def heatAlarmEvent(value) {
log.debug "heatAlarmEvent(value): $value" log.debug "heatAlarmEvent(value): $value"
def map = [name: "heatAlarm"] def map = [name: "heatAlarm"]
if (value == 1 || value == 2) { if (value == 2) {
map.value = "overheat detected" map.value = "overheat"
map.descriptionText = "$device.displayName overheat detected" map.descriptionText = "$device.displayName overheat detected"
} else if (value == 0) { } else if (value == 0) {
map.value = "clear" map.value = "inactive"
map.descriptionText = "$device.displayName heat alarm cleared (no overheat)" map.descriptionText = "$device.displayName heat alarm cleared (no overheat)"
} else if (value == 3 || value == 4) {
map.value = "rapid temperature rise"
map.descriptionText = "$device.displayName rapid temperature rise"
} else if (value == 5 || value == 6) {
map.value = "underheat detected"
map.descriptionText = "$device.displayName underheat detected"
} else { } else {
map.value = "unknown" map.value = "unknown"
map.descriptionText = "$device.displayName unknown event" map.descriptionText = "$device.displayName unknown event"
@@ -274,12 +296,14 @@ def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) {
//Only ask for battery if we haven't had a BatteryReport in a while //Only ask for battery if we haven't had a BatteryReport in a while
if (!state.lastbatt || (new Date().time) - state.lastbatt > 24*60*60*1000) { if (!state.lastbatt || (new Date().time) - state.lastbatt > 24*60*60*1000) {
log.debug("Device has been configured sending >> batteryGet()") log.debug("Device has been configured sending >> batteryGet()")
cmds << zwave.securityV1.securityMessageEncapsulation().encapsulate(zwave.batteryV1.batteryGet()).format() cmds << zwave.batteryV1.batteryGet()
cmds << "delay 1200"
} }
cmds << zwave.sensorAlarmV1.sensorAlarmGet(sensorType: 0)
cmds << zwave.sensorAlarmV1.sensorAlarmGet(sensorType: 1)
cmds << zwave.sensorAlarmV1.sensorAlarmGet(sensorType: 4)
log.debug("Device has been configured sending >> wakeUpNoMoreInformation()") log.debug("Device has been configured sending >> wakeUpNoMoreInformation()")
cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format() cmds << zwave.wakeUpV1.wakeUpNoMoreInformation()
result << response(cmds) //tell device back to sleep result << response(commands(cmds,500)) //tell device back to sleep
} }
result result
} }
@@ -317,8 +341,26 @@ def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerS
log.debug "After device is securely joined, send commands to update tiles" log.debug "After device is securely joined, send commands to update tiles"
result << zwave.batteryV1.batteryGet() result << zwave.batteryV1.batteryGet()
result << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x01) result << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x01)
result << zwave.wakeUpV1.wakeUpNoMoreInformation() //always send wakeUpNoMoreInformation as secure (at this point "secured" property is not set)
[[descriptionText:"${device.displayName} MSR report"], response(commands(result, 5000))] [[descriptionText:"${device.displayName} MSR report"], response(commands(result, 500) << "delay 1000" << secure(zwave.wakeUpV1.wakeUpNoMoreInformation()))]
}
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.DeviceSpecificReport cmd) {
log.debug "deviceIdData: ${cmd.deviceIdData}"
log.debug "deviceIdDataFormat: ${cmd.deviceIdDataFormat}"
log.debug "deviceIdDataLengthIndicator: ${cmd.deviceIdDataLengthIndicator}"
log.debug "deviceIdType: ${cmd.deviceIdType}"
if (cmd.deviceIdType == 1 && cmd.deviceIdDataFormat == 1) {//serial number in binary format
String serialNumber = "h'"
cmd.deviceIdData.each{ data ->
serialNumber += "${String.format("%02X", data)}"
}
updateDataValue("serialNumber", serialNumber)
log.debug "${device.displayName} - serial number: ${serialNumber}"
}
} }
def zwaveEvent(physicalgraph.zwave.commands.associationv2.AssociationReport cmd) { def zwaveEvent(physicalgraph.zwave.commands.associationv2.AssociationReport cmd) {
@@ -332,6 +374,37 @@ def zwaveEvent(physicalgraph.zwave.commands.associationv2.AssociationReport cmd)
result result
} }
def zwaveEvent(physicalgraph.zwave.commands.sensoralarmv1.SensorAlarmReport cmd) {
def map = [:]
switch (cmd.sensorType) {
case 0:
map.name = "tamper"
map.value = cmd.sensorState == 0xFF ? "active" : "inactive"
map.descriptionText = cmd.sensorState == 0xFF ? "$device.displayName casing was opened" : ""
break
case 1:
map.name = "smoke"
map.value = cmd.sensorState == 0xFF ? "detected" : "clear"
map.descriptionText = cmd.sensorState == 0xFF ? "$device.displayName detected smoke" : "$device.displayName is clear (no smoke)"
break
case 4:
map.name = "heatAlarm"
map.value = cmd.sensorState == 0xFF ? "overheat" : "inactive"
map.descriptionText = cmd.sensorState == 0xFF ? "$device.displayName overheat detected" : "$device.displayName heat alarm cleared (no overheat)"
break
}
createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.timeparametersv1.TimeParametersGet cmd) {
log.info "Executing zwaveEvent 8B (TimeParametersV1) : 02 (TimeParametersGet) with cmd: $cmd"
def nowCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"))
//Time Parameters are requested by an un-encapsulated frame
response(zwave.timeParametersV1.timeParametersReport(year: nowCal.get(Calendar.YEAR), month: (nowCal.get(Calendar.MONTH) + 1), day: nowCal.get(Calendar.DAY_OF_MONTH),
hourUtc: nowCal.get(Calendar.HOUR_OF_DAY), minuteUtc: nowCal.get(Calendar.MINUTE), secondUtc: nowCal.get(Calendar.SECOND)).format())
}
def zwaveEvent(physicalgraph.zwave.Command cmd) { def zwaveEvent(physicalgraph.zwave.Command cmd) {
log.warn "General zwaveEvent cmd: ${cmd}" log.warn "General zwaveEvent cmd: ${cmd}"
createEvent(descriptionText: cmd.toString(), isStateChange: false) createEvent(descriptionText: cmd.toString(), isStateChange: false)
@@ -360,7 +433,7 @@ def configure() {
} }
//3. Z-Wave notification status: 0-all disabled (default), 1-casing open enabled, 2-exceeding temp enable //3. Z-Wave notification status: 0-all disabled (default), 1-casing open enabled, 2-exceeding temp enable
if (zwaveNotificationStatus && zwaveNotificationStatus != "null"){ if (zwaveNotificationStatus && zwaveNotificationStatus != "null"){
request += zwave.configurationV1.configurationSet(parameterNumber: 2, size: 1, scaledConfigurationValue: notificationOptionValueMap[zwaveNotificationStatus] ?: 0) request += zwave.configurationV1.configurationSet(parameterNumber: 2, size: 1, scaledConfigurationValue: zwaveNotificationOptionValueMap[zwaveNotificationStatus] ?: 0)
} }
//4. Visual indicator notification status: 0-all disabled (default), 1-casing open enabled, 2-exceeding temp enable, 4-lack of range notification //4. Visual indicator notification status: 0-all disabled (default), 1-casing open enabled, 2-exceeding temp enable, 4-lack of range notification
if (visualIndicatorNotificationStatus && visualIndicatorNotificationStatus != "null") { if (visualIndicatorNotificationStatus && visualIndicatorNotificationStatus != "null") {
@@ -402,7 +475,16 @@ def configure() {
//12. get temperature reading from device //12. get temperature reading from device
request += zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x01) request += zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x01)
commands(request) + ["delay 10000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()] //13. set association group
request += zwave.associationV2.associationSet(groupingIdentifier:1, nodeId:[zwaveHubNodeId])
//14. get version
request += zwave.versionV1.versionGet()
//15. get serial number
request += zwave.manufacturerSpecificV2.deviceSpecificGet()
commands(request) + ["delay 1000", command(zwave.wakeUpV1.wakeUpNoMoreInformation())]
} }
} }
@@ -418,24 +500,42 @@ private def getTimeOptionValueMap() { [
"reports inactive" : 0, "reports inactive" : 0,
]} ]}
private def getZwaveNotificationOptionValueMap() { [
"disabled" : 0,
"casing opened" : 1,
"exceeding temperature threshold" : 2,
"all notifications" : 3
]}
private def getNotificationOptionValueMap() { [ private def getNotificationOptionValueMap() { [
"disabled" : 0, "disabled" : 0,
"casing opened" : 1, "casing opened" : 1,
"exceeding temperature threshold" : 2, "exceeding temperature threshold" : 2,
"lack of Z-Wave range" : 4, "lack of Z-Wave range" : 4,
"all notifications" : 7, "all notifications" : 7
]} ]}
private command(physicalgraph.zwave.Command cmd) { private command(physicalgraph.zwave.Command cmd) {
if (isSecured()) { def secureClasses = [0x20, 0x5A, 0x70, 0x71, 0x84, 0x85, 0x8E, 0x9C]
if (isSecured() && secureClasses.find{ it == cmd.commandClassId }) {
log.info "Sending secured command: ${cmd}" log.info "Sending secured command: ${cmd}"
zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() secure(cmd)
} else { } else {
log.info "Sending unsecured command: ${cmd}" log.info "Sending unsecured command: ${cmd}"
cmd.format() crc16(cmd)
} }
} }
private secure(physicalgraph.zwave.Command cmd) {
zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
}
private crc16(physicalgraph.zwave.Command cmd) {
//zwave.crc16encapV1.crc16Encap().encapsulate(cmd).format()
"5601${cmd.format()}0000"
}
private commands(commands, delay=200) { private commands(commands, delay=200) {
log.info "inside commands: ${commands}" log.info "inside commands: ${commands}"
delayBetween(commands.collect{ command(it) }, delay) delayBetween(commands.collect{ command(it) }, delay)