Compare commits

...

10 Commits

Author SHA1 Message Date
Vinay Rao
79c254cfac Merge pull request #1774 from SmartThingsCommunity/staging
Rolling up staging to production
2017-03-14 11:40:39 -07:00
Vinay Rao
72248b0004 Merge pull request #1773 from SmartThingsCommunity/production
Rolling down production to staging
2017-03-14 11:38:11 -07:00
Vinay Rao
d8b35b23ea Merge pull request #1770 from dkirker/DVCSMP-2472
DVCSMP-2472: Add Eaton Halo downlight
2017-03-14 02:28:47 -07:00
Donald Kirker
9a53e12427 DVCSMP-2472: Add Eaton Halo downlight 2017-03-14 02:20:58 -07:00
Vinay Rao
3c4d86bb31 Merge pull request #1761 from mckeed/ICP-399-prod
Update Fibaro Flood Sensor configuration ICP-399 ICP-398
2017-03-08 16:43:23 -08:00
Duncan McKee
1f69ab6634 Update Fibaro Flood Sensor configuration
ICP-399 ICP-398
2017-03-08 19:17:46 -05:00
Vinay Rao
b0ac006781 Merge pull request #1758 from mckeed/ICP-399-staging
Update Fibaro Flood Sensor configuration ICP-399 ICP-398
2017-03-07 17:53:27 -08:00
Duncan McKee
ef1ebc8347 Update Fibaro Flood Sensor configuration
ICP-399 ICP-398
2017-03-07 20:45:49 -05:00
Vinay Rao
aa1f2f21e8 Merge pull request #1756 from SmartThingsCommunity/master
Rolling up master to staging
2017-03-07 13:55:39 -08:00
Vinay Rao
7a605373d6 Merge pull request #1754 from SmartThingsCommunity/staging
Rolling up staging to production
2017-03-07 13:27:33 -08:00
3 changed files with 460 additions and 279 deletions

View File

@@ -23,27 +23,28 @@ metadata {
capability "Water Sensor" capability "Water Sensor"
capability "Health Check" capability "Health Check"
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x22, 0x85, 0x59, 0x20, 0x80, 0x70, 0x56, 0x5A, 0x7A, 0x72, 0x8E, 0x71, 0x73, 0x98, 0x9C, 0x31, 0x86", outClusters: "" fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x22, 0x85, 0x59, 0x20, 0x80, 0x70, 0x56, 0x5A, 0x7A, 0x72, 0x8E, 0x71, 0x73, 0x98, 0x9C, 0x31, 0x86", outClusters: ""
fingerprint mfr:"010F", prod:"0B01", model:"2002"
fingerprint mfr:"010F", prod:"0B01", model:"1002"
} }
simulator { simulator {
} }
tiles(scale: 2) { tiles(scale: 2) {
multiAttributeTile(name:"FGFS", type:"lighting", width:6, height:4) {//with generic type secondary control text is not displayed in Android app multiAttributeTile(name:"FGFS", type:"lighting", width:6, height:4) {//with generic type secondary control text is not displayed in Android app
tileAttribute("device.water", key:"PRIMARY_CONTROL") { tileAttribute("device.water", key:"PRIMARY_CONTROL") {
attributeState("dry", icon:"st.alarm.water.dry", backgroundColor:"#00a0dc") attributeState("dry", icon:"st.alarm.water.dry", backgroundColor:"#00a0dc")
attributeState("wet", icon:"st.alarm.water.wet", backgroundColor:"#e86d13") attributeState("wet", icon:"st.alarm.water.wet", backgroundColor:"#e86d13")
} }
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") { tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
attributeState("active", label:'tamper active', backgroundColor:"#00a0dc") attributeState("active", label:'tamper active', backgroundColor:"#00a0dc")
attributeState("inactive", label:'tamper inactive', backgroundColor:"#cccccc") attributeState("inactive", label:'tamper inactive', backgroundColor:"#cccccc")
} }
} }
valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) { valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {
state "temperature", label:'${currentValue}°', state "temperature", label:'${currentValue}°',
backgroundColors:[ backgroundColors:[
[value: 31, color: "#153591"], [value: 31, color: "#153591"],
@@ -56,13 +57,13 @@ metadata {
] ]
} }
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:""
} }
main "FGFS" main "FGFS"
details(["FGFS","battery", "temperature"]) details(["FGFS","battery", "temperature"])
} }
} }
// parse events into attributes // parse events into attributes
@@ -70,7 +71,7 @@ def parse(String description) {
log.debug "Parsing '${description}'" log.debug "Parsing '${description}'"
def result = [] def result = []
if (description.startsWith("Err 106")) { if (description.startsWith("Err 106")) {
if (state.sec) { if (state.sec) {
result = createEvent(descriptionText:description, displayed:false) result = createEvent(descriptionText:description, displayed:false)
} else { } else {
@@ -85,13 +86,13 @@ def parse(String description) {
} else if (description == "updated") { } else if (description == "updated") {
return null return null
} else { } else {
def cmd = zwave.parse(description, [0x31: 5, 0x56: 1, 0x71: 3, 0x72:2, 0x80: 1, 0x84: 2, 0x85: 2, 0x86: 1, 0x98: 1]) def cmd = zwave.parse(description, [0x31: 5, 0x56: 1, 0x71: 3, 0x72:2, 0x80: 1, 0x84: 2, 0x85: 2, 0x86: 1, 0x98: 1])
if (cmd) { if (cmd) {
log.debug "Parsed '${cmd}'" log.debug "Parsed '${cmd}'"
zwaveEvent(cmd) zwaveEvent(cmd)
} }
} }
} }
//security //security
@@ -108,7 +109,7 @@ def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulat
//crc16 //crc16
def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd) def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd)
{ {
def versions = [0x31: 5, 0x72: 2, 0x80: 1] def versions = [0x31: 5, 0x72: 2, 0x80: 1]
def version = versions[cmd.commandClass as Integer] def version = versions[cmd.commandClass as Integer]
def ccObj = version ? zwave.commandClass(cmd.commandClass, version) : zwave.commandClass(cmd.commandClass) def ccObj = version ? zwave.commandClass(cmd.commandClass, version) : zwave.commandClass(cmd.commandClass)
def encapsulatedCommand = ccObj?.command(cmd.command)?.parse(cmd.data) def encapsulatedCommand = ccObj?.command(cmd.command)?.parse(cmd.data)
@@ -122,105 +123,124 @@ def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd)
def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd)
{ {
def event = createEvent(descriptionText: "${device.displayName} woke up", displayed: false) def event = createEvent(descriptionText: "${device.displayName} woke up", displayed: false)
def cmds = [] def cmds = []
cmds << encap(zwave.batteryV1.batteryGet()) // cmds << encap(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 1, scale: 0))
cmds << "delay 500" // cmds << "delay 500"
cmds << encap(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 1, scale: 0)) cmds << encap(zwave.batteryV1.batteryGet())
cmds << "delay 1200" [event, response(cmds)]
cmds << encap(zwave.wakeUpV1.wakeUpNoMoreInformation())
[event, response(cmds)]
} }
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) { def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
log.debug "manufacturerId: ${cmd.manufacturerId}" log.debug "manufacturerId: ${cmd.manufacturerId}"
log.debug "manufacturerName: ${cmd.manufacturerName}" log.debug "manufacturerName: ${cmd.manufacturerName}"
log.debug "productId: ${cmd.productId}" log.debug "productId: ${cmd.productId}"
log.debug "productTypeId: ${cmd.productTypeId}" log.debug "productTypeId: ${cmd.productTypeId}"
} }
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.DeviceSpecificReport cmd) { def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.DeviceSpecificReport cmd) {
log.debug "deviceIdData: ${cmd.deviceIdData}" log.debug "deviceIdData: ${cmd.deviceIdData}"
log.debug "deviceIdDataFormat: ${cmd.deviceIdDataFormat}" log.debug "deviceIdDataFormat: ${cmd.deviceIdDataFormat}"
log.debug "deviceIdDataLengthIndicator: ${cmd.deviceIdDataLengthIndicator}" log.debug "deviceIdDataLengthIndicator: ${cmd.deviceIdDataLengthIndicator}"
log.debug "deviceIdType: ${cmd.deviceIdType}" log.debug "deviceIdType: ${cmd.deviceIdType}"
if (cmd.deviceIdType == 1 && cmd.deviceIdDataFormat == 1) {//serial number in binary format if (cmd.deviceIdType == 1 && cmd.deviceIdDataFormat == 1) { //serial number in binary format
String serialNumber = "h'" String serialNumber = "h'"
cmd.deviceIdData.each{ data -> cmd.deviceIdData.each{ data ->
serialNumber += "${String.format("%02X", data)}" serialNumber += "${String.format("%02X", data)}"
} }
updateDataValue("serialNumber", serialNumber) updateDataValue("serialNumber", serialNumber)
log.debug "${device.displayName} - serial number: ${serialNumber}" log.debug "${device.displayName} - serial number: ${serialNumber}"
} }
def response_cmds = []
if (!device.currentState("temperature")) {
response_cmds << encap(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 1, scale: 0))
}
if (!getDataValue("version") && !zwaveInfo.ver) {
log.debug "Requesting Version Report"
response_cmds << "delay 500"
response_cmds << encap(zwave.versionV1.versionGet())
}
response_cmds << "delay 1000"
response_cmds << encap(zwave.wakeUpV2.wakeUpNoMoreInformation())
[[:], response(response_cmds)]
} }
def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) {
updateDataValue("version", "${cmd.applicationVersion}.${cmd.applicationSubVersion}") updateDataValue("version", "${cmd.applicationVersion}.${cmd.applicationSubVersion}")
log.debug "applicationVersion: ${cmd.applicationVersion}" log.debug "applicationVersion: ${cmd.applicationVersion}"
log.debug "applicationSubVersion: ${cmd.applicationSubVersion}" log.debug "applicationSubVersion: ${cmd.applicationSubVersion}"
log.debug "zWaveLibraryType: ${cmd.zWaveLibraryType}" log.debug "zWaveLibraryType: ${cmd.zWaveLibraryType}"
log.debug "zWaveProtocolVersion: ${cmd.zWaveProtocolVersion}" log.debug "zWaveProtocolVersion: ${cmd.zWaveProtocolVersion}"
log.debug "zWaveProtocolSubVersion: ${cmd.zWaveProtocolSubVersion}" log.debug "zWaveProtocolSubVersion: ${cmd.zWaveProtocolSubVersion}"
} }
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
def result = []
def map = [:] def map = [:]
map.name = "battery" map.name = "battery"
map.value = cmd.batteryLevel == 255 ? 1 : cmd.batteryLevel.toString() map.value = cmd.batteryLevel == 255 ? 1 : cmd.batteryLevel.toString()
map.unit = "%" map.unit = "%"
map.displayed = true
createEvent(map) result << createEvent(map)
if (!getDataValue("serialNumber")) {
result << response(encap(zwave.manufacturerSpecificV2.deviceSpecificGet()))
} else {
result << response(encap(zwave.wakeUpV2.wakeUpNoMoreInformation()))
}
result
} }
def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) {
def map = [:] def map = [:]
if (cmd.notificationType == 5) { if (cmd.notificationType == 5) {
switch (cmd.event) { switch (cmd.event) {
case 2: case 2:
map.name = "water" map.name = "water"
map.value = "wet" map.value = "wet"
map.descriptionText = "${device.displayName} is ${map.value}" map.descriptionText = "${device.displayName} is ${map.value}"
break
case 0:
map.name = "water"
map.value = "dry"
map.descriptionText = "${device.displayName} is ${map.value}"
break
}
} else if (cmd.notificationType == 7) {
switch (cmd.event) {
case 0:
map.name = "tamper"
map.value = "inactive"
map.descriptionText = "${device.displayName}: tamper alarm has been deactivated"
break break
case 3: case 0:
map.name = "tamper" map.name = "water"
map.value = "active" map.value = "dry"
map.descriptionText = "${device.displayName}: tamper alarm activated" map.descriptionText = "${device.displayName} is ${map.value}"
break break
} }
} } else if (cmd.notificationType == 7) {
switch (cmd.event) {
case 0:
map.name = "tamper"
map.value = "inactive"
map.descriptionText = "${device.displayName}: tamper alarm has been deactivated"
break
createEvent(map) case 3:
map.name = "tamper"
map.value = "active"
map.descriptionText = "${device.displayName}: tamper alarm activated"
break
}
}
createEvent(map)
} }
def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) { def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) {
def map = [:] def map = [:]
if (cmd.sensorType == 1) { if (cmd.sensorType == 1) {
// temperature // temperature
def cmdScale = cmd.scale == 1 ? "F" : "C" def cmdScale = cmd.scale == 1 ? "F" : "C"
map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision) map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision)
map.unit = getTemperatureScale() map.unit = getTemperatureScale()
map.name = "temperature" map.name = "temperature"
map.displayed = true map.displayed = true
} }
createEvent(map) createEvent(map)
} }
def zwaveEvent(physicalgraph.zwave.commands.deviceresetlocallyv1.DeviceResetLocallyNotification cmd) { def zwaveEvent(physicalgraph.zwave.commands.deviceresetlocallyv1.DeviceResetLocallyNotification cmd) {
@@ -229,21 +249,18 @@ def zwaveEvent(physicalgraph.zwave.commands.deviceresetlocallyv1.DeviceResetLoca
def configure() { def configure() {
log.debug "Executing 'configure'" log.debug "Executing 'configure'"
// Device-Watch simply pings if no device events received for 8 hrs & 2 minutes // Device wakes up every 4 hours, this interval of 8h 2m allows us to miss one wakeup notification before marking offline
sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
def cmds = [] // default initial state
sendEvent(name: "water", value: "dry")
cmds += zwave.wakeUpV2.wakeUpIntervalSet(seconds:21600, nodeid: zwaveHubNodeId)//FGFS' default wake up interval def cmds = []
cmds += zwave.manufacturerSpecificV2.manufacturerSpecificGet()
cmds += zwave.manufacturerSpecificV2.deviceSpecificGet()
cmds += zwave.versionV1.versionGet()
cmds += zwave.batteryV1.batteryGet()
cmds += zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 1, scale: 0)
cmds += zwave.associationV2.associationSet(groupingIdentifier:1, nodeId: [zwaveHubNodeId])
cmds += zwave.wakeUpV2.wakeUpNoMoreInformation()
encapSequence(cmds, 500) cmds << zwave.associationV2.associationSet(groupingIdentifier:1, nodeId: [zwaveHubNodeId])
cmds << zwave.batteryV1.batteryGet() // other queries sent as response to BatteryReport
encapSequence(cmds, 200)
} }
private secure(physicalgraph.zwave.Command cmd) { private secure(physicalgraph.zwave.Command cmd) {
@@ -252,7 +269,7 @@ private secure(physicalgraph.zwave.Command cmd) {
private crc16(physicalgraph.zwave.Command cmd) { private crc16(physicalgraph.zwave.Command cmd) {
//zwave.crc16EncapV1.crc16Encap().encapsulate(cmd).format() //zwave.crc16EncapV1.crc16Encap().encapsulate(cmd).format()
"5601${cmd.format()}0000" "5601${cmd.format()}0000"
} }
private encapSequence(commands, delay=200) { private encapSequence(commands, delay=200) {
@@ -260,13 +277,10 @@ private encapSequence(commands, delay=200) {
} }
private encap(physicalgraph.zwave.Command cmd) { private encap(physicalgraph.zwave.Command cmd) {
def secureClasses = [0x20, 0x5A, 0x70, 0x71, 0x84, 0x85, 0x8E, 0x9C] if (zwaveInfo.zw && !zwaveInfo.zw.contains("s")) {
// Secure inclusion failed
//todo: check if secure inclusion was successful crc16(cmd)
//if not do not send security-encapsulated command } else {
if (secureClasses.find{ it == cmd.commandClassId }) { secure(cmd)
secure(cmd) }
} else {
crc16(cmd)
}
} }

View File

@@ -1,12 +1,12 @@
/** /**
* Device Type Definition File * Device Type Definition File
* *
* Device Type: Fibaro Flood Sensor * Device Type: Fibaro Flood Sensor
* File Name: fibaro-flood-sensor.groovy * File Name: fibaro-flood-sensor.groovy
* Initial Release: 2014-12-10 * Initial Release: 2014-12-10
* @author: Todd Wackford * @author: Todd Wackford
* Email: todd@wackford.net * Email: todd@wackford.net
* @version: 1.0 * @version: 1.0
* *
* Copyright 2014 SmartThings * Copyright 2014 SmartThings
* *
@@ -26,8 +26,8 @@
* not displayed to the user. We do this so we can receive events and display on device * not displayed to the user. We do this so we can receive events and display on device
* activity. If the user wants to display the tamper tile, adjust the tile display lines * activity. If the user wants to display the tamper tile, adjust the tile display lines
* with the following: * with the following:
* main(["water", "temperature", "tamper"]) * main(["water", "temperature", "tamper"])
* details(["water", "temperature", "battery", "tamper"]) * details(["water", "temperature", "battery", "tamper"])
* *
* @param none * @param none
* *
@@ -41,12 +41,15 @@ metadata {
capability "Battery" capability "Battery"
capability "Health Check" capability "Health Check"
command "resetParams2StDefaults" command "resetParams2StDefaults"
command "listCurrentParams" command "listCurrentParams"
command "updateZwaveParam" command "updateZwaveParam"
command "test" command "test"
fingerprint deviceId: "0xA102", inClusters: "0x30,0x9C,0x60,0x85,0x8E,0x72,0x70,0x86,0x80,0x84" fingerprint deviceId: "0xA102", inClusters: "0x30,0x9C,0x60,0x85,0x8E,0x72,0x70,0x86,0x80,0x84"
fingerprint mfr:"010F", prod:"0000", model:"2002"
fingerprint mfr:"010F", prod:"0000", model:"1002"
fingerprint mfr:"010F", prod:"0B00", model:"1001"
} }
simulator { simulator {
@@ -87,9 +90,9 @@ metadata {
[value: 96, color: "#bc2323"] [value: 96, color: "#bc2323"]
] ]
} }
standardTile("tamper", "device.tamper") { standardTile("tamper", "device.tamper") {
state("secure", label:"secure", icon:"st.locks.lock.locked", backgroundColor:"#ffffff") state("secure", label:"secure", icon:"st.locks.lock.locked", backgroundColor:"#ffffff")
state("tampered", label:"tampered", icon:"st.locks.lock.unlocked", backgroundColor:"#53a7c0") state("tampered", label:"tampered", icon:"st.locks.lock.unlocked", backgroundColor:"#53a7c0")
} }
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") { valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") {
state "battery", label:'${currentValue}% battery', unit:"" state "battery", label:'${currentValue}% battery', unit:""
@@ -108,25 +111,16 @@ def parse(String description)
{ {
def result = [] def result = []
if (description == "updated") { def cmd = zwave.parse(description, [0x31: 2, 0x30: 1, 0x70: 2, 0x71: 1, 0x84: 1, 0x80: 1, 0x9C: 1, 0x72: 2, 0x56: 2, 0x60: 3])
if (!state.MSR) {
result << response(zwave.wakeUpV1.wakeUpIntervalSet(seconds: 60*60, nodeid:zwaveHubNodeId))
result << response(zwave.manufacturerSpecificV2.manufacturerSpecificGet())
}
} else {
def cmd = zwave.parse(description, [0x31: 2, 0x30: 1, 0x70: 2, 0x71: 1, 0x84: 1, 0x80: 1, 0x9C: 1, 0x72: 2, 0x56: 2, 0x60: 3])
if (cmd) { if (cmd) {
result += zwaveEvent(cmd) //createEvent(zwaveEvent(cmd)) result += zwaveEvent(cmd) //createEvent(zwaveEvent(cmd))
} }
}
result << response(zwave.batteryV1.batteryGet().format()) if ( result[0] != null ) {
if ( result[0] != null ) {
log.debug "Parse returned ${result}" log.debug "Parse returned ${result}"
result result
} }
} }
@@ -143,10 +137,9 @@ def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) {
def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)] def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)]
if (!isConfigured()) { if (!isConfigured()) {
// we're still in the process of configuring a newly joined device // we're still in the process of configuring a newly joined device
result += lateConfigure(true) result << lateConfigure(true)
} else { } else {
result += response(zwave.wakeUpV1.wakeUpNoMoreInformation()) result << response(zwave.wakeUpV1.wakeUpNoMoreInformation())
log.debug "We're done with WakeUp!"
} }
result result
} }
@@ -200,23 +193,23 @@ def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport
} }
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) {
log.debug "BasicSet with CMD = ${cmd}" log.debug "BasicSet with CMD = ${cmd}"
if (!isConfigured()) { if (!isConfigured()) {
def result = [] def result = []
def map = [:] def map = [:]
map.name = "water" map.name = "water"
map.value = cmd.value ? "wet" : "dry" map.value = cmd.value ? "wet" : "dry"
map.descriptionText = "${device.displayName} is ${map.value}" map.descriptionText = "${device.displayName} is ${map.value}"
// If we are getting a BasicSet, and isConfigured == false, then we are likely NOT properly configured. // If we are getting a BasicSet, and isConfigured == false, then we are likely NOT properly configured.
result += lateConfigure(true) result += lateConfigure(true)
result << createEvent(map) result << createEvent(map)
result result
} }
} }
def zwaveEvent(physicalgraph.zwave.commands.sensoralarmv1.SensorAlarmReport cmd) def zwaveEvent(physicalgraph.zwave.commands.sensoralarmv1.SensorAlarmReport cmd)
@@ -228,20 +221,20 @@ def zwaveEvent(physicalgraph.zwave.commands.sensoralarmv1.SensorAlarmReport cmd)
map.value = cmd.sensorState ? "wet" : "dry" map.value = cmd.sensorState ? "wet" : "dry"
map.descriptionText = "${device.displayName} is ${map.value}" map.descriptionText = "${device.displayName} is ${map.value}"
log.debug "CMD = SensorAlarmReport: ${cmd}" log.debug "CMD = SensorAlarmReport: ${cmd}"
setConfigured() setConfigured()
} else if ( cmd.sensorType == 0) { } else if ( cmd.sensorType == 0) {
map.name = "tamper" map.name = "tamper"
map.isStateChange = true map.isStateChange = true
map.value = cmd.sensorState ? "tampered" : "secure" map.value = cmd.sensorState ? "tampered" : "secure"
map.descriptionText = "${device.displayName} has been tampered with" map.descriptionText = "${device.displayName} has been tampered with"
runIn(30, "resetTamper") //device does not send alarm cancelation runIn(30, "resetTamper") //device does not send alarm cancelation
} else if ( cmd.sensorType == 1) { } else if ( cmd.sensorType == 1) {
map.name = "tamper" map.name = "tamper"
map.value = cmd.sensorState ? "tampered" : "secure" map.value = cmd.sensorState ? "tampered" : "secure"
map.descriptionText = "${device.displayName} has been tampered with" map.descriptionText = "${device.displayName} has been tampered with"
runIn(30, "resetTamper") //device does not send alarm cancelation runIn(30, "resetTamper") //device does not send alarm cancelation
} else { } else {
map.descriptionText = "${device.displayName}: ${cmd}" map.descriptionText = "${device.displayName}: ${cmd}"
@@ -251,10 +244,10 @@ def zwaveEvent(physicalgraph.zwave.commands.sensoralarmv1.SensorAlarmReport cmd)
def resetTamper() { def resetTamper() {
def map = [:] def map = [:]
map.name = "tamper" map.name = "tamper"
map.value = "secure" map.value = "secure"
map.descriptionText = "$device.displayName is secure" map.descriptionText = "$device.displayName is secure"
sendEvent(map) sendEvent(map)
} }
def zwaveEvent(physicalgraph.zwave.Command cmd) { def zwaveEvent(physicalgraph.zwave.Command cmd) {
@@ -269,9 +262,9 @@ def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerS
log.debug "msr: $msr" log.debug "msr: $msr"
device.updateDataValue(["MSR", msr]) device.updateDataValue(["MSR", msr])
if ( msr == "010F-0B00-2001" ) { //this is the msr and device type for the fibaro flood sensor if ( msr == "010F-0B00-2001" ) { //this is the msr and device type for the fibaro flood sensor
result += lateConfigure(true) result += lateConfigure(true)
} }
result << createEvent(descriptionText: "$device.displayName MSR: $msr", isStateChange: false) result << createEvent(descriptionText: "$device.displayName MSR: $msr", isStateChange: false)
result result
@@ -284,16 +277,16 @@ def setConfigured() {
def isConfigured() { def isConfigured() {
Boolean configured = device.getDataValue(["configured"]) as Boolean Boolean configured = device.getDataValue(["configured"]) as Boolean
return configured return configured
} }
def lateConfigure(setConf = False) { def lateConfigure(setConf = False) {
def res = response(configure()) def res = response(configure())
if (setConf) if (setConf)
setConfigured() setConfigured()
return res return res
} }
/** /**
@@ -305,28 +298,33 @@ def lateConfigure(setConf = False) {
*/ */
def configure() { def configure() {
log.debug "Configuring Device..." log.debug "Configuring Device..."
// Device-Watch simply pings if no device events received for 8 hrs & 2 minutes // Device wakes up every 4 hours, this interval allows us to miss one wakeup notification before marking offline
sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
def cmds = [] // default initial state
sendEvent(name: "water", value: "dry")
// send associate to group 2 to get alarm data def cmds = []
cmds << zwave.associationV2.associationSet(groupingIdentifier:2, nodeId:[zwaveHubNodeId]).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [255], parameterNumber: 5, size: 1).format() // send associate to group 2 to get alarm data
cmds << zwave.associationV2.associationSet(groupingIdentifier:2, nodeId:[zwaveHubNodeId]).format()
// send associate to group 3 to get sensor data reported only to hub cmds << zwave.configurationV1.configurationSet(configurationValue: [255], parameterNumber: 5, size: 1).format()
cmds << zwave.associationV2.associationSet(groupingIdentifier:3, nodeId:[zwaveHubNodeId]).format()
// temp hysteresis set to .5 degrees celcius // send associate to group 3 to get sensor data reported only to hub
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,50], parameterNumber: 12, size: 2).format() cmds << zwave.associationV2.associationSet(groupingIdentifier:3, nodeId:[zwaveHubNodeId]).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 12).format()
// reporting frequency of temps and battery set to one hour // reporting frequency of temps and battery set to one hour
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,60*60], parameterNumber: 10, size: 2).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [0,60*60], parameterNumber: 10, size: 2).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 10).format() // cmds << zwave.configurationV1.configurationGet(parameterNumber: 10).format()
cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format() // temp hysteresis set to .5 degrees celcius
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,50], parameterNumber: 12, size: 2).format()
// cmds << zwave.configurationV1.configurationGet(parameterNumber: 12).format()
cmds << zwave.batteryV1.batteryGet().format()
cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format()
delayBetween(cmds, 100) delayBetween(cmds, 100)
} }
@@ -354,17 +352,17 @@ def test() {
*/ */
def updateZwaveParam(params) { def updateZwaveParam(params) {
if ( params ) { if ( params ) {
def pNumber = params.paramNumber def pNumber = params.paramNumber
def pSize = params.size def pSize = params.size
def pValue = [params.value] def pValue = [params.value]
log.debug "Make sure device is awake and in recieve mode (triple-click?)" log.debug "Make sure device is awake and in recieve mode (triple-click?)"
log.debug "Updating ${device.displayName} parameter number '${pNumber}' with value '${pValue}' with size of '${pSize}'" log.debug "Updating ${device.displayName} parameter number '${pNumber}' with value '${pValue}' with size of '${pSize}'"
def cmds = [] def cmds = []
cmds << zwave.configurationV1.configurationSet(configurationValue: pValue, parameterNumber: pNumber, size: pSize).format() cmds << zwave.configurationV1.configurationSet(configurationValue: pValue, parameterNumber: pNumber, size: pSize).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: pNumber).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: pNumber).format()
delayBetween(cmds, 1000) delayBetween(cmds, 1000)
} }
} }
/** /**
@@ -381,26 +379,26 @@ def updateZwaveParam(params) {
def resetParams2StDefaults() { def resetParams2StDefaults() {
log.debug "Resetting ${device.displayName} parameters to SmartThings compatible defaults" log.debug "Resetting ${device.displayName} parameters to SmartThings compatible defaults"
def cmds = [] def cmds = []
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0], parameterNumber: 1, size: 2).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0], parameterNumber: 1, size: 2).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [3], parameterNumber: 2, size: 1).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [3], parameterNumber: 2, size: 1).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [255], parameterNumber: 5, size: 1).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [255], parameterNumber: 5, size: 1).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [255], parameterNumber: 7, size: 1).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [255], parameterNumber: 7, size: 1).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [1], parameterNumber: 9, size: 1).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [1], parameterNumber: 9, size: 1).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,60*60], parameterNumber: 10, size: 2).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [0,60*60], parameterNumber: 10, size: 2).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,50], parameterNumber: 12, size: 2).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [0,50], parameterNumber: 12, size: 2).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 13, size: 1).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 13, size: 1).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [5,220], parameterNumber: 50, size: 2).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [5,220], parameterNumber: 50, size: 2).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [13,172], parameterNumber: 51, size: 2).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [13,172], parameterNumber: 51, size: 2).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0,0,225], parameterNumber: 61, size: 4).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0,0,225], parameterNumber: 61, size: 4).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,255,0,0], parameterNumber: 62, size: 4).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [0,255,0,0], parameterNumber: 62, size: 4).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [2], parameterNumber: 63, size: 1).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [2], parameterNumber: 63, size: 1).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0], parameterNumber: 73, size: 2).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0], parameterNumber: 73, size: 2).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [2], parameterNumber: 74, size: 1).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [2], parameterNumber: 74, size: 1).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0], parameterNumber: 75, size: 2).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0], parameterNumber: 75, size: 2).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0], parameterNumber: 76, size: 2).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0], parameterNumber: 76, size: 2).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 77, size: 1).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 77, size: 1).format()
delayBetween(cmds, 1200) delayBetween(cmds, 1200)
} }
/** /**
@@ -417,24 +415,24 @@ def resetParams2StDefaults() {
def listCurrentParams() { def listCurrentParams() {
log.debug "Listing of current parameter settings of ${device.displayName}" log.debug "Listing of current parameter settings of ${device.displayName}"
def cmds = [] def cmds = []
cmds << zwave.configurationV1.configurationGet(parameterNumber: 1).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 1).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 2).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 2).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 5).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 5).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 7).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 7).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 9).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 9).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 10).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 10).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 12).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 12).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 13).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 13).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 50).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 50).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 51).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 51).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 61).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 61).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 62).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 62).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 63).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 63).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 73).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 73).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 74).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 74).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 75).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 75).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 76).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 76).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 77).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 77).format()
delayBetween(cmds, 1200) delayBetween(cmds, 1200)
} }

View File

@@ -0,0 +1,169 @@
/**
* Copyright 2016 SmartThings
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*
*/
import groovy.transform.Field
@Field Boolean hasConfiguredHealthCheck = false
metadata {
definition (name: "ZLL White Color Temperature Bulb 5000K", namespace: "smartthings", author: "SmartThings") {
capability "Actuator"
capability "Color Temperature"
capability "Configuration"
capability "Polling"
capability "Refresh"
capability "Switch"
capability "Switch Level"
capability "Health Check"
attribute "colorName", "string"
command "setGenericName"
fingerprint profileId: "C05E", deviceId: "0220", inClusters: "0000, 0004, 0003, 0006, 0008, 0005, 0300", outClusters: "0019", manufacturer: "Eaton", model: "Halo_LT01", deviceJoinName: "Halo RL56 Wireless"
}
// UI tile definitions
tiles(scale: 2) {
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
}
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
attributeState "level", action:"switch level.setLevel"
}
tileAttribute ("colorName", key: "SECONDARY_CONTROL") {
attributeState "colorName", label:'${currentValue}'
}
}
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
}
controlTile("colorTempSliderControl", "device.colorTemperature", "slider", width: 4, height: 2, inactiveLabel: false, range:"(2700..5000)") {
state "colorTemperature", action:"color temperature.setColorTemperature"
}
valueTile("colorTemp", "device.colorTemperature", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "colorTemperature", label: '${currentValue} K'
}
main(["switch"])
details(["switch", "colorTempSliderControl", "colorTemp", "refresh"])
}
}
// Parse incoming device messages to generate events
def parse(String description) {
log.debug "description is $description"
def event = zigbee.getEvent(description)
if (event) {
if (event.name == "colorTemperature") {
event.unit = "K"
}
sendEvent(event)
}
else {
log.warn "DID NOT PARSE MESSAGE for description : $description"
log.debug zigbee.parseDescriptionAsMap(description)
}
}
def off() {
zigbee.off() + ["delay 1500"] + zigbee.onOffRefresh()
}
def on() {
zigbee.on() + ["delay 1500"] + zigbee.onOffRefresh()
}
def setLevel(value) {
zigbee.setLevel(value) + zigbee.onOffRefresh() + zigbee.levelRefresh()
}
def refresh() {
def cmds = zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh()
// Do NOT config if the device is the Eaton Halo_LT01, it responds with "switch:off" to onOffConfig, and maybe other weird things with the others
if (!((device.getDataValue("manufacturer") == "Eaton") && (device.getDataValue("model") == "Halo_LT01"))) {
cmds = cmds + zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.colorTemperatureConfig()
}
cmds
}
def poll() {
zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh()
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
return zigbee.levelRefresh()
}
def healthPoll() {
log.debug "healthPoll()"
def cmds = zigbee.onOffRefresh() + zigbee.levelRefresh()
cmds.each{ sendHubCommand(new physicalgraph.device.HubAction(it))}
}
def configureHealthCheck() {
Integer hcIntervalMinutes = 12
if (!hasConfiguredHealthCheck) {
log.debug "Configuring Health Check, Reporting"
unschedule("healthPoll")
runEvery5Minutes("healthPoll")
// Device-Watch allows 2 check-in misses from device
sendEvent(name: "checkInterval", value: hcIntervalMinutes * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
hasConfiguredHealthCheck = true
}
}
def configure() {
log.debug "configure()"
configureHealthCheck()
// Implementation note: for the Eaton Halo_LT01, it responds with "switch:off" to onOffConfig, so be sure this is before the call to onOffRefresh
zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.colorTemperatureConfig() + zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh()
}
def updated() {
log.debug "updated()"
configureHealthCheck()
}
def setColorTemperature(value) {
setGenericName(value)
zigbee.setColorTemperature(value) + ["delay 1500"] + zigbee.colorTemperatureRefresh()
}
//Naming based on the wiki article here: http://en.wikipedia.org/wiki/Color_temperature
def setGenericName(value){
if (value != null) {
def genericName = ""
if (value < 3300) {
genericName = "Soft White"
} else if (value < 4150) {
genericName = "Moonlight"
} else if (value <= 5000) {
genericName = "Cool White"
} else {
genericName = "Daylight"
}
sendEvent(name: "colorName", value: genericName, displayed: false)
}
}