mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-10 13:21:52 +00:00
Compare commits
20 Commits
PROD_2017.
...
MSA-1956-3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
014ae02ad5 | ||
|
|
c58132a69e | ||
|
|
93544c4f60 | ||
|
|
7527fdd1bb | ||
|
|
b552bcc6f0 | ||
|
|
f069ea3087 | ||
|
|
10f51945f5 | ||
|
|
5816fe8a1e | ||
|
|
e763dde6aa | ||
|
|
ff8fd3d1a9 | ||
|
|
7e8baeeb0b | ||
|
|
ad824a9dd8 | ||
|
|
980bef6879 | ||
|
|
120935f14e | ||
|
|
032f4a92d4 | ||
|
|
6d528683e6 | ||
|
|
8bcbe7b924 | ||
|
|
69dd13f333 | ||
|
|
29c7049d60 | ||
|
|
03a79b8bb5 |
2
devicetypes/osotech/plantlink.src/.st-ignore
Normal file
2
devicetypes/osotech/plantlink.src/.st-ignore
Normal file
@@ -0,0 +1,2 @@
|
||||
.st-ignore
|
||||
README.md
|
||||
33
devicetypes/osotech/plantlink.src/README.md
Normal file
33
devicetypes/osotech/plantlink.src/README.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# Osotech Plant Link
|
||||
|
||||
Cloud Execution
|
||||
|
||||
Works with:
|
||||
|
||||
* [OSO Technologies PlantLink Soil Moisture Sensor](https://www.smartthings.com/works-with-smartthings/oso-technologies/oso-technologies-plantlink-soil-moisture-sensor)
|
||||
|
||||
## Table of contents
|
||||
|
||||
* [Capabilities](#capabilities)
|
||||
* [Health](#device-health)
|
||||
* [Troubleshooting](#troubleshooting)
|
||||
|
||||
## Capabilities
|
||||
|
||||
* **Sensor** - detects sensor events
|
||||
* **Health Check** - indicates ability to get device health notifications
|
||||
|
||||
## Device Health
|
||||
|
||||
Plant Link sensor is a ZigBee sleepy device and checks in every 15 minutes.
|
||||
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*15 + 2)mins = 32 mins.
|
||||
|
||||
* __32min__ checkInterval
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the sensor is out of range.
|
||||
Pairing needs to be tried again by placing the sensor closer to the hub.
|
||||
Instructions related to pairing, resetting and removing the different motion sensors from SmartThings can be found in the following links
|
||||
for the different models:
|
||||
* [OSO Technologies PlantLink Soil Moisture Sensor Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/206868986-PlantLink-Soil-Moisture-Sensor)
|
||||
@@ -24,6 +24,7 @@ import groovy.json.JsonBuilder
|
||||
metadata {
|
||||
definition (name: "PlantLink", namespace: "OsoTech", author: "Oso Technologies") {
|
||||
capability "Sensor"
|
||||
capability "Health Check"
|
||||
|
||||
command "setStatusIcon"
|
||||
command "setPlantFuelLevel"
|
||||
@@ -70,6 +71,16 @@ metadata {
|
||||
}
|
||||
}
|
||||
|
||||
def updated() {
|
||||
// Device-Watch allows 2 check-in misses from device
|
||||
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
||||
}
|
||||
|
||||
def installed() {
|
||||
// Device-Watch allows 2 check-in misses from device
|
||||
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
||||
}
|
||||
|
||||
def setStatusIcon(value){
|
||||
def status = ''
|
||||
switch (value) {
|
||||
@@ -161,4 +172,4 @@ def parseDescriptionAsMap(description) {
|
||||
map += []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ Works with:
|
||||
|
||||
## Device Health
|
||||
|
||||
Plant Link sensor is a Z-wave sleepy device and checks in every 15 minutes.
|
||||
Plant Link sensor is a ZigBee sleepy device and checks in every 15 minutes.
|
||||
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*15 + 2)mins = 32 mins.
|
||||
|
||||
* __32min__ checkInterval
|
||||
|
||||
2
devicetypes/smartthings/smartalert-siren.src/.st-ignore
Normal file
2
devicetypes/smartthings/smartalert-siren.src/.st-ignore
Normal file
@@ -0,0 +1,2 @@
|
||||
.st-ignore
|
||||
README.md
|
||||
39
devicetypes/smartthings/smartalert-siren.src/README.md
Normal file
39
devicetypes/smartthings/smartalert-siren.src/README.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# Smartalert Siren
|
||||
|
||||
Cloud Execution
|
||||
|
||||
Works with:
|
||||
|
||||
* [FortrezZ Siren Strobe Alarm](https://www.smartthings.com/works-with-smartthings/other/fortrezz-water-valve)
|
||||
|
||||
## Table of contents
|
||||
|
||||
* [Capabilities](#capabilities)
|
||||
* [Health](#device-health)
|
||||
* [Troubleshooting](#troubleshooting)
|
||||
|
||||
## Capabilities
|
||||
|
||||
* **Actuator** - represents that a Device has commands
|
||||
* **Switch** - can detect state (possible values: on/off)
|
||||
* **Sensor** - detects sensor events
|
||||
* **Alarm** - allows for interacting with devices that serve as alarms
|
||||
* **Health Check** - indicates ability to get device health notifications
|
||||
|
||||
## Device Health
|
||||
|
||||
FortrezZ Siren Strobe Alarm 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:
|
||||
* [FortrezZ Siren Strobe Alarm Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/202294760-FortrezZ-Siren-Strobe-Alarm)
|
||||
@@ -21,10 +21,12 @@ metadata {
|
||||
capability "Switch"
|
||||
capability "Sensor"
|
||||
capability "Alarm"
|
||||
capability "Health Check"
|
||||
|
||||
command "test"
|
||||
|
||||
fingerprint deviceId: "0x1100", inClusters: "0x26,0x71"
|
||||
fingerprint mfr:"0084", prod:"0313", model:"010B", deviceJoinName: "FortrezZ Siren Strobe Alarm"
|
||||
}
|
||||
|
||||
simulator {
|
||||
@@ -68,6 +70,16 @@ metadata {
|
||||
}
|
||||
}
|
||||
|
||||
def installed() {
|
||||
// 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])
|
||||
}
|
||||
|
||||
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])
|
||||
}
|
||||
|
||||
def on() {
|
||||
[
|
||||
zwave.basicV1.basicSet(value: 0xFF).format(),
|
||||
@@ -149,3 +161,10 @@ def createEvents(physicalgraph.zwave.commands.basicv1.BasicReport cmd)
|
||||
def zwaveEvent(physicalgraph.zwave.Command cmd) {
|
||||
log.warn "UNEXPECTED COMMAND: $cmd"
|
||||
}
|
||||
|
||||
/**
|
||||
* PING is used by Device-Watch in attempt to reach the Device
|
||||
* */
|
||||
def ping() {
|
||||
secure(zwave.basicV1.basicGet())
|
||||
}
|
||||
@@ -191,6 +191,10 @@ private List<Map> parseAxis(List<Map> attrData) {
|
||||
def y = hexToSignedInt(attrData.find { it.attrInt == 0x0013 }?.value)
|
||||
def z = hexToSignedInt(attrData.find { it.attrInt == 0x0014 }?.value)
|
||||
|
||||
if ([x, y ,z].any { it == null }) {
|
||||
return []
|
||||
}
|
||||
|
||||
def xyzResults = [:]
|
||||
if (device.getDataValue("manufacturer") == "SmartThings") {
|
||||
// This mapping matches the current behavior of the Device Handler for the Centralite sensors
|
||||
@@ -371,6 +375,10 @@ def updated() {
|
||||
}
|
||||
|
||||
private hexToSignedInt(hexVal) {
|
||||
if (!hexVal) {
|
||||
return null
|
||||
}
|
||||
|
||||
def unsignedVal = hexToInt(hexVal)
|
||||
unsignedVal > 32767 ? unsignedVal - 65536 : unsignedVal
|
||||
}
|
||||
|
||||
@@ -70,19 +70,27 @@ def parse(String description) {
|
||||
else {
|
||||
sendEvent(event)
|
||||
}
|
||||
}
|
||||
else {
|
||||
def cluster = zigbee.parse(description)
|
||||
if (cluster && cluster.clusterId == 0x0006 && cluster.command == 0x07) {
|
||||
if (cluster.data[0] == 0x00){
|
||||
} else {
|
||||
def descMap = zigbee.parseDescriptionAsMap(description)
|
||||
if (descMap && descMap.clusterInt == 0x0006 && descMap.commandInt == 0x07) {
|
||||
if (descMap.data[0] == "00") {
|
||||
log.debug "ON/OFF REPORTING CONFIG RESPONSE: " + cluster
|
||||
sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
log.warn "ON/OFF REPORTING CONFIG FAILED- error code:${cluster.data[0]}"
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else if (device.getDataValue("manufacturer") == "sengled" && descMap && descMap.clusterInt == 0x0008 && descMap.attrInt == 0x0000) {
|
||||
// This is being done because the sengled element touch incorrectly uses the value 0xFF for the max level.
|
||||
// Per the ZCL spec for the UINT8 data type 0xFF is an invalid value, and 0xFE should be the max. Here we
|
||||
// manually handle the invalid attribute value since it will be ignored by getEvent as an invalid value.
|
||||
// We also set the level of the bulb to 0xFE so future level reports will be 0xFE until it is changed by
|
||||
// something else.
|
||||
if (descMap.value.toUpperCase() == "FF") {
|
||||
descMap.value = "FE"
|
||||
}
|
||||
sendHubCommand(zigbee.command(zigbee.LEVEL_CONTROL_CLUSTER, 0x00, "FE0000").collect { new physicalgraph.device.HubAction(it) }, 0)
|
||||
sendEvent(zigbee.getEventFromAttrData(descMap.clusterInt, descMap.attrInt, descMap.encoding, descMap.value))
|
||||
} else {
|
||||
log.warn "DID NOT PARSE MESSAGE for description : $description"
|
||||
log.debug zigbee.parseDescriptionAsMap(description)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright 2016 SmartThings
|
||||
* Copyright 2017 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:
|
||||
@@ -64,6 +64,7 @@ private getATTRIBUTE_HUE() { 0x0000 }
|
||||
private getATTRIBUTE_SATURATION() { 0x0001 }
|
||||
private getHUE_COMMAND() { 0x00 }
|
||||
private getSATURATION_COMMAND() { 0x03 }
|
||||
private getMOVE_TO_HUE_AND_SATURATION_COMMAND() { 0x06 }
|
||||
private getCOLOR_CONTROL_CLUSTER() { 0x0300 }
|
||||
|
||||
// Parse incoming device messages to generate events
|
||||
@@ -84,11 +85,11 @@ def parse(String description) {
|
||||
|
||||
if (zigbeeMap?.clusterInt == COLOR_CONTROL_CLUSTER) {
|
||||
if(zigbeeMap.attrInt == ATTRIBUTE_HUE){ //Hue Attribute
|
||||
def hueValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 255 * 100)
|
||||
def hueValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 0xfe * 100)
|
||||
sendEvent(name: "hue", value: hueValue, descriptionText: "Color has changed")
|
||||
}
|
||||
else if(zigbeeMap.attrInt == ATTRIBUTE_SATURATION){ //Saturation Attribute
|
||||
def saturationValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 255 * 100)
|
||||
def saturationValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 0xfe * 100)
|
||||
sendEvent(name: "saturation", value: saturationValue, descriptionText: "Color has changed", displayed: false)
|
||||
}
|
||||
}
|
||||
@@ -123,7 +124,12 @@ def ping() {
|
||||
}
|
||||
|
||||
def refresh() {
|
||||
zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION) + zigbee.onOffConfig(0, 300) + zigbee.levelConfig() + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE, DataType.UINT8, 1, 3600, 0x01) + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION, DataType.UINT8, 1, 3600, 0x01)
|
||||
zigbee.onOffRefresh() +
|
||||
zigbee.levelRefresh() +
|
||||
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) +
|
||||
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION) +
|
||||
zigbee.onOffConfig(0, 300) +
|
||||
zigbee.levelConfig()
|
||||
}
|
||||
|
||||
def configure() {
|
||||
@@ -133,26 +139,38 @@ def configure() {
|
||||
sendEvent(name: "checkInterval", value: 3 * 10 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
||||
|
||||
// OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity
|
||||
zigbee.onOffConfig(0, 300) + zigbee.levelConfig() + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE, DataType.UINT8, 1, 3600, 0x01) + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION, DataType.UINT8, 1, 3600, 0x01) + zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
|
||||
refresh()
|
||||
}
|
||||
|
||||
def setLevel(value) {
|
||||
zigbee.setLevel(value)
|
||||
}
|
||||
|
||||
private getScaledHue(value) {
|
||||
zigbee.convertToHexString(Math.round(value * 0xfe / 100.0), 2)
|
||||
}
|
||||
|
||||
private getScaledSaturation(value) {
|
||||
zigbee.convertToHexString(Math.round(value * 0xfe / 100.0), 2)
|
||||
}
|
||||
|
||||
def setColor(value){
|
||||
log.trace "setColor($value)"
|
||||
zigbee.on() + setHue(value.hue) + "delay 500" + setSaturation(value.saturation)
|
||||
zigbee.on() +
|
||||
zigbee.command(COLOR_CONTROL_CLUSTER, MOVE_TO_HUE_AND_SATURATION_COMMAND,
|
||||
getScaledHue(value.hue), getScaledSaturation(value.saturation), "0000") +
|
||||
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) +
|
||||
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
|
||||
}
|
||||
|
||||
def setHue(value) {
|
||||
def scaledHueValue = zigbee.convertToHexString(Math.round(value * 0xfe / 100.0), 2)
|
||||
zigbee.command(COLOR_CONTROL_CLUSTER, HUE_COMMAND, scaledHueValue, "00", "0500") //payload-> hue value, direction (00-> shortest distance), transition time (1/10th second) (0500 in U16 reads 5)
|
||||
zigbee.command(COLOR_CONTROL_CLUSTER, HUE_COMMAND, getScaledHue(value), "00", "0000") +
|
||||
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE)
|
||||
}
|
||||
|
||||
def setSaturation(value) {
|
||||
def scaledSatValue = zigbee.convertToHexString(Math.round(value * 0xfe / 100.0), 2)
|
||||
zigbee.command(COLOR_CONTROL_CLUSTER, SATURATION_COMMAND, scaledSatValue, "0500") + "delay 1000" + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
|
||||
zigbee.command(COLOR_CONTROL_CLUSTER, SATURATION_COMMAND, getScaledSaturation(value), "0000") +
|
||||
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
|
||||
}
|
||||
|
||||
def installed() {
|
||||
@@ -161,4 +179,4 @@ def installed() {
|
||||
sendEvent(name: "level", value: 100)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright 2016 SmartThings
|
||||
* Copyright 2017 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:
|
||||
@@ -78,6 +78,7 @@ private getATTRIBUTE_HUE() { 0x0000 }
|
||||
private getATTRIBUTE_SATURATION() { 0x0001 }
|
||||
private getHUE_COMMAND() { 0x00 }
|
||||
private getSATURATION_COMMAND() { 0x03 }
|
||||
private getMOVE_TO_HUE_AND_SATURATION_COMMAND() { 0x06 }
|
||||
private getCOLOR_CONTROL_CLUSTER() { 0x0300 }
|
||||
private getATTRIBUTE_COLOR_TEMPERATURE() { 0x0007 }
|
||||
|
||||
@@ -102,11 +103,11 @@ def parse(String description) {
|
||||
|
||||
if (zigbeeMap?.clusterInt == COLOR_CONTROL_CLUSTER) {
|
||||
if(zigbeeMap.attrInt == ATTRIBUTE_HUE){ //Hue Attribute
|
||||
def hueValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 255 * 100)
|
||||
def hueValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 0xfe * 100)
|
||||
sendEvent(name: "hue", value: hueValue, descriptionText: "Color has changed")
|
||||
}
|
||||
else if(zigbeeMap.attrInt == ATTRIBUTE_SATURATION){ //Saturation Attribute
|
||||
def saturationValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 255 * 100)
|
||||
def saturationValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 0xfe * 100)
|
||||
sendEvent(name: "saturation", value: saturationValue, descriptionText: "Color has changed", displayed: false)
|
||||
}
|
||||
}
|
||||
@@ -141,7 +142,13 @@ def ping() {
|
||||
}
|
||||
|
||||
def refresh() {
|
||||
zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_COLOR_TEMPERATURE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION) + zigbee.onOffConfig(0, 300) + zigbee.levelConfig() + zigbee.colorTemperatureConfig() + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE, DataType.UINT8, 1, 3600, 0x01) + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION, DataType.UINT8, 1, 3600, 0x01)
|
||||
zigbee.onOffRefresh() +
|
||||
zigbee.levelRefresh() +
|
||||
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_COLOR_TEMPERATURE) +
|
||||
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) +
|
||||
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION) +
|
||||
zigbee.onOffConfig(0, 300) +
|
||||
zigbee.levelConfig()
|
||||
}
|
||||
|
||||
def configure() {
|
||||
@@ -156,7 +163,12 @@ def configure() {
|
||||
|
||||
def setColorTemperature(value) {
|
||||
setGenericName(value)
|
||||
zigbee.setColorTemperature(value)
|
||||
value = value as Integer
|
||||
def tempInMired = (1000000 / value) as Integer
|
||||
def finalHex = zigbee.swapEndianHex(zigbee.convertToHexString(tempInMired, 4))
|
||||
|
||||
zigbee.command(COLOR_CONTROL_CLUSTER, 0x0A, "$finalHex 0000") +
|
||||
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_COLOR_TEMPERATURE)
|
||||
}
|
||||
|
||||
//Naming based on the wiki article here: http://en.wikipedia.org/wiki/Color_temperature
|
||||
@@ -180,19 +192,31 @@ def setLevel(value) {
|
||||
zigbee.setLevel(value)
|
||||
}
|
||||
|
||||
private getScaledHue(value) {
|
||||
zigbee.convertToHexString(Math.round(value * 0xfe / 100.0), 2)
|
||||
}
|
||||
|
||||
private getScaledSaturation(value) {
|
||||
zigbee.convertToHexString(Math.round(value * 0xfe / 100.0), 2)
|
||||
}
|
||||
|
||||
def setColor(value){
|
||||
log.trace "setColor($value)"
|
||||
zigbee.on() + setHue(value.hue) + "delay 300" + setSaturation(value.saturation)
|
||||
zigbee.on() +
|
||||
zigbee.command(COLOR_CONTROL_CLUSTER, MOVE_TO_HUE_AND_SATURATION_COMMAND,
|
||||
getScaledHue(value.hue), getScaledSaturation(value.saturation), "0000") +
|
||||
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) +
|
||||
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
|
||||
}
|
||||
|
||||
def setHue(value) {
|
||||
def scaledHueValue = zigbee.convertToHexString(Math.round(value * 0xfe / 100.0), 2)
|
||||
zigbee.command(COLOR_CONTROL_CLUSTER, HUE_COMMAND, scaledHueValue, "00", "0500") //payload-> hue value, direction (00-> shortest distance), transition time (1/10th second) (0500 in U16 reads 5)
|
||||
zigbee.command(COLOR_CONTROL_CLUSTER, HUE_COMMAND, getScaledHue(value), "00", "0000") +
|
||||
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE)
|
||||
}
|
||||
|
||||
def setSaturation(value) {
|
||||
def scaledSatValue = zigbee.convertToHexString(Math.round(value * 0xfe / 100.0), 2)
|
||||
zigbee.command(COLOR_CONTROL_CLUSTER, SATURATION_COMMAND, scaledSatValue, "0500") + "delay 1000" + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
|
||||
zigbee.command(COLOR_CONTROL_CLUSTER, SATURATION_COMMAND, getScaledSaturation(value), "0000") +
|
||||
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
|
||||
}
|
||||
|
||||
def installed() {
|
||||
@@ -201,4 +225,4 @@ def installed() {
|
||||
sendEvent(name: "level", value: 100)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright 2015 SmartThings
|
||||
* Copyright 2017 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:
|
||||
@@ -71,6 +71,11 @@ metadata {
|
||||
}
|
||||
}
|
||||
|
||||
// Globals
|
||||
private getMOVE_TO_COLOR_TEMPERATURE_COMMAND() { 0x0A }
|
||||
private getCOLOR_CONTROL_CLUSTER() { 0x0300 }
|
||||
private getATTRIBUTE_COLOR_TEMPERATURE() { 0x0007 }
|
||||
|
||||
// Parse incoming device messages to generate events
|
||||
def parse(String description) {
|
||||
log.debug "description is $description"
|
||||
@@ -123,7 +128,11 @@ def ping() {
|
||||
}
|
||||
|
||||
def refresh() {
|
||||
zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh() + zigbee.onOffConfig(0, 300) + zigbee.levelConfig() + zigbee.colorTemperatureConfig()
|
||||
zigbee.onOffRefresh() +
|
||||
zigbee.levelRefresh() +
|
||||
zigbee.colorTemperatureRefresh() +
|
||||
zigbee.onOffConfig(0, 300) +
|
||||
zigbee.levelConfig()
|
||||
}
|
||||
|
||||
def configure() {
|
||||
@@ -138,7 +147,12 @@ def configure() {
|
||||
|
||||
def setColorTemperature(value) {
|
||||
setGenericName(value)
|
||||
zigbee.setColorTemperature(value)
|
||||
value = value as Integer
|
||||
def tempInMired = (1000000 / value) as Integer
|
||||
def finalHex = zigbee.swapEndianHex(zigbee.convertToHexString(tempInMired, 4))
|
||||
|
||||
zigbee.command(COLOR_CONTROL_CLUSTER, MOVE_TO_COLOR_TEMPERATURE_COMMAND, "$finalHex 0000") +
|
||||
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_COLOR_TEMPERATURE)
|
||||
}
|
||||
|
||||
//Naming based on the wiki article here: http://en.wikipedia.org/wiki/Color_temperature
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright 2016 SmartThings
|
||||
* Copyright 2017 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:
|
||||
@@ -55,6 +55,7 @@ private getATTRIBUTE_HUE() { 0x0000 }
|
||||
private getATTRIBUTE_SATURATION() { 0x0001 }
|
||||
private getHUE_COMMAND() { 0x00 }
|
||||
private getSATURATION_COMMAND() { 0x03 }
|
||||
private getMOVE_TO_HUE_AND_SATURATION_COMMAND() { 0x06 }
|
||||
private getCOLOR_CONTROL_CLUSTER() { 0x0300 }
|
||||
|
||||
// Parse incoming device messages to generate events
|
||||
@@ -72,11 +73,11 @@ def parse(String description) {
|
||||
|
||||
if (zigbeeMap?.clusterInt == COLOR_CONTROL_CLUSTER) {
|
||||
if(zigbeeMap.attrInt == ATTRIBUTE_HUE){ //Hue Attribute
|
||||
def hueValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 255 * 360)
|
||||
def hueValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 0xfe * 100)
|
||||
sendEvent(name: "hue", value: hueValue, displayed:false)
|
||||
}
|
||||
else if(zigbeeMap.attrInt == ATTRIBUTE_SATURATION){ //Saturation Attribute
|
||||
def saturationValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 255 * 100)
|
||||
def saturationValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 0xfe * 100)
|
||||
sendEvent(name: "saturation", value: saturationValue, displayed:false)
|
||||
}
|
||||
}
|
||||
@@ -108,28 +109,46 @@ def configure() {
|
||||
}
|
||||
|
||||
def configureAttributes() {
|
||||
zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE, DataType.UINT8, 1, 3600, 0x01) + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION, DataType.UINT8, 1, 3600, 0x01)
|
||||
zigbee.onOffConfig() +
|
||||
zigbee.levelConfig()
|
||||
}
|
||||
|
||||
def refreshAttributes() {
|
||||
zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
|
||||
zigbee.onOffRefresh() +
|
||||
zigbee.levelRefresh() +
|
||||
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) +
|
||||
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
|
||||
}
|
||||
|
||||
def setLevel(value) {
|
||||
zigbee.setLevel(value) + zigbee.onOffRefresh() + zigbee.levelRefresh() //adding refresh because of ZLL bulb not conforming to send-me-a-report
|
||||
}
|
||||
|
||||
private getScaledHue(value) {
|
||||
zigbee.convertToHexString(Math.round(value * 0xfe / 100.0), 2)
|
||||
}
|
||||
|
||||
private getScaledSaturation(value) {
|
||||
zigbee.convertToHexString(Math.round(value * 0xfe / 100.0), 2)
|
||||
}
|
||||
|
||||
def setColor(value){
|
||||
log.trace "setColor($value)"
|
||||
zigbee.on() + setHue(value.hue) + ["delay 300"] + setSaturation(value.saturation) + ["delay 2000"] + refreshAttributes()
|
||||
zigbee.on() +
|
||||
zigbee.command(COLOR_CONTROL_CLUSTER, MOVE_TO_HUE_AND_SATURATION_COMMAND,
|
||||
getScaledHue(value.hue), getScaledSaturation(value.saturation), "0000") +
|
||||
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) +
|
||||
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
|
||||
}
|
||||
|
||||
def setHue(value) {
|
||||
def scaledHueValue = zigbee.convertToHexString(Math.round(value * 0xfe / 100.0), 2)
|
||||
zigbee.command(COLOR_CONTROL_CLUSTER, HUE_COMMAND, scaledHueValue, "00", "0500") + ["delay 1500"] + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) //payload-> hue value, direction (00-> shortest distance), transition time (1/10th second) (0500 in U16 reads 5)
|
||||
//payload-> hue value, direction (00-> shortest distance), transition time (1/10th second)
|
||||
zigbee.command(COLOR_CONTROL_CLUSTER, HUE_COMMAND, getScaledHue(value), "00", "0000") +
|
||||
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE)
|
||||
}
|
||||
|
||||
def setSaturation(value) {
|
||||
def scaledSatValue = zigbee.convertToHexString(Math.round(value * 0xfe / 100.0), 2)
|
||||
zigbee.command(COLOR_CONTROL_CLUSTER, SATURATION_COMMAND, scaledSatValue, "0500") + ["delay 1500"] + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION) //payload-> sat value, transition time
|
||||
//payload-> sat value, transition time
|
||||
zigbee.command(COLOR_CONTROL_CLUSTER, SATURATION_COMMAND, getScaledSaturation(value), "0000") +
|
||||
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright 2016 SmartThings
|
||||
* Copyright 2017 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:
|
||||
@@ -70,6 +70,7 @@ private getATTRIBUTE_HUE() { 0x0000 }
|
||||
private getATTRIBUTE_SATURATION() { 0x0001 }
|
||||
private getHUE_COMMAND() { 0x00 }
|
||||
private getSATURATION_COMMAND() { 0x03 }
|
||||
private getMOVE_TO_HUE_AND_SATURATION_COMMAND() { 0x06 }
|
||||
private getCOLOR_CONTROL_CLUSTER() { 0x0300 }
|
||||
private getATTRIBUTE_COLOR_TEMPERATURE() { 0x0007 }
|
||||
|
||||
@@ -88,11 +89,11 @@ def parse(String description) {
|
||||
|
||||
if (zigbeeMap?.clusterInt == COLOR_CONTROL_CLUSTER) {
|
||||
if(zigbeeMap.attrInt == ATTRIBUTE_HUE){ //Hue Attribute
|
||||
def hueValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 255 * 360)
|
||||
def hueValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 0xfe * 100)
|
||||
sendEvent(name: "hue", value: hueValue, displayed:false)
|
||||
}
|
||||
else if(zigbeeMap.attrInt == ATTRIBUTE_SATURATION){ //Saturation Attribute
|
||||
def saturationValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 255 * 100)
|
||||
def saturationValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 0xfe * 100)
|
||||
sendEvent(name: "saturation", value: saturationValue, displayed:false)
|
||||
}
|
||||
}
|
||||
@@ -124,11 +125,16 @@ def configure() {
|
||||
}
|
||||
|
||||
def configureAttributes() {
|
||||
zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.colorTemperatureConfig() + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE, DataType.UINT8, 1, 3600, 0x01) + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION, DataType.UINT8, 1, 3600, 0x01)
|
||||
zigbee.onOffConfig() +
|
||||
zigbee.levelConfig()
|
||||
}
|
||||
|
||||
def refreshAttributes() {
|
||||
zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh() + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
|
||||
zigbee.onOffRefresh() +
|
||||
zigbee.levelRefresh() +
|
||||
zigbee.colorTemperatureRefresh() +
|
||||
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) +
|
||||
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
|
||||
}
|
||||
|
||||
def setColorTemperature(value) {
|
||||
@@ -139,17 +145,32 @@ def setLevel(value) {
|
||||
zigbee.setLevel(value) + zigbee.onOffRefresh() + zigbee.levelRefresh() //adding refresh because of ZLL bulb not conforming to send-me-a-report
|
||||
}
|
||||
|
||||
private getScaledHue(value) {
|
||||
zigbee.convertToHexString(Math.round(value * 0xfe / 100.0), 2)
|
||||
}
|
||||
|
||||
private getScaledSaturation(value) {
|
||||
zigbee.convertToHexString(Math.round(value * 0xfe / 100.0), 2)
|
||||
}
|
||||
|
||||
def setColor(value){
|
||||
log.trace "setColor($value)"
|
||||
zigbee.on() + setHue(value.hue) + ["delay 300"] + setSaturation(value.saturation) + ["delay 2000"] + refreshAttributes()
|
||||
zigbee.on() +
|
||||
zigbee.command(COLOR_CONTROL_CLUSTER, MOVE_TO_HUE_AND_SATURATION_COMMAND,
|
||||
getScaledHue(value.hue), getScaledSaturation(value.saturation), "0000") +
|
||||
zigbee.onOffRefresh() +
|
||||
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) +
|
||||
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
|
||||
}
|
||||
|
||||
def setHue(value) {
|
||||
def scaledHueValue = zigbee.convertToHexString(Math.round(value * 0xfe / 100.0), 2)
|
||||
zigbee.command(COLOR_CONTROL_CLUSTER, HUE_COMMAND, scaledHueValue, "00", "0500") + ["delay 1500"] + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) //payload-> hue value, direction (00-> shortest distance), transition time (1/10th second) (0500 in U16 reads 5)
|
||||
//payload-> hue value, direction (00-> shortest distance), transition time (1/10th second)
|
||||
zigbee.command(COLOR_CONTROL_CLUSTER, HUE_COMMAND, getScaledHue(value), "00", "0000") +
|
||||
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE)
|
||||
}
|
||||
|
||||
def setSaturation(value) {
|
||||
def scaledSatValue = zigbee.convertToHexString(Math.round(value * 0xfe / 100.0), 2)
|
||||
zigbee.command(COLOR_CONTROL_CLUSTER, SATURATION_COMMAND, scaledSatValue, "0500") + ["delay 1500"] + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION) //payload-> sat value, transition time
|
||||
//payload-> sat value, transition time
|
||||
zigbee.command(COLOR_CONTROL_CLUSTER, SATURATION_COMMAND, getScaledSaturation(value), "0000") +
|
||||
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright 2016 SmartThings
|
||||
* Copyright 2017 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:
|
||||
@@ -66,6 +66,11 @@ metadata {
|
||||
}
|
||||
}
|
||||
|
||||
// Globals
|
||||
private getMOVE_TO_COLOR_TEMPERATURE_COMMAND() { 0x0A }
|
||||
private getCOLOR_CONTROL_CLUSTER() { 0x0300 }
|
||||
private getATTRIBUTE_COLOR_TEMPERATURE() { 0x0007 }
|
||||
|
||||
// Parse incoming device messages to generate events
|
||||
def parse(String description) {
|
||||
log.debug "description is $description"
|
||||
@@ -95,14 +100,14 @@ def setLevel(value) {
|
||||
}
|
||||
|
||||
def refresh() {
|
||||
def cmds = zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh()
|
||||
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
|
||||
// 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 += zigbee.onOffConfig() + zigbee.levelConfig()
|
||||
}
|
||||
|
||||
cmds
|
||||
cmds
|
||||
}
|
||||
|
||||
def poll() {
|
||||
@@ -138,7 +143,7 @@ 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()
|
||||
zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh()
|
||||
}
|
||||
|
||||
def updated() {
|
||||
@@ -148,7 +153,12 @@ def updated() {
|
||||
|
||||
def setColorTemperature(value) {
|
||||
setGenericName(value)
|
||||
zigbee.setColorTemperature(value) + ["delay 1500"] + zigbee.colorTemperatureRefresh()
|
||||
value = value as Integer
|
||||
def tempInMired = (1000000 / value) as Integer
|
||||
def finalHex = zigbee.swapEndianHex(zigbee.convertToHexString(tempInMired, 4))
|
||||
|
||||
zigbee.command(COLOR_CONTROL_CLUSTER, MOVE_TO_COLOR_TEMPERATURE_COMMAND, "$finalHex 0000") +
|
||||
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_COLOR_TEMPERATURE)
|
||||
}
|
||||
|
||||
//Naming based on the wiki article here: http://en.wikipedia.org/wiki/Color_temperature
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright 2016 SmartThings
|
||||
* Copyright 2017 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:
|
||||
@@ -68,6 +68,11 @@ metadata {
|
||||
}
|
||||
}
|
||||
|
||||
// Globals
|
||||
private getMOVE_TO_COLOR_TEMPERATURE_COMMAND() { 0x0A }
|
||||
private getCOLOR_CONTROL_CLUSTER() { 0x0300 }
|
||||
private getATTRIBUTE_COLOR_TEMPERATURE() { 0x0007 }
|
||||
|
||||
// Parse incoming device messages to generate events
|
||||
def parse(String description) {
|
||||
log.debug "description is $description"
|
||||
@@ -94,7 +99,11 @@ def setLevel(value) {
|
||||
}
|
||||
|
||||
def refresh() {
|
||||
zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh() + zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.colorTemperatureConfig()
|
||||
zigbee.onOffRefresh() +
|
||||
zigbee.levelRefresh() +
|
||||
zigbee.colorTemperatureRefresh() +
|
||||
zigbee.onOffConfig() +
|
||||
zigbee.levelConfig()
|
||||
}
|
||||
|
||||
def poll() {
|
||||
@@ -129,8 +138,7 @@ def configureHealthCheck() {
|
||||
def configure() {
|
||||
log.debug "configure()"
|
||||
configureHealthCheck()
|
||||
zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.colorTemperatureConfig() + zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh()
|
||||
|
||||
refresh()
|
||||
}
|
||||
|
||||
def updated() {
|
||||
@@ -140,7 +148,12 @@ def updated() {
|
||||
|
||||
def setColorTemperature(value) {
|
||||
setGenericName(value)
|
||||
zigbee.setColorTemperature(value) + ["delay 1500"] + zigbee.colorTemperatureRefresh()
|
||||
value = value as Integer
|
||||
def tempInMired = (1000000 / value) as Integer
|
||||
def finalHex = zigbee.swapEndianHex(zigbee.convertToHexString(tempInMired, 4))
|
||||
|
||||
zigbee.command(COLOR_CONTROL_CLUSTER, MOVE_TO_COLOR_TEMPERATURE_COMMAND, "$finalHex 0000") +
|
||||
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_COLOR_TEMPERATURE)
|
||||
}
|
||||
|
||||
//Naming based on the wiki article here: http://en.wikipedia.org/wiki/Color_temperature
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Z-Wave Switch
|
||||
# Z-Wave Lock
|
||||
|
||||
Cloud Execution
|
||||
|
||||
@@ -6,7 +6,6 @@ Works with:
|
||||
|
||||
* [Yale Key Free Touchscreen Deadbolt (YRD240)](https://www.smartthings.com/works-with-smartthings/yale/yale-key-free-touchscreen-deadbolt-yrd240)
|
||||
|
||||
|
||||
## Table of contents
|
||||
|
||||
* [Capabilities](#capabilities)
|
||||
@@ -41,5 +40,3 @@ If the device doesn't pair when trying from the SmartThings mobile app, it is po
|
||||
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:
|
||||
* [General Z-Wave/ZigBee Yale Lock Troubleshooting](https://support.smartthings.com/hc/en-us/articles/205138400-How-to-connect-Yale-locks)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,273 @@
|
||||
/**
|
||||
* Lloyds Banking Group Connect & Protect
|
||||
*
|
||||
* Copyright 2016 Domotz
|
||||
*
|
||||
* 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: "Lloyds Banking Group Connect & Protect",
|
||||
namespace: "domotz.dev",
|
||||
author: "Domotz",
|
||||
description: "The Lloyds Connect & Protect SmartApp is a bridge between SmartThings Cloud and Lloyds Banking Group to enable advanced connected device monitoring and alerting features to be included in the offering to their customers for the connected home service",
|
||||
category: "Convenience",
|
||||
singleInstance: true,
|
||||
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: [displayName: "Lloyds Banking Group Connect & Protect", displayLink: ""]) {
|
||||
appSetting "endpointRetrievalUrl"
|
||||
appSetting "xApiKey"
|
||||
}
|
||||
|
||||
def getSupportedTypes() {
|
||||
return [
|
||||
[obj: switches, name: "switches", attribute: "switch", capability: "switch", title: "Switches"],
|
||||
[obj: motions, name: "motions", attribute: "motion", capability: "motionSensor", title: "Motion Sensors"],
|
||||
[obj: temperature, name: "temperature", attribute: "temperature", capability: "temperatureMeasurement", title: "Temperature Sensors"],
|
||||
[obj: contact, name: "contact", attribute: "contact", capability: "contactSensor", title: "Contact Sensors"],
|
||||
[obj: presence, name: "presence", attribute: "presence", capability: "presenceSensor", title: "Presence Sensors"],
|
||||
[obj: water, name: "water", attribute: "water", capability: "waterSensor", title: "Water Sensors"],
|
||||
[obj: smoke, name: "smoke", attribute: "smoke", capability: "smokeDetector", title: "Smoke Sensors"],
|
||||
[obj: battery, name: "battery", attribute: "battery", capability: "battery", title: "Batteries"]
|
||||
]
|
||||
}
|
||||
|
||||
preferences {
|
||||
section("Allow Lloyds Banking Group Connect & Protect service to monitor these devices") {
|
||||
for (type in getSupportedTypes()) {
|
||||
input type.get("name"), "capability.${type.get('capability')}", title: type.get('title'), multiple: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def installed() {
|
||||
initialize()
|
||||
}
|
||||
|
||||
def updated() {
|
||||
unsubscribe()
|
||||
initialize()
|
||||
hubUpdateHandler()
|
||||
|
||||
}
|
||||
|
||||
def getRequestHeaders() {
|
||||
return ['Accept': '*/*', 'X-API-KEY': appSettings.xApiKey]
|
||||
}
|
||||
|
||||
def subscribeToDeviceEvents() {
|
||||
for (type in getSupportedTypes()) {
|
||||
subscribe(type.get("obj"), "${type.get("attribute")}", genericDeviceEventHandler)
|
||||
}
|
||||
}
|
||||
|
||||
def initialize() {
|
||||
if (atomicState.endpoint != null) {
|
||||
log.debug "Detected endpoint: ${atomicState.endpoint}"
|
||||
subscribeToDeviceEvents()
|
||||
subscribe(location, "routineExecuted", modeChangeHandler)
|
||||
subscribe(location, "mode", modeChangeHandler)
|
||||
} else {
|
||||
log.debug "There is no endpoint, requesting domotz for a new one"
|
||||
requestNewEndpoint()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def getHubLocation() {
|
||||
def location_info = [:]
|
||||
location_info['uid'] = location.id
|
||||
//location_info['hubs'] = location.hubs
|
||||
location_info['latitude'] = location.latitude
|
||||
location_info['longitude'] = location.longitude
|
||||
location_info['current_mode'] = location.mode
|
||||
//location_info['modes'] = location.modes
|
||||
location_info['name'] = location.name
|
||||
location_info['temperature_scale'] = location.temperatureScale
|
||||
location_info['version'] = location.version
|
||||
location_info['channel_name'] = location.channelName
|
||||
location_info['zip_code'] = location.zipCode
|
||||
log.debug "Triggered getHubLocation with properties: ${location_info}"
|
||||
return location_info
|
||||
}
|
||||
|
||||
def modeChangeHandler(evt) {
|
||||
log.debug "mode changed to ${evt.value}"
|
||||
def url = null
|
||||
if (atomicState.endpoint != null) {
|
||||
url = atomicState.endpoint + '/hub-change'
|
||||
|
||||
httpPutJson(
|
||||
uri: url,
|
||||
body: getHubLocation(),
|
||||
headers: getRequestHeaders()
|
||||
)
|
||||
} else {
|
||||
log.debug "There is no endpoint, requesting domotz for a new one"
|
||||
requestNewEndpoint()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
def genericDeviceEventHandler(event) {
|
||||
log.debug "Device Event Handler, event properties: ${event.getProperties().toString()}"
|
||||
log.debug "Device Event Handler, value: ${event.value}"
|
||||
def resp = [:]
|
||||
def url = null
|
||||
def device = null
|
||||
|
||||
device = getDevice(event.device, resp)
|
||||
|
||||
url = atomicState.endpoint + "/device/" + device.provider_uid + "/${event.name}"
|
||||
|
||||
log.debug "Device Event Handler, put url: ${url}"
|
||||
log.debug "Device Event Handler, put body: value: ${event.value}\ndate: ${event.isoDate}"
|
||||
httpPutJson(
|
||||
uri: url,
|
||||
body: [
|
||||
"value": event.value,
|
||||
"time" : event.isoDate
|
||||
],
|
||||
headers: getRequestHeaders()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
def hubUpdateHandler() {
|
||||
log.debug "Hub Update Handler, with settings: ${settings}"
|
||||
def url = null
|
||||
def deviceList = [:]
|
||||
|
||||
if (atomicState.endpoint != null) {
|
||||
url = atomicState.endpoint + '/device-list'
|
||||
log.debug "Hub Update Event Handler, put url: ${url}"
|
||||
deviceList = getDeviceList()
|
||||
httpPutJson(
|
||||
uri: url,
|
||||
body: deviceList,
|
||||
headers: getRequestHeaders()
|
||||
)
|
||||
} else {
|
||||
log.debug "There is no endpoint, requesting domotz for a new one"
|
||||
requestNewEndpoint()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
def getDeviceList() {
|
||||
try {
|
||||
|
||||
def resp = [:]
|
||||
def attribute = null
|
||||
|
||||
for (type in getSupportedTypes()) {
|
||||
type.get("obj").each {
|
||||
device = getDevice(it, resp)
|
||||
attribute = type.get("attribute")
|
||||
if (it.currentState(attribute)) {
|
||||
device['attributes'][attribute] = [
|
||||
"value": it.currentState(attribute).value,
|
||||
"time" : it.currentState(attribute).getIsoDate(),
|
||||
"unit" : it.currentState(attribute).unit
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return resp
|
||||
} catch (e) {
|
||||
log.debug("caught exception", e)
|
||||
return [:]
|
||||
}
|
||||
}
|
||||
|
||||
def getDevice(it, resp) {
|
||||
if (resp[it.id]) {
|
||||
return resp[it.id]
|
||||
}
|
||||
resp[it.id] = [name: it.name, display_name: it.displayName, provider_uid: it.id, type: it.typeName, label: it.label, manufacturer_name: it.manufacturerName, model: it.modelName, attributes: [:]]
|
||||
|
||||
}
|
||||
|
||||
def activateMonitoring(resp) {
|
||||
unsubscribe()
|
||||
log.debug "Event monitoring activated for endpoint: ${request.JSON.endpoint}"
|
||||
atomicState.endpoint = request.JSON.endpoint
|
||||
log.debug "Event monitoring activated for endpoint: ${atomicState.endpoint}"
|
||||
initialize()
|
||||
}
|
||||
|
||||
def deactivateMonitoring() {
|
||||
log.debug "Event monitoring deactivated."
|
||||
atomicState.endpoint = null
|
||||
unsubscribe()
|
||||
}
|
||||
|
||||
def requestNewEndpoint() {
|
||||
log.debug "Requesting a new endpoint."
|
||||
def hubId = location.id
|
||||
def params = [
|
||||
uri : "${appSettings.endpointRetrievalUrl}/${hubId}/endpoint",
|
||||
headers: getRequestHeaders()
|
||||
]
|
||||
|
||||
try {
|
||||
httpGet(params) { response ->
|
||||
log.debug "Request was successful, received endpoint: ${response.data.endpoint}"
|
||||
atomicState.endpoint = response.data.endpoint
|
||||
subscribeToDeviceEvents()
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
log.debug "Unable to retrieve the endpoint"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
def handleClientUninstall() {
|
||||
log.info("Deactivated from client")
|
||||
try {
|
||||
app.delete()
|
||||
} catch (e) {
|
||||
unschedule()
|
||||
unsubscribe()
|
||||
httpError(500, "An error occurred during deleting SmartApp: ${e}")
|
||||
}
|
||||
}
|
||||
|
||||
mappings {
|
||||
path("/device") {
|
||||
action:
|
||||
[
|
||||
GET: getDeviceList
|
||||
]
|
||||
}
|
||||
path("/location") {
|
||||
action:
|
||||
[
|
||||
GET: getHubLocation
|
||||
]
|
||||
}
|
||||
path("/monitoring") {
|
||||
action:
|
||||
[
|
||||
POST : activateMonitoring,
|
||||
DELETE: deactivateMonitoring
|
||||
]
|
||||
}
|
||||
path("/uninstall") {
|
||||
action
|
||||
[GET: handleClientUninstall]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user