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

@@ -22,29 +22,28 @@ metadata {
capability "Temperature Measurement"
capability "Water Sensor"
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 mfr:"010F", prod:"0B01", model:"2002"
fingerprint mfr:"010F", prod:"0B01", model:"1002"
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x22, 0x85, 0x59, 0x20, 0x80, 0x70, 0x56, 0x5A, 0x7A, 0x72, 0x8E, 0x71, 0x73, 0x98, 0x9C, 0x31, 0x86", outClusters: ""
}
simulator {
}
tiles(scale: 2) {
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") {
attributeState("dry", icon:"st.alarm.water.dry", backgroundColor:"#00a0dc")
attributeState("wet", icon:"st.alarm.water.wet", backgroundColor:"#e86d13")
}
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
tiles(scale: 2) {
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") {
attributeState("dry", icon:"st.alarm.water.dry", backgroundColor:"#00a0dc")
attributeState("wet", icon:"st.alarm.water.wet", backgroundColor:"#e86d13")
}
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
attributeState("active", label:'tamper active', backgroundColor:"#00a0dc")
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}°',
backgroundColors:[
[value: 31, color: "#153591"],
@@ -56,22 +55,22 @@ metadata {
[value: 96, color: "#bc2323"]
]
}
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "battery", label:'${currentValue}% battery', unit:""
}
main "FGFS"
details(["FGFS","battery", "temperature"])
}
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "battery", label:'${currentValue}% battery', unit:""
}
main "FGFS"
details(["FGFS","battery", "temperature"])
}
}
// parse events into attributes
def parse(String description) {
log.debug "Parsing '${description}'"
def result = []
if (description.startsWith("Err 106")) {
if (description.startsWith("Err 106")) {
if (state.sec) {
result = createEvent(descriptionText:description, displayed:false)
} else {
@@ -86,13 +85,13 @@ def parse(String description) {
} else if (description == "updated") {
return null
} 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) {
log.debug "Parsed '${cmd}'"
zwaveEvent(cmd)
}
}
if (cmd) {
log.debug "Parsed '${cmd}'"
zwaveEvent(cmd)
}
}
}
//security
@@ -109,7 +108,7 @@ def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulat
//crc16
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 ccObj = version ? zwave.commandClass(cmd.commandClass, version) : zwave.commandClass(cmd.commandClass)
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 event = createEvent(descriptionText: "${device.displayName} woke up", displayed: false)
def cmds = []
// cmds << encap(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 1, scale: 0))
// cmds << "delay 500"
cmds << encap(zwave.batteryV1.batteryGet())
[event, response(cmds)]
def cmds = []
cmds << encap(zwave.batteryV1.batteryGet())
cmds << "delay 500"
cmds << encap(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 1, scale: 0))
cmds << "delay 1200"
cmds << encap(zwave.wakeUpV1.wakeUpNoMoreInformation())
[event, response(cmds)]
}
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
log.debug "manufacturerId: ${cmd.manufacturerId}"
log.debug "manufacturerName: ${cmd.manufacturerName}"
log.debug "productId: ${cmd.productId}"
log.debug "productTypeId: ${cmd.productTypeId}"
log.debug "manufacturerName: ${cmd.manufacturerName}"
log.debug "productId: ${cmd.productId}"
log.debug "productTypeId: ${cmd.productTypeId}"
}
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.DeviceSpecificReport cmd) {
log.debug "deviceIdData: ${cmd.deviceIdData}"
log.debug "deviceIdDataFormat: ${cmd.deviceIdDataFormat}"
log.debug "deviceIdDataLengthIndicator: ${cmd.deviceIdDataLengthIndicator}"
log.debug "deviceIdType: ${cmd.deviceIdType}"
if (cmd.deviceIdType == 1 && cmd.deviceIdDataFormat == 1) { //serial number in binary format
log.debug "deviceIdDataFormat: ${cmd.deviceIdDataFormat}"
log.debug "deviceIdDataLengthIndicator: ${cmd.deviceIdDataLengthIndicator}"
log.debug "deviceIdType: ${cmd.deviceIdType}"
if (cmd.deviceIdType == 1 && cmd.deviceIdDataFormat == 1) {//serial number in binary format
String serialNumber = "h'"
cmd.deviceIdData.each{ data ->
serialNumber += "${String.format("%02X", data)}"
}
updateDataValue("serialNumber", serialNumber)
log.debug "${device.displayName} - serial number: ${serialNumber}"
}
def 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)]
cmd.deviceIdData.each{ data ->
serialNumber += "${String.format("%02X", data)}"
}
updateDataValue("serialNumber", serialNumber)
log.debug "${device.displayName} - serial number: ${serialNumber}"
}
}
def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) {
updateDataValue("version", "${cmd.applicationVersion}.${cmd.applicationSubVersion}")
log.debug "applicationVersion: ${cmd.applicationVersion}"
log.debug "applicationSubVersion: ${cmd.applicationSubVersion}"
log.debug "zWaveLibraryType: ${cmd.zWaveLibraryType}"
log.debug "zWaveProtocolVersion: ${cmd.zWaveProtocolVersion}"
log.debug "zWaveProtocolSubVersion: ${cmd.zWaveProtocolSubVersion}"
def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) {
updateDataValue("version", "${cmd.applicationVersion}.${cmd.applicationSubVersion}")
log.debug "applicationVersion: ${cmd.applicationVersion}"
log.debug "applicationSubVersion: ${cmd.applicationSubVersion}"
log.debug "zWaveLibraryType: ${cmd.zWaveLibraryType}"
log.debug "zWaveProtocolVersion: ${cmd.zWaveProtocolVersion}"
log.debug "zWaveProtocolSubVersion: ${cmd.zWaveProtocolSubVersion}"
}
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
def result = []
def map = [:]
map.name = "battery"
map.value = cmd.batteryLevel == 255 ? 1 : cmd.batteryLevel.toString()
map.unit = "%"
result << createEvent(map)
if (!getDataValue("serialNumber")) {
result << response(encap(zwave.manufacturerSpecificV2.deviceSpecificGet()))
} else {
result << response(encap(zwave.wakeUpV2.wakeUpNoMoreInformation()))
}
result
map.displayed = true
createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) {
def map = [:]
if (cmd.notificationType == 5) {
switch (cmd.event) {
case 2:
map.name = "water"
map.value = "wet"
map.descriptionText = "${device.displayName} is ${map.value}"
if (cmd.notificationType == 5) {
switch (cmd.event) {
case 2:
map.name = "water"
map.value = "wet"
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
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
case 3:
map.name = "tamper"
map.value = "active"
map.descriptionText = "${device.displayName}: tamper alarm activated"
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 map = [:]
if (cmd.sensorType == 1) {
// temperature
def cmdScale = cmd.scale == 1 ? "F" : "C"
map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision)
map.unit = getTemperatureScale()
map.name = "temperature"
map.displayed = true
// temperature
def cmdScale = cmd.scale == 1 ? "F" : "C"
map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision)
map.unit = getTemperatureScale()
map.name = "temperature"
map.displayed = true
}
createEvent(map)
createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.deviceresetlocallyv1.DeviceResetLocallyNotification cmd) {
@@ -249,18 +229,21 @@ def zwaveEvent(physicalgraph.zwave.commands.deviceresetlocallyv1.DeviceResetLoca
def 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])
// default initial state
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()
def cmds = []
cmds << zwave.associationV2.associationSet(groupingIdentifier:1, nodeId: [zwaveHubNodeId])
cmds << zwave.batteryV1.batteryGet() // other queries sent as response to BatteryReport
encapSequence(cmds, 200)
encapSequence(cmds, 500)
}
private secure(physicalgraph.zwave.Command cmd) {
@@ -269,7 +252,7 @@ private secure(physicalgraph.zwave.Command cmd) {
private crc16(physicalgraph.zwave.Command cmd) {
//zwave.crc16EncapV1.crc16Encap().encapsulate(cmd).format()
"5601${cmd.format()}0000"
"5601${cmd.format()}0000"
}
private encapSequence(commands, delay=200) {
@@ -277,10 +260,13 @@ private encapSequence(commands, delay=200) {
}
private encap(physicalgraph.zwave.Command cmd) {
if (zwaveInfo.zw && !zwaveInfo.zw.contains("s")) {
// Secure inclusion failed
crc16(cmd)
} else {
secure(cmd)
}
}
def secureClasses = [0x20, 0x5A, 0x70, 0x71, 0x84, 0x85, 0x8E, 0x9C]
//todo: check if secure inclusion was successful
//if not do not send security-encapsulated command
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 "Alarm"
capability "Switch"
capability "Health Check"
command "test"
fingerprint deviceId: "0x1005", inClusters: "0x5E,0x98", deviceJoinName: "Aeon Labs Siren (Gen 5)"
fingerprint deviceId: "0x1005", inClusters: "0x5E,0x98"
}
simulator {
@@ -59,9 +58,6 @@ metadata {
}
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.volume) state.volume = 3
@@ -152,10 +148,3 @@ def test() {
private secure(physicalgraph.zwave.Command cmd) {
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: Fibaro Flood Sensor
* File Name: fibaro-flood-sensor.groovy
* Initial Release: 2014-12-10
* @author: Todd Wackford
* Email: todd@wackford.net
* @version: 1.0
* Device Type: Fibaro Flood Sensor
* File Name: fibaro-flood-sensor.groovy
* Initial Release: 2014-12-10
* @author: Todd Wackford
* Email: todd@wackford.net
* @version: 1.0
*
* Copyright 2014 SmartThings
*
@@ -26,8 +26,8 @@
* 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
* with the following:
* main(["water", "temperature", "tamper"])
* details(["water", "temperature", "battery", "tamper"])
* main(["water", "temperature", "tamper"])
* details(["water", "temperature", "battery", "tamper"])
*
* @param none
*
@@ -40,17 +40,14 @@ metadata {
capability "Configuration"
capability "Battery"
capability "Health Check"
capability "Sensor"
command "resetParams2StDefaults"
command "listCurrentParams"
command "updateZwaveParam"
command "test"
capability "Sensor"
command "resetParams2StDefaults"
command "listCurrentParams"
command "updateZwaveParam"
command "test"
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 {
@@ -91,9 +88,9 @@ metadata {
[value: 96, color: "#bc2323"]
]
}
standardTile("tamper", "device.tamper") {
state("secure", label:"secure", icon:"st.locks.lock.locked", backgroundColor:"#ffffff")
state("tampered", label:"tampered", icon:"st.locks.lock.unlocked", backgroundColor:"#53a7c0")
standardTile("tamper", "device.tamper") {
state("secure", label:"secure", icon:"st.locks.lock.locked", backgroundColor:"#ffffff")
state("tampered", label:"tampered", icon:"st.locks.lock.unlocked", backgroundColor:"#53a7c0")
}
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") {
state "battery", label:'${currentValue}% battery', unit:""
@@ -111,17 +108,26 @@ metadata {
def parse(String description)
{
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 (cmd) {
result += zwaveEvent(cmd) //createEvent(zwaveEvent(cmd))
}
if ( result[0] != null ) {
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) {
result += zwaveEvent(cmd) //createEvent(zwaveEvent(cmd))
}
}
result << response(zwave.batteryV1.batteryGet().format())
if ( result[0] != null ) {
log.debug "Parse returned ${result}"
result
}
}
}
@@ -138,9 +144,10 @@ def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) {
def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)]
if (!isConfigured()) {
// we're still in the process of configuring a newly joined device
result << lateConfigure(true)
result += lateConfigure(true)
} else {
result << response(zwave.wakeUpV1.wakeUpNoMoreInformation())
result += response(zwave.wakeUpV1.wakeUpNoMoreInformation())
log.debug "We're done with WakeUp!"
}
result
}
@@ -148,7 +155,7 @@ def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) {
def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv2.SensorMultilevelReport cmd)
{
def map = [:]
switch (cmd.sensorType) {
case 1:
// temperature
@@ -179,7 +186,7 @@ def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv1.SensorBinaryReport cm
def map = [:]
map.value = cmd.sensorValue ? "active" : "inactive"
map.name = "acceleration"
if (map.value == "active") {
map.descriptionText = "$device.displayName detected vibration"
}
@@ -194,49 +201,49 @@ def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport
}
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) {
log.debug "BasicSet with CMD = ${cmd}"
if (!isConfigured()) {
def result = []
def map = [:]
map.name = "water"
log.debug "BasicSet with CMD = ${cmd}"
if (!isConfigured()) {
def result = []
def map = [:]
map.name = "water"
map.value = cmd.value ? "wet" : "dry"
map.descriptionText = "${device.displayName} is ${map.value}"
// If we are getting a BasicSet, and isConfigured == false, then we are likely NOT properly configured.
result += lateConfigure(true)
result << createEvent(map)
result
}
// If we are getting a BasicSet, and isConfigured == false, then we are likely NOT properly configured.
result += lateConfigure(true)
result << createEvent(map)
result
}
}
def zwaveEvent(physicalgraph.zwave.commands.sensoralarmv1.SensorAlarmReport cmd)
{
def map = [:]
if (cmd.sensorType == 0x05) {
map.name = "water"
map.value = cmd.sensorState ? "wet" : "dry"
map.descriptionText = "${device.displayName} is ${map.value}"
log.debug "CMD = SensorAlarmReport: ${cmd}"
setConfigured()
} else if ( cmd.sensorType == 0) {
map.name = "tamper"
map.isStateChange = true
map.value = cmd.sensorState ? "tampered" : "secure"
map.descriptionText = "${device.displayName} has been tampered with"
runIn(30, "resetTamper") //device does not send alarm cancelation
} else if ( cmd.sensorType == 1) {
map.name = "tamper"
map.value = cmd.sensorState ? "tampered" : "secure"
map.descriptionText = "${device.displayName} has been tampered with"
runIn(30, "resetTamper") //device does not send alarm cancelation
log.debug "CMD = SensorAlarmReport: ${cmd}"
setConfigured()
} else if ( cmd.sensorType == 0) {
map.name = "tamper"
map.isStateChange = true
map.value = cmd.sensorState ? "tampered" : "secure"
map.descriptionText = "${device.displayName} has been tampered with"
runIn(30, "resetTamper") //device does not send alarm cancelation
} else if ( cmd.sensorType == 1) {
map.name = "tamper"
map.value = cmd.sensorState ? "tampered" : "secure"
map.descriptionText = "${device.displayName} has been tampered with"
runIn(30, "resetTamper") //device does not send alarm cancelation
} else {
map.descriptionText = "${device.displayName}: ${cmd}"
}
@@ -245,10 +252,10 @@ def zwaveEvent(physicalgraph.zwave.commands.sensoralarmv1.SensorAlarmReport cmd)
def resetTamper() {
def map = [:]
map.name = "tamper"
map.value = "secure"
map.descriptionText = "$device.displayName is secure"
sendEvent(map)
map.name = "tamper"
map.value = "secure"
map.descriptionText = "$device.displayName is secure"
sendEvent(map)
}
def zwaveEvent(physicalgraph.zwave.Command cmd) {
@@ -262,10 +269,10 @@ def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerS
def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)
log.debug "msr: $msr"
device.updateDataValue(["MSR", msr])
if ( msr == "010F-0B00-2001" ) { //this is the msr and device type for the fibaro flood sensor
result += lateConfigure(true)
}
if ( msr == "010F-0B00-2001" ) { //this is the msr and device type for the fibaro flood sensor
result += lateConfigure(true)
}
result << createEvent(descriptionText: "$device.displayName MSR: $msr", isStateChange: false)
result
@@ -277,17 +284,17 @@ def setConfigured() {
def isConfigured() {
Boolean configured = device.getDataValue(["configured"]) as Boolean
return configured
return configured
}
def lateConfigure(setConf = False) {
def res = response(configure())
if (setConf)
setConfigured()
return res
if (setConf)
setConfigured()
return res
}
/**
@@ -299,34 +306,29 @@ def lateConfigure(setConf = False) {
*/
def configure() {
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])
// default initial state
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()
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()
// 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()
def cmds = []
// send associate to group 2 to get alarm data
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()
// 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()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 12).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()
delayBetween(cmds, 100)
}
@@ -352,18 +354,18 @@ def test() {
* @return none
*/
def updateZwaveParam(params) {
if ( params ) {
def pNumber = params.paramNumber
def pSize = params.size
def pValue = [params.value]
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}'"
if ( params ) {
def pNumber = params.paramNumber
def pSize = params.size
def pValue = [params.value]
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}'"
def cmds = []
cmds << zwave.configurationV1.configurationSet(configurationValue: pValue, parameterNumber: pNumber, size: pSize).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: pNumber).format()
delayBetween(cmds, 1000)
}
cmds << zwave.configurationV1.configurationSet(configurationValue: pValue, parameterNumber: pNumber, size: pSize).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: pNumber).format()
delayBetween(cmds, 1000)
}
}
/**
@@ -380,26 +382,26 @@ def updateZwaveParam(params) {
def resetParams2StDefaults() {
log.debug "Resetting ${device.displayName} parameters to SmartThings compatible defaults"
def cmds = []
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: [255], parameterNumber: 5, 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: [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], parameterNumber: 13, size: 1).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: [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: [2], parameterNumber: 63, size: 1).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: [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], parameterNumber: 77, size: 1).format()
delayBetween(cmds, 1200)
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: [255], parameterNumber: 5, 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: [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], parameterNumber: 13, size: 1).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: [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: [2], parameterNumber: 63, size: 1).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: [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], parameterNumber: 77, size: 1).format()
delayBetween(cmds, 1200)
}
/**
@@ -416,25 +418,25 @@ def resetParams2StDefaults() {
def listCurrentParams() {
log.debug "Listing of current parameter settings of ${device.displayName}"
def cmds = []
cmds << zwave.configurationV1.configurationGet(parameterNumber: 1).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 2).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 5).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 7).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 9).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 10).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 12).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 13).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 50).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 51).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 61).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 62).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 63).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 73).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 74).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 75).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 76).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 77).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 1).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 2).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 5).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 7).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 9).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 10).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 12).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 13).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 50).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 51).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 61).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 62).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 63).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 73).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 74).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 75).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 76).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 77).format()
delayBetween(cmds, 1200)
}

View File

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

View File

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

View File

@@ -45,8 +45,8 @@ metadata {
tiles(scale: 2) {
multiAttributeTile(name: "contact", type: "generic", width: 6, height: 4) {
tileAttribute("device.contact", key: "PRIMARY_CONTROL") {
attributeState "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#e86d13"
attributeState "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#00A0DC"
attributeState "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#ffa81e"
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 {
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"
}
standardTile("switchOn", "device.switch", inactiveLabel: false, decoration: "flat") {

View File

@@ -51,7 +51,7 @@ metadata {
// tile definitions
tiles {
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"
}
valueTile("power", "device.power") {

View File

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

View File

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

View File

@@ -47,7 +47,7 @@ metadata {
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.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"
}
}

View File

@@ -46,7 +46,7 @@ metadata {
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.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"
}
}

View File

@@ -33,7 +33,7 @@ metadata {
tiles {
standardTile("water", "device.water", width: 2, height: 2) {
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") {
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"]
}