Compare commits

..

1 Commits

Author SHA1 Message Date
Neal Black
a0ba15fe1b MSA-1836: null 2017-03-13 18:21:10 -07:00
19 changed files with 5647 additions and 672 deletions

View File

@@ -23,28 +23,27 @@ 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"],
@@ -57,13 +56,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
@@ -71,7 +70,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 {
@@ -86,13 +85,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
@@ -109,7 +108,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)
@@ -123,124 +122,105 @@ 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.sensorMultilevelV5.sensorMultilevelGet(sensorType: 1, scale: 0)) cmds << encap(zwave.batteryV1.batteryGet())
// cmds << "delay 500" cmds << "delay 500"
cmds << encap(zwave.batteryV1.batteryGet()) cmds << encap(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 1, scale: 0))
[event, response(cmds)] cmds << "delay 1200"
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
result << createEvent(map) 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 0: case 3:
map.name = "water" map.name = "tamper"
map.value = "dry" map.value = "active"
map.descriptionText = "${device.displayName} is ${map.value}" map.descriptionText = "${device.displayName}: tamper alarm activated"
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
case 3: createEvent(map)
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) {
@@ -249,18 +229,21 @@ def zwaveEvent(physicalgraph.zwave.commands.deviceresetlocallyv1.DeviceResetLoca
def configure() { def configure() {
log.debug "Executing 'configure'" log.debug "Executing 'configure'"
// Device wakes up every 4 hours, this interval of 8h 2m allows us to miss one wakeup notification before marking offline // Device-Watch simply pings if no device events received for 8 hrs & 2 minutes
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])
// default initial state def cmds = []
sendEvent(name: "water", value: "dry")
def cmds = [] cmds += zwave.wakeUpV2.wakeUpIntervalSet(seconds:21600, nodeid: zwaveHubNodeId)//FGFS' default wake up interval
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()
cmds << zwave.associationV2.associationSet(groupingIdentifier:1, nodeId: [zwaveHubNodeId]) encapSequence(cmds, 500)
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) {
@@ -269,7 +252,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) {
@@ -277,10 +260,13 @@ private encapSequence(commands, delay=200) {
} }
private encap(physicalgraph.zwave.Command cmd) { private encap(physicalgraph.zwave.Command cmd) {
if (zwaveInfo.zw && !zwaveInfo.zw.contains("s")) { def secureClasses = [0x20, 0x5A, 0x70, 0x71, 0x84, 0x85, 0x8E, 0x9C]
// Secure inclusion failed
crc16(cmd) //todo: check if secure inclusion was successful
} else { //if not do not send security-encapsulated command
secure(cmd) if (secureClasses.find{ it == cmd.commandClassId }) {
} secure(cmd)
} else {
crc16(cmd)
}
} }

View File

@@ -1,2 +0,0 @@
.st-ignore
README.md

View File

@@ -1,37 +0,0 @@
# Aeon Siren
Cloud Execution
Works with:
* [Aeon Labs Siren (Gen 5)](https://www.smartthings.com/works-with-smartthings/aeon-labs/aeon-labs-siren-gen-5)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
## Capabilities
* **Actuator** - represents that a Device has commands
* **Alarm** - allows for interacting with devices that serve as alarms
* **Switch** - can detect state (possible values: on/off)
* **Health Check** - indicates ability to get device health notifications
## Device Health
Aeon Labs Siren (Gen 5) is polled by the hub.
As of hubCore version 0.14.38 the hub sends up reports every 15 minutes regardless of whether the state changed.
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*15 + 2)mins = 32 mins.
Not to mention after going OFFLINE when the device is plugged back in, it might take a considerable amount of time for
the device to appear as ONLINE again. This is because if this listening device does not respond to two poll requests in a row,
it is not polled for 5 minutes by the hub. This can delay up the process of being marked ONLINE by quite some time.
* __32min__ checkInterval
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
Pairing needs to be tried again by placing the device closer to the hub.
Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link:
* [Aeon Labs Siren (Gen 5) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/204555240-Aeon-Labs-Siren-Gen-5-)

View File

@@ -20,11 +20,10 @@ metadata {
capability "Actuator" capability "Actuator"
capability "Alarm" capability "Alarm"
capability "Switch" capability "Switch"
capability "Health Check"
command "test" command "test"
fingerprint deviceId: "0x1005", inClusters: "0x5E,0x98", deviceJoinName: "Aeon Labs Siren (Gen 5)" fingerprint deviceId: "0x1005", inClusters: "0x5E,0x98"
} }
simulator { simulator {
@@ -59,9 +58,6 @@ metadata {
} }
def updated() { def updated() {
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
if(!state.sound) state.sound = 1 if(!state.sound) state.sound = 1
if(!state.volume) state.volume = 3 if(!state.volume) state.volume = 3
@@ -152,10 +148,3 @@ def test() {
private secure(physicalgraph.zwave.Command cmd) { private secure(physicalgraph.zwave.Command cmd) {
zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
} }
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
secure(zwave.basicV1.basicGet())
}

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
* *
@@ -40,17 +40,14 @@ metadata {
capability "Configuration" capability "Configuration"
capability "Battery" capability "Battery"
capability "Health Check" capability "Health Check"
capability "Sensor" capability "Sensor"
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 {
@@ -91,9 +88,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:""
@@ -112,16 +109,25 @@ def parse(String description)
{ {
def result = [] def result = []
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 (description == "updated") {
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))
} }
}
if ( result[0] != null ) { result << response(zwave.batteryV1.batteryGet().format())
if ( result[0] != null ) {
log.debug "Parse returned ${result}" log.debug "Parse returned ${result}"
result result
} }
} }
@@ -138,9 +144,10 @@ 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
} }
@@ -194,23 +201,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)
@@ -222,20 +229,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}"
@@ -245,10 +252,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) {
@@ -263,9 +270,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
@@ -278,16 +285,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
} }
/** /**
@@ -299,33 +306,28 @@ def lateConfigure(setConf = False) {
*/ */
def configure() { def configure() {
log.debug "Configuring Device..." log.debug "Configuring Device..."
// Device wakes up every 4 hours, this interval allows us to miss one wakeup notification before marking offline // Device-Watch simply pings if no device events received for 8 hrs & 2 minutes
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])
// default initial state def cmds = []
sendEvent(name: "water", value: "dry")
def cmds = [] // send associate to group 2 to get alarm data
cmds << zwave.associationV2.associationSet(groupingIdentifier:2, nodeId:[zwaveHubNodeId]).format()
// send associate to group 2 to get alarm data cmds << zwave.configurationV1.configurationSet(configurationValue: [255], parameterNumber: 5, size: 1).format()
cmds << zwave.associationV2.associationSet(groupingIdentifier:2, nodeId:[zwaveHubNodeId]).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [255], parameterNumber: 5, size: 1).format() // send associate to group 3 to get sensor data reported only to hub
cmds << zwave.associationV2.associationSet(groupingIdentifier:3, nodeId:[zwaveHubNodeId]).format()
// send associate to group 3 to get sensor data reported only to hub
cmds << zwave.associationV2.associationSet(groupingIdentifier:3, nodeId:[zwaveHubNodeId]).format()
// 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.configurationGet(parameterNumber: 10).format()
// temp hysteresis set to .5 degrees celcius // temp hysteresis set to .5 degrees celcius
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.configurationGet(parameterNumber: 12).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 12).format()
cmds << zwave.batteryV1.batteryGet().format() // 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.configurationGet(parameterNumber: 10).format()
cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format() cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format()
delayBetween(cmds, 100) delayBetween(cmds, 100)
} }
@@ -353,17 +355,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)
} }
} }
/** /**
@@ -380,26 +382,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)
} }
/** /**
@@ -416,24 +418,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

@@ -39,8 +39,8 @@ metadata {
tiles { tiles {
standardTile("motion", "device.motion", width: 2, height: 2) { standardTile("motion", "device.motion", width: 2, height: 2) {
state "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00A0DC" state "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0"
state "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#cccccc" state "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff"
} }
valueTile("temperature", "device.temperature", inactiveLabel: false) { valueTile("temperature", "device.temperature", inactiveLabel: false) {
state "temperature", label:'${currentValue}°', state "temperature", label:'${currentValue}°',

View File

@@ -32,8 +32,8 @@ metadata {
tiles { tiles {
standardTile("motion", "device.motion", width: 2, height: 2) { standardTile("motion", "device.motion", width: 2, height: 2) {
state("active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00A0DC") state("active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0")
state("inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#cccccc") state("inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff")
} }
valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false) { valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false) {

View File

@@ -45,8 +45,8 @@ metadata {
tiles(scale: 2) { tiles(scale: 2) {
multiAttributeTile(name: "contact", type: "generic", width: 6, height: 4) { multiAttributeTile(name: "contact", type: "generic", width: 6, height: 4) {
tileAttribute("device.contact", key: "PRIMARY_CONTROL") { tileAttribute("device.contact", key: "PRIMARY_CONTROL") {
attributeState "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#e86d13" attributeState "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#ffa81e"
attributeState "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#00A0DC" attributeState "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#79b821"
} }
} }

View File

@@ -1,169 +0,0 @@
/**
* 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)
}
}

View File

@@ -33,7 +33,7 @@ metadata {
tiles { tiles {
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) { standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
state "on", label: '${name}', action: "switch.off", icon: "st.unknown.zwave.device", backgroundColor: "#00A0DC" state "on", label: '${name}', action: "switch.off", icon: "st.unknown.zwave.device", backgroundColor: "#79b821"
state "off", label: '${name}', action: "switch.on", icon: "st.unknown.zwave.device", backgroundColor: "#ffffff" state "off", label: '${name}', action: "switch.on", icon: "st.unknown.zwave.device", backgroundColor: "#ffffff"
} }
standardTile("switchOn", "device.switch", inactiveLabel: false, decoration: "flat") { standardTile("switchOn", "device.switch", inactiveLabel: false, decoration: "flat") {

View File

@@ -51,7 +51,7 @@ metadata {
// tile definitions // tile definitions
tiles { tiles {
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) { standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00A0DC" state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821"
state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff" state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
} }
valueTile("power", "device.power") { valueTile("power", "device.power") {

View File

@@ -38,8 +38,8 @@ metadata {
tiles { tiles {
standardTile("motion", "device.motion", width: 2, height: 2) { standardTile("motion", "device.motion", width: 2, height: 2) {
state("active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00A0DC") state("active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0")
state("inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#cccccc") state("inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff")
} }
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:"")

View File

@@ -32,8 +32,8 @@ metadata {
tiles { tiles {
standardTile("sensor", "device.sensor", width: 2, height: 2) { standardTile("sensor", "device.sensor", width: 2, height: 2) {
state("inactive", label:'inactive', icon:"st.unknown.zwave.sensor", backgroundColor:"#cccccc") state("inactive", label:'inactive', icon:"st.unknown.zwave.sensor", backgroundColor:"#ffffff")
state("active", label:'active', icon:"st.unknown.zwave.sensor", backgroundColor:"#00A0DC") state("active", label:'active', icon:"st.unknown.zwave.sensor", 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:""

View File

@@ -47,7 +47,7 @@ metadata {
tiles(scale: 2) { tiles(scale: 2) {
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){ multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") { tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00A0DC" attributeState "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821"
attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff" attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
} }
} }

View File

@@ -46,7 +46,7 @@ metadata {
tiles(scale: 2) { tiles(scale: 2) {
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){ multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") { tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00A0DC" attributeState "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821"
attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff" attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
} }
} }

View File

@@ -33,7 +33,7 @@ metadata {
tiles { tiles {
standardTile("water", "device.water", width: 2, height: 2) { standardTile("water", "device.water", width: 2, height: 2) {
state "dry", icon:"st.alarm.water.dry", backgroundColor:"#ffffff" state "dry", icon:"st.alarm.water.dry", backgroundColor:"#ffffff"
state "wet", icon:"st.alarm.water.wet", backgroundColor:"#00A0DC" state "wet", icon:"st.alarm.water.wet", 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:""

File diff suppressed because it is too large Load Diff

View File

@@ -1,145 +0,0 @@
/**
* JSON
*
* Copyright 2015 Jesse Newland
*
* 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.
*
*/
definition(
name: "JSON API",
namespace: "jnewland",
author: "Jesse Newland",
description: "A JSON API for SmartThings",
category: "SmartThings Labs",
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
iconX3Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
oauth: true)
def installed() {
initialize()
}
def updated() {
unsubscribe()
initialize()
}
def initialize() {
if (!state.accessToken) {
createAccessToken()
}
}
preferences {
page(name: "copyConfig")
}
def copyConfig() {
if (!state.accessToken) {
createAccessToken()
}
dynamicPage(name: "copyConfig", title: "Config", install:true) {
section("Select devices to include in the /devices API call") {
input "switches", "capability.switch", title: "Switches", multiple: true, required: false
input "hues", "capability.colorControl", title: "Hues", multiple: true, required: false
}
section() {
paragraph "View this SmartApp's configuration to use it in other places."
href url:"https://graph.api.smartthings.com/api/smartapps/installations/${app.id}/config?access_token=${state.accessToken}", style:"embedded", required:false, title:"Config", description:"Tap, select, copy, then click \"Done\""
}
section() {
href url:"https://graph.api.smartthings.com/api/smartapps/installations/${app.id}/devices?access_token=${state.accessToken}", style:"embedded", required:false, title:"Debug", description:"View accessories JSON"
}
}
}
def renderConfig() {
def configJson = new groovy.json.JsonOutput().toJson([
description: "JSON API",
platforms: [
[
platform: "SmartThings",
name: "SmartThings",
app_id: app.id,
access_token: state.accessToken
]
],
])
def configString = new groovy.json.JsonOutput().prettyPrint(configJson)
render contentType: "text/plain", data: configString
}
def deviceCommandMap(device, type) {
device.supportedCommands.collectEntries { command->
def commandUrl = "https://graph.api.smartthings.com/api/smartapps/installations/${app.id}/${type}/${device.id}/command/${command.name}?access_token=${state.accessToken}"
[
(command.name): commandUrl
]
}
}
def authorizedDevices() {
[
switches: switches,
hues: hues
]
}
def renderDevices() {
def deviceData = authorizedDevices().collectEntries { devices->
[
(devices.key): devices.value.collect { device->
[
name: device.displayName,
commands: deviceCommandMap(device, devices.key)
]
}
]
}
def deviceJson = new groovy.json.JsonOutput().toJson(deviceData)
def deviceString = new groovy.json.JsonOutput().prettyPrint(deviceJson)
render contentType: "application/json", data: deviceString
}
def deviceCommand() {
def device = authorizedDevices()[params.type].find { it.id == params.id }
def command = params.command
if (!device) {
httpError(404, "Device not found")
} else {
if (params.value) {
device."$command"(params.value)
} else {
device."$command"()
}
}
}
mappings {
if (!params.access_token || (params.access_token && params.access_token != state.accessToken)) {
path("/devices") { action: [GET: "authError"] }
path("/config") { action: [GET: "authError"] }
path("/:type/:id/command/:command") { action: [PUT: "authError"] }
} else {
path("/devices") { action: [GET: "renderDevices"] }
path("/config") { action: [GET: "renderConfig"] }
path("/:type/:id/command/:command") { action: [PUT: "deviceCommand"] }
}
}
def authError() {
[error: "Permission denied"]
}