Compare commits

..

1 Commits

Author SHA1 Message Date
Jungle
5dedaf2eb6 MSA-1534: Leedarson CCT Bulb 2016-10-17 22:25:42 -05:00
19 changed files with 284 additions and 1059 deletions

View File

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

View File

@@ -1,45 +0,0 @@
# Z-wave Dimmer Switch
Works with:
* [GE Z-Wave In-Wall Smart Dimmer (GE 12724)](http://products.z-wavealliance.org/products/1197)
* [GE Z-Wave In-Wall Smart Dimmer (Toggle) (GE 12729)](http://products.z-wavealliance.org/products/1201)
* [GE Z-Wave Plug-in Smart Dimmer (GE 12718)](http://products.z-wavealliance.org/products/1191)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Troubleshooting](#Troubleshooting)
## Capabilities
* **Switch Level** - it's defined to accept two parameters, the level and the rate of dimming
* **Actuator** - represents that a Device has commands
* **Indicator** - gives you the ability to set the indicator LED light on a Z-Wave switch
* **Switch** - can detect state (possible values: on/off)
* **Polling** - represents that poll() can be implemented for the device
* **Refresh** - _refresh()_ command for status updates
* **Sensor** - detects sensor events
* **Health Check** - indicates ability to get device health notifications
## Device Health
Z-Wave Smart Dimmers (In-Wall, In-Wall(Toggle), Plug-In) are 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.
Check-in interval = 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.
## 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:
* [General Z-Wave Dimmer/Switch Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/200955890-Troubleshooting-GE-in-wall-switch-or-dimmer-won-t-respond-to-commands-or-automations-Z-Wave-)
* [GE Z-Wave In-Wall Smart Dimmer (GE 12724) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/200902600-GE-In-Wall-Paddle-Dimmer-Switch-GE-12724-Z-Wave-)
* [GE Z-Wave In-Wall Smart Dimmer (Toggle) (GE 12729) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/207568463-GE-In-Wall-Smart-Toggle-Dimmer-GE-12729-Z-Wave-)
* [GE Z-Wave Plug-in Smart Dimmer (GE 12718) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/202088474-GE-Plug-In-Smart-Dimmer-GE-12718-Z-Wave-)

View File

@@ -20,7 +20,6 @@ metadata {
capability "Polling"
capability "Refresh"
capability "Sensor"
capability "Health Check"
fingerprint mfr:"0063", prod:"4457", deviceJoinName: "Z-Wave Wall Dimmer"
fingerprint mfr:"0063", prod:"4944", deviceJoinName: "Z-Wave Wall Dimmer"
@@ -83,8 +82,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])
switch (ledIndicator) {
case "on":
indicatorWhenOn()
@@ -218,13 +215,6 @@ def poll() {
zwave.switchMultilevelV1.switchMultilevelGet().format()
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
refresh()
}
def refresh() {
log.debug "refresh() is called"
def commands = []

View File

@@ -0,0 +1,267 @@
/**
* Leedarson Light
*
* Copyright 2016 Jungle
*
* 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.
*
*/
/*
Osram Tunable White 60 A19 bulb
Osram bulbs have a firmware issue causing it to forget its dimming level when turned off (via commands). Handling
that issue by using state variables
*/
//DEPRECATED - Using the generic DTH for this device. Users need to be moved before deleting this DTH
metadata {
definition (name: "LEEDARSON LED Tunable White", namespace: "smartthings", author: "Yechi") {
capability "Color Temperature"
capability "Actuator"
capability "Switch"
capability "Switch Level"
capability "Configuration"
capability "Refresh"
capability "Sensor"
attribute "colorName", "string"
}
// simulator metadata
simulator {
// status messages
status "on": "on/off: 1"
status "off": "on/off: 0"
// reply messages
reply "zcl on-off on": "on/off: 1"
reply "zcl on-off off": "on/off: 0"
}
// UI tile definitions
tiles {
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
state "on", label: '${name}', action: "switch.off", icon: "st.switches.light.on", backgroundColor: "#79b821"
state "off", label: '${name}', action: "switch.on", icon: "st.switches.light.off", backgroundColor: "#ffffff"
}
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
}
controlTile("colorTempSliderControl", "device.colorTemperature", "slider", height: 1, width: 2, inactiveLabel: false, range:"(2700..5000)") {
state "colorTemperature", action:"color temperature.setColorTemperature"
}
valueTile("colorTemp", "device.colorTemperature", inactiveLabel: false, decoration: "flat") {
state "colorTemperature", label: '${currentValue} K'
}
valueTile("colorName", "device.colorName", inactiveLabel: false, decoration: "flat") {
state "colorName", label: '${currentValue}'
}
controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 2, inactiveLabel: false, range:"(0..100)") {
state "level", action:"switch level.setLevel"
}
valueTile("level", "device.level", inactiveLabel: false, decoration: "flat") {
state "level", label: 'Level ${currentValue}%'
}
main(["switch"])
details(["switch", "refresh", "colorName", "levelSliderControl", "level", "colorTempSliderControl", "colorTemp"])
}
}
// Parse incoming device messages to generate events
def parse(String description) {
//log.trace description
if (description?.startsWith("catchall:")) {
if(description?.endsWith("0100") ||description?.endsWith("1001") || description?.matches("on/off\\s*:\\s*1"))
{
def result = createEvent(name: "switch", value: "on")
log.debug "Parse returned ${result?.descriptionText}"
return result
}
else if(description?.endsWith("0000") || description?.endsWith("1000") || description?.matches("on/off\\s*:\\s*0"))
{
def result = createEvent(name: "switch", value: "off")
log.debug "Parse returned ${result?.descriptionText}"
return result
}
}
else if (description?.startsWith("read attr -")) {
def descMap = parseDescriptionAsMap(description)
log.trace "descMap : $descMap"
if (descMap.cluster == "0300") {
log.debug descMap.value
def tempInMired = convertHexToInt(descMap.value)
def tempInKelvin = Math.round(1000000/tempInMired)
log.trace "temp in kelvin: $tempInKelvin"
sendEvent(name: "colorTemperature", value: tempInKelvin, displayed:false)
}
else if(descMap.cluster == "0008"){
def dimmerValue = Math.round(convertHexToInt(descMap.value) * 100 / 255)
log.debug "dimmer value is $dimmerValue"
sendEvent(name: "level", value: dimmerValue)
}
}
else {
def name = description?.startsWith("on/off: ") ? "switch" : null
def value = name == "switch" ? (description?.endsWith(" 1") ? "on" : "off") : null
def result = createEvent(name: name, value: value)
log.debug "Parse returned ${result?.descriptionText}"
return result
}
}
def on() {
log.debug "on()"
sendEvent(name: "switch", value: "on")
setLevel(state?.levelValue)
}
def off() {
log.debug "off()"
sendEvent(name: "switch", value: "off")
"st cmd 0x${device.deviceNetworkId} ${endpointId} 6 0 {}"
}
def refresh() {
[
"st rattr 0x${device.deviceNetworkId} ${endpointId} 6 0", "delay 500",
"st rattr 0x${device.deviceNetworkId} ${endpointId} 8 0", "delay 500",
"st rattr 0x${device.deviceNetworkId} ${endpointId} 0x0300 7"
]
}
def configure() {
state.levelValue = 100
log.debug "Configuring Reporting and Bindings."
def configCmds = [
"zdo bind 0x${device.deviceNetworkId} ${endpointId} 1 0x0300 {${device.zigbeeId}} {}", "delay 500"
]
return onOffConfig() + levelConfig() + configCmds + refresh() // send refresh cmds as part of config
}
def onOffConfig() {
[
"zdo bind 0x${device.deviceNetworkId} ${endpointId} 1 6 {${device.zigbeeId}} {}", "delay 200",
"zcl global send-me-a-report 6 0 0x10 0 300 {01}",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 1500"
]
}
//level config for devices with min reporting interval as 5 seconds and reporting interval if no activity as 1hour (3600s)
//min level change is 01
def levelConfig() {
[
"zdo bind 0x${device.deviceNetworkId} ${endpointId} 1 8 {${device.zigbeeId}} {}", "delay 200",
"zcl global send-me-a-report 8 0 0x20 5 3600 {01}",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 1500"
]
}
def setColorTemperature(value) {
if(value<101){
value = (value*23) + 2700 //Calculation of mapping 0-100 to 2700-6500
}
def tempInMired = Math.round(1000000/value)
def finalHex = swapEndianHex(hex(tempInMired, 4))
def genericName = getGenericName(value)
log.debug "generic name is : $genericName"
def cmds = []
sendEvent(name: "colorTemperature", value: value, displayed:false)
sendEvent(name: "colorName", value: genericName)
cmds << "st cmd 0x${device.deviceNetworkId} ${endpointId} 0x0300 0x0a {${finalHex} 2000}"
cmds
}
def parseDescriptionAsMap(description) {
(description - "read attr - ").split(",").inject([:]) { map, param ->
def nameAndValue = param.split(":")
map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
}
}
def setLevel(value) {
state.levelValue = (value==null) ? 100 : value
log.trace "setLevel($value)"
def cmds = []
if (value == 0) {
sendEvent(name: "switch", value: "off")
cmds << "st cmd 0x${device.deviceNetworkId} ${endpointId} 6 0 {}"
}
else if (device.latestValue("switch") == "off") {
sendEvent(name: "switch", value: "on")
}
sendEvent(name: "level", value: state.levelValue)
def level = hex(state.levelValue * 254 / 100)
cmds << "st cmd 0x${device.deviceNetworkId} ${endpointId} 8 4 {${level} 0000}"
//log.debug cmds
cmds
}
//Naming based on the wiki article here: http://en.wikipedia.org/wiki/Color_temperature
private getGenericName(value){
def genericName = "White"
if(value < 3300){
genericName = "Soft White"
} else if(value < 4150){
genericName = "Moonlight"
} else if(value < 5000){
genericName = "Cool White"
} else if(value <= 6500){
genericName = "Daylight"
}
genericName
}
private getEndpointId() {
new BigInteger(device.endpointId, 16).toString()
}
private hex(value, width=2) {
def s = new BigInteger(Math.round(value).toString()).toString(16)
while (s.size() < width) {
s = "0" + s
}
s
}
private String swapEndianHex(String hex) {
reverseArray(hex.decodeHex()).encodeHex()
}
private Integer convertHexToInt(hex) {
Integer.parseInt(hex,16)
}
//Need to reverse array of size 2
private byte[] reverseArray(byte[] array) {
byte tmp;
tmp = array[1];
array[1] = array[0];
array[0] = tmp;
return array
}

View File

@@ -143,7 +143,7 @@ def refresh() {
def configure() {
// Device-Watch allows 3 check-in misses from device (plus 1 min lag time)
// enrolls with default periodic reporting until newer 5 min interval is confirmed
sendEvent(name: "checkInterval", value: 3 * 10 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
sendEvent(name: "checkInterval", value: 3 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
// OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity
refresh() + zigbee.onOffConfig(0, 300) + powerConfig()

View File

@@ -104,7 +104,7 @@ def configure() {
log.debug "Configuring Reporting and Bindings."
// Device-Watch allows 3 check-in misses from device (plus 1 min lag time)
// enrolls with default periodic reporting until newer 5 min interval is confirmed
sendEvent(name: "checkInterval", value: 3 * 10 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
sendEvent(name: "checkInterval", value: 3 * 60 * 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.onOffRefresh() + zigbee.levelRefresh() + zigbee.onOffConfig(0, 300) + zigbee.levelConfig()

View File

@@ -28,8 +28,8 @@ metadata {
capability "Switch Level"
capability "Health Check"
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Gardenspot RGB", deviceJoinName: "OSRAM LIGHTIFY Gardenspot mini RGB"
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY Gardenspot RGB", deviceJoinName: "OSRAM LIGHTIFY Gardenspot mini RGB"
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Gardenspot RGB"
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY Gardenspot RGB"
}
// UI tile definitions

View File

@@ -145,7 +145,7 @@ def configure() {
log.debug "Configuring Reporting and Bindings."
// Device-Watch allows 3 check-in misses from device (plus 1 min lag time)
// enrolls with default periodic reporting until newer 5 min interval is confirmed
sendEvent(name: "checkInterval", value: 3 * 10 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
sendEvent(name: "checkInterval", value: 3 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
// OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity
refresh()

View File

@@ -37,6 +37,7 @@ metadata {
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Classic A60 TW", deviceJoinName: "OSRAM LIGHTIFY LED Tunable White 60W"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY A19 Tunable White", deviceJoinName: "OSRAM LIGHTIFY LED Tunable White 60W"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Classic B40 TW - LIGHTIFY", deviceJoinName: "OSRAM LIGHTIFY Classic B40 Tunable White"
fingerprint profileId: "0104", deviceId: "0102", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "Eaton", model: "Halo_LT01", deviceJoinName: "Halo_LT01"
}
// UI tile definitions
@@ -128,7 +129,7 @@ def configure() {
log.debug "Configuring Reporting and Bindings."
// Device-Watch allows 3 check-in misses from device (plus 1 min lag time)
// enrolls with default periodic reporting until newer 5 min interval is confirmed
sendEvent(name: "checkInterval", value: 3 * 10 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
sendEvent(name: "checkInterval", value: 3 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
// OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity
refresh()
@@ -154,4 +155,4 @@ def setGenericName(value){
}
sendEvent(name: "colorName", value: genericName)
}
}
}

View File

@@ -11,9 +11,6 @@
* for the specific language governing permissions and limitations under the License.
*
*/
import groovy.transform.Field
@Field Boolean hasConfiguredHealthCheck = false
metadata {
definition (name: "ZLL Dimmer Bulb", namespace: "smartthings", author: "SmartThings") {
@@ -24,7 +21,6 @@ metadata {
capability "Refresh"
capability "Switch"
capability "Switch Level"
capability "Health Check"
//fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0000,0019"
fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019"
@@ -100,38 +96,7 @@ def poll() {
refresh()
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
return zigbee.levelRefresh()
}
def healthPoll() {
log.debug "healthPoll()"
def cmds = refresh()
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()"
log.debug "Configuring Reporting and Bindings."
zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.onOffRefresh() + zigbee.levelRefresh()
configureHealthCheck()
}
def updated() {
log.debug "updated()"
configureHealthCheck()
}

View File

@@ -11,9 +11,6 @@
* 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", namespace: "smartthings", author: "SmartThings") {
@@ -25,7 +22,6 @@ metadata {
capability "Refresh"
capability "Switch"
capability "Switch Level"
capability "Health Check"
attribute "colorName", "string"
command "setGenericName"
@@ -100,41 +96,9 @@ 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()
log.debug "Configuring Reporting and Bindings."
zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.colorTemperatureConfig() + zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh()
}
def updated() {
log.debug "updated()"
configureHealthCheck()
}
def setColorTemperature(value) {

View File

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

View File

@@ -1,39 +0,0 @@
# Z-wave Switch
Works with:
* [Leviton Appliance Module (DZPA1-1LW)](https://support.smartthings.com/hc/en-us/articles/205881176-Leviton-Appliance-Module-DZPA1-1LW-)
* [GE Plug-In Outdoor Smart Switch (GE 12720) (Z-Wave)](https://support.smartthings.com/hc/en-us/articles/200903080-GE-Plug-In-Outdoor-Smart-Switch-GE-12720-Z-Wave-)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
## Capabilities
* **Actuator** - represents that a Device has commands
* **Health Check** - indicates ability to get device health notifications
* **Switch** - can detect state (possible values: on/off)
* **Polling** - represents that poll() can be implemented for the device
* **Refresh** - _refresh()_ command for status updates
* **Sensor** - detects sensor events
## Device Health
A Category C5 Leviton Appliance Module (DZPA1-1LW) and GE Plug-In Outdoor Smart Switch (GE 12720) (Z-Wave) 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.
## 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:
* [Leviton Appliance Module (DZPA1-1LW) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/205881176-Leviton-Appliance-Module-DZPA1-1LW-)
* [GE Plug-In Outdoor Smart Switch (GE 12720) (Z-Wave) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/200903080-GE-Plug-In-Outdoor-Smart-Switch-GE-12720-Z-Wave-)

View File

@@ -14,15 +14,12 @@
metadata {
definition (name: "Z-Wave Switch Generic", namespace: "smartthings", author: "SmartThings") {
capability "Actuator"
capability "Health Check"
capability "Switch"
capability "Polling"
capability "Refresh"
capability "Sensor"
fingerprint inClusters: "0x25", deviceJoinName: "Z-Wave Switch"
fingerprint mfr:"001D", prod:"1A02", deviceJoinName: "Z-Wave Switch"
fingerprint mfr:"0063", prod:"4F50", deviceJoinName: "Z-Wave Switch"
}
// simulator metadata
@@ -53,11 +50,6 @@ metadata {
}
}
def updated(){
// Device-Watch simply pings if no device events received for checkInterval duration of 32min = 2 * 15min + 2min lag time
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
}
def parse(String description) {
def result = null
def cmd = zwave.parse(description, [0x20: 1, 0x70: 1])
@@ -134,13 +126,6 @@ def poll() {
])
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
refresh()
}
def refresh() {
delayBetween([
zwave.switchBinaryV1.switchBinaryGet().format(),

View File

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

View File

@@ -1,49 +0,0 @@
# Z-Wave Switch
Works with:
* [GE Z-Wave Plug-In Smart Switch (12719)](http://products.z-wavealliance.org/products/1193)
* [GE Z-Wave In-Wall Smart Outlet (12721)](http://products.z-wavealliance.org/products/1195)
* [GE Z-Wave In-Wall Smart Switch (12722)](http://products.z-wavealliance.org/products/1196)
* [GE Z-Wave In-Wall Smart Toggle Switch (12727)](http://products.z-wavealliance.org/products/1200)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Troubleshooting](#Troubleshooting)
## Capabilities
* **Actuator** - represents that a Device has commands
* **Indicator** - gives you the ability to set the indicator LED light on a Z-Wave switch
* **Switch** - can detect state (possible values: on/off)
* **Polling** - represents that poll() can be implemented for the device
* **Refresh** - _refresh()_ command for status updates
* **Sensor** - detects sensor events
* **Health Check** - indicates ability to get device health notifications
## Device Health
Z-Wave Switches (Plug-In, In-Wall(Toggle Switch, Switch, Outlet)) are 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.
## 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:
* [General Z-Wave Dimmer/Switch Troubleshooting](https://support.smartthings.com/hc/en-us/articles/200955890-Troubleshooting-GE-in-wall-switch-or-dimmer-won-t-respond-to-commands-or-automations-Z-Wave-)
* [GE Z-Wave Plug-In Smart Switch (12719) Troubleshooting](https://support.smartthings.com/hc/en-us/articles/200903070-GE-Plug-In-Smart-Switch-GE-12719-Z-Wave)
* [GE Z-Wave In-Wall Smart Outlet (12721) Troubleshooting](https://support.smartthings.com/hc/en-us/articles/200903020-GE-In-Wall-Smart-Outlet-GE-12721-Z-Wave)
* [GE Z-Wave In-Wall Smart Switch (12722) Troubleshooting](https://support.smartthings.com/hc/en-us/articles/200902540-GE-In-Wall-Smart-Switch-GE-12722-Z-Wave)
* [GE Z-Wave In-Wall Smart Toggle Switch (12727) Troubleshooting](https://support.smartthings.com/hc/en-us/articles/207568933-GE-In-Wall-Smart-Toggle-Switch-GE-12727-Z-Wave)

View File

@@ -19,7 +19,6 @@ metadata {
capability "Polling"
capability "Refresh"
capability "Sensor"
capability "Health Check"
fingerprint mfr:"0063", prod:"4952", deviceJoinName: "Z-Wave Wall Switch"
fingerprint mfr:"0063", prod:"5257", deviceJoinName: "Z-Wave Wall Switch"
@@ -65,8 +64,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])
switch (ledIndicator) {
case "on":
indicatorWhenOn()
@@ -159,13 +156,6 @@ def poll() {
])
}
/**
* PING is used by Device-Watch in attempt to reach the Device
**/
def ping() {
refresh()
}
def refresh() {
delayBetween([
zwave.switchBinaryV1.switchBinaryGet().format(),

View File

@@ -1,779 +0,0 @@
/**
* Filtrete 3M-50 WiFi Thermostat.
*
* For more information, please visit:
* <https://github.com/statusbits/smartthings/tree/master/RadioThermostat/>
*
* --------------------------------------------------------------------------
*
* Copyright (c) 2014 Statusbits.com
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --------------------------------------------------------------------------
*
* Version 1.0.3 (07/20/2015)
*/
import groovy.json.JsonSlurper
preferences {
input("confIpAddr", "string", title:"Thermostat IP Address",
required:true, displayDuringSetup: true)
input("confTcpPort", "number", title:"Thermostat TCP Port",
required:true, displayDuringSetup:true)
}
metadata {
definition (name:"Radio Thermostat", namespace:"statusbits", author:"geko@statusbits.com") {
capability "Thermostat"
capability "Temperature Measurement"
capability "Sensor"
capability "Refresh"
capability "Polling"
// Custom attributes
attribute "fanState", "string" // Fan operating state. Values: "on", "off"
attribute "hold", "string" // Target temperature Hold status. Values: "on", "off"
// Custom commands
command "heatLevelUp"
command "heatLevelDown"
command "coolLevelUp"
command "coolLevelDown"
command "holdOn"
command "holdOff"
}
tiles {
valueTile("temperature", "device.temperature") {
state "temperature", label:'${currentValue}°', unit:"F",
backgroundColors:[
[value: 31, color: "#153591"],
[value: 44, color: "#1e9cbb"],
[value: 59, color: "#90d2a7"],
[value: 74, color: "#44b621"],
[value: 84, color: "#f1d801"],
[value: 95, color: "#d04e00"],
[value: 96, color: "#bc2323"]
]
}
valueTile("heatingSetpoint", "device.heatingSetpoint", inactiveLabel:false) {
state "default", label:'${currentValue}°', unit:"F",
backgroundColors:[
[value: 31, color: "#153591"],
[value: 44, color: "#1e9cbb"],
[value: 59, color: "#90d2a7"],
[value: 74, color: "#44b621"],
[value: 84, color: "#f1d801"],
[value: 95, color: "#d04e00"],
[value: 96, color: "#bc2323"]
]
}
valueTile("coolingSetpoint", "device.coolingSetpoint", inactiveLabel:false) {
state "default", label:'${currentValue}°', unit:"F",
backgroundColors:[
[value: 31, color: "#153591"],
[value: 44, color: "#1e9cbb"],
[value: 59, color: "#90d2a7"],
[value: 74, color: "#44b621"],
[value: 84, color: "#f1d801"],
[value: 95, color: "#d04e00"],
[value: 96, color: "#bc2323"]
]
}
standardTile("heatLevelUp", "device.heatingSetpoint", inactiveLabel:false, decoration:"flat") {
state "default", label:'Heating', icon:"st.custom.buttons.add-icon", action:"heatLevelUp"
}
standardTile("heatLevelDown", "device.heatingSetpoint", inactiveLabel:false, decoration:"flat") {
state "default", label:'Heating', icon:"st.custom.buttons.subtract-icon", action:"heatLevelDown"
}
standardTile("coolLevelUp", "device.coolingSetpoint", inactiveLabel:false, decoration:"flat") {
state "default", label:'Cooling', icon:"st.custom.buttons.add-icon", action:"coolLevelUp"
}
standardTile("coolLevelDown", "device.coolingSetpoint", inactiveLabel:false, decoration:"flat") {
state "default", label:'Cooling', icon:"st.custom.buttons.subtract-icon", action:"coolLevelDown"
}
standardTile("operatingState", "device.thermostatOperatingState", inactiveLabel:false, decoration:"flat") {
state "default", label:'[State]'
state "idle", label:'', icon:"st.thermostat.heating-cooling-off"
state "heating", label:'', icon:"st.thermostat.heating"
state "cooling", label:'', icon:"st.thermostat.cooling"
}
standardTile("fanState", "device.fanState", inactiveLabel:false, decoration:"flat") {
state "default", label:'[Fan State]'
state "on", label:'', icon:"st.thermostat.fan-on"
state "off", label:'', icon:"st.thermostat.fan-off"
}
standardTile("mode", "device.thermostatMode", inactiveLabel:false) {
state "default", label:'[Mode]'
state "off", label:'', icon:"st.thermostat.heating-cooling-off", backgroundColor:"#FFFFFF", action:"thermostat.heat"
state "heat", label:'', icon:"st.thermostat.heat", backgroundColor:"#FFCC99", action:"thermostat.cool"
state "cool", label:'', icon:"st.thermostat.cool", backgroundColor:"#99CCFF", action:"thermostat.auto"
state "auto", label:'', icon:"st.thermostat.auto", backgroundColor:"#99FF99", action:"thermostat.off"
}
standardTile("fanMode", "device.thermostatFanMode", inactiveLabel:false) {
state "default", label:'[Fan Mode]'
state "auto", label:'', icon:"st.thermostat.fan-auto", backgroundColor:"#A4FCA6", action:"thermostat.fanOn"
state "on", label:'', icon:"st.thermostat.fan-on", backgroundColor:"#FAFCA4", action:"thermostat.fanAuto"
}
standardTile("hold", "device.hold", inactiveLabel:false) {
state "default", label:'[Hold]'
state "on", label:'Hold On', icon:"st.Weather.weather2", backgroundColor:"#FFDB94", action:"holdOff"
state "off", label:'Hold Off', icon:"st.Weather.weather2", backgroundColor:"#FFFFFF", action:"holdOn"
}
standardTile("refresh", "device.thermostatMode", inactiveLabel:false, decoration:"flat") {
state "default", icon:"st.secondary.refresh", action:"refresh.refresh"
}
main(["temperature"])
details(["temperature", "operatingState", "fanState",
"heatingSetpoint", "heatLevelDown", "heatLevelUp",
"coolingSetpoint", "coolLevelDown", "coolLevelUp",
"mode", "fanMode", "hold", "refresh"])
}
simulator {
status "Temperature 72.0": "simulator:true, temp:72.00"
status "Cooling Setpoint 76.0": "simulator:true, t_cool:76.00"
status "Heating Setpoint 68.0": "simulator:true, t_cool:68.00"
status "Thermostat Mode Off": "simulator:true, tmode:0"
status "Thermostat Mode Heat": "simulator:true, tmode:1"
status "Thermostat Mode Cool": "simulator:true, tmode:2"
status "Thermostat Mode Auto": "simulator:true, tmode:3"
status "Fan Mode Auto": "simulator:true, fmode:0"
status "Fan Mode Circulate": "simulator:true, fmode:1"
status "Fan Mode On": "simulator:true, fmode:2"
status "State Off": "simulator:true, tstate:0"
status "State Heat": "simulator:true, tstate:1"
status "State Cool": "simulator:true, tstate:2"
status "Fan State Off": "simulator:true, fstate:0"
status "Fan State On": "simulator:true, fstate:1"
status "Hold Disabled": "simulator:true, hold:0"
status "Hold Enabled": "simulator:true, hold:1"
}
}
def updated() {
log.info "Radio Thermostat. ${textVersion()}. ${textCopyright()}"
LOG("$device.displayName updated with settings: ${settings.inspect()}")
state.hostAddress = "${settings.confIpAddr}:${settings.confTcpPort}"
state.dni = createDNI(settings.confIpAddr, settings.confTcpPort)
STATE()
}
def parse(String message) {
LOG("parse(${message})")
def msg = stringToMap(message)
if (msg.headers) {
// parse HTTP response headers
def headers = new String(msg.headers.decodeBase64())
def parsedHeaders = parseHttpHeaders(headers)
LOG("parsedHeaders: ${parsedHeaders}")
if (parsedHeaders.status != 200) {
log.error "Server error: ${parsedHeaders.reason}"
return null
}
// parse HTTP response body
if (!msg.body) {
log.error "HTTP response has no body"
return null
}
def body = new String(msg.body.decodeBase64())
def slurper = new JsonSlurper()
def tstat = slurper.parseText(body)
return parseTstatData(tstat)
} else if (msg.containsKey("simulator")) {
// simulator input
return parseTstatData(msg)
}
return null
}
// thermostat.setThermostatMode
def setThermostatMode(mode) {
LOG("setThermostatMode(${mode})")
switch (mode) {
case "off": return off()
case "heat": return heat()
case "cool": return cool()
case "auto": return auto()
case "emergency heat": return emergencyHeat()
}
log.error "Invalid thermostat mode: \'${mode}\'"
}
// thermostat.off
def off() {
LOG("off()")
if (device.currentValue("thermostatMode") == "off") {
return null
}
sendEvent([name:"thermostatMode", value:"off"])
return writeTstatValue('tmode', 0)
}
// thermostat.heat
def heat() {
LOG("heat()")
if (device.currentValue("thermostatMode") == "heat") {
return null
}
sendEvent([name:"thermostatMode", value:"heat"])
return writeTstatValue('tmode', 1)
}
// thermostat.cool
def cool() {
LOG("cool()")
if (device.currentValue("thermostatMode") == "cool") {
return null
}
sendEvent([name:"thermostatMode", value:"cool"])
return writeTstatValue('tmode', 2)
}
// thermostat.auto
def auto() {
LOG("auto()")
if (device.currentValue("thermostatMode") == "auto") {
return null
}
sendEvent([name:"thermostatMode", value:"auto"])
return writeTstatValue('tmode', 3)
}
// thermostat.emergencyHeat
def emergencyHeat() {
LOG("emergencyHeat()")
log.warn "'emergency heat' mode is not supported"
return null
}
// thermostat.setThermostatFanMode
def setThermostatFanMode(fanMode) {
LOG("setThermostatFanMode(${fanMode})")
switch (fanMode) {
case "auto": return fanAuto()
case "circulate": return fanCirculate()
case "on": return fanOn()
}
log.error "Invalid fan mode: \'${fanMode}\'"
}
// thermostat.fanAuto
def fanAuto() {
LOG("fanAuto()")
if (device.currentValue("thermostatFanMode") == "auto") {
return null
}
sendEvent([name:"thermostatFanMode", value:"auto"])
return writeTstatValue('fmode', 0)
}
// thermostat.fanCirculate
def fanCirculate() {
LOG("fanCirculate()")
log.warn "Fan 'Circulate' mode is not supported"
return null
}
// thermostat.fanOn
def fanOn() {
LOG("fanOn()")
if (device.currentValue("thermostatFanMode") == "on") {
return null
}
sendEvent([name:"thermostatFanMode", value:"on"])
return writeTstatValue('fmode', 2)
}
// thermostat.setHeatingSetpoint
def setHeatingSetpoint(tempHeat) {
LOG("setHeatingSetpoint(${tempHeat})")
def ev = [
name: "heatingSetpoint",
value: tempHeat,
unit: getTemperatureScale(),
]
sendEvent(ev)
if (getTemperatureScale() == "C") {
tempHeat = temperatureCtoF(tempHeat)
}
return writeTstatValue('it_heat', tempHeat)
}
// thermostat.setCoolingSetpoint
def setCoolingSetpoint(tempCool) {
LOG("setCoolingSetpoint(${tempCool})")
def ev = [
name: "coolingSetpoint",
value: tempCool,
unit: getTemperatureScale(),
]
sendEvent(ev)
if (getTemperatureScale() == "C") {
tempCool = temperatureCtoF(tempCool)
}
return writeTstatValue('it_cool', tempCool)
}
def heatLevelDown() {
LOG("heatLevelDown()")
def currentT = device.currentValue("heatingSetpoint")?.toFloat()
if (!currentT) {
return
}
def limit = 50
def step = 1
if (getTemperatureScale() == "C") {
limit = 10
step = 0.5
}
if (currentT > limit) {
setHeatingSetpoint(currentT - step)
}
}
def heatLevelUp() {
LOG("heatLevelUp()")
def currentT = device.currentValue("heatingSetpoint")?.toFloat()
if (!currentT) {
return
}
def limit = 95
def step = 1
if (getTemperatureScale() == "C") {
limit = 35
step = 0.5
}
if (currentT < limit) {
setHeatingSetpoint(currentT + step)
}
}
def coolLevelDown() {
LOG("coolLevelDown()")
def currentT = device.currentValue("coolingSetpoint")?.toFloat()
if (!currentT) {
return
}
def limit = 50
def step = 1
if (getTemperatureScale() == "C") {
limit = 10
step = 0.5
}
if (currentT > limit) {
setCoolingSetpoint(currentT - step)
}
}
def coolLevelUp() {
LOG("coolLevelUp()")
def currentT = device.currentValue("coolingSetpoint")?.toFloat()
if (!currentT) {
return
}
def limit = 95
def step = 1
if (getTemperatureScale() == "C") {
limit = 35
step = 0.5
}
if (currentT < limit) {
setCoolingSetpoint(currentT + step)
}
}
def holdOn() {
LOG("holdOn()")
if (device.currentValue("hold") == "on") {
return null
}
sendEvent([name:"hold", value:"on"])
writeTstatValue("hold", 1)
}
def holdOff() {
LOG("holdOff()")
if (device.currentValue("hold") == "off") {
return null
}
sendEvent([name:"hold", value:"off"])
writeTstatValue("hold", 0)
}
// polling.poll
def poll() {
LOG("poll()")
return refresh()
}
// refresh.refresh
def refresh() {
LOG("refresh()")
//STATE()
return apiGet("/tstat")
}
// Creates Device Network ID in 'AAAAAAAA:PPPP' format
private String createDNI(ipaddr, port) {
LOG("createDNI(${ipaddr}, ${port})")
def hexIp = ipaddr.tokenize('.').collect {
String.format('%02X', it.toInteger())
}.join()
def hexPort = String.format('%04X', port.toInteger())
return "${hexIp}:${hexPort}"
}
private updateDNI() {
if (device.deviceNetworkId != state.dni) {
device.deviceNetworkId = state.dni
}
}
private apiGet(String path) {
LOG("apiGet(${path})")
def headers = [
HOST: state.hostAddress,
Accept: "*/*"
]
def httpRequest = [
method: 'GET',
path: path,
headers: headers
]
updateDNI()
return new physicalgraph.device.HubAction(httpRequest)
}
private apiPost(String path, data) {
LOG("apiPost(${path}, ${data})")
def headers = [
HOST: state.hostAddress,
Accept: "*/*"
]
def httpRequest = [
method: 'POST',
path: path,
headers: headers,
body: data
]
updateDNI()
return new physicalgraph.device.HubAction(httpRequest)
}
private def writeTstatValue(name, value) {
LOG("writeTstatValue(${name}, ${value})")
def json = "{\"${name}\": ${value}}"
def hubActions = [
apiPost("/tstat", json),
delayHubAction(2000),
apiGet("/tstat")
]
return hubActions
}
private def delayHubAction(ms) {
return new physicalgraph.device.HubAction("delay ${ms}")
}
private parseHttpHeaders(String headers) {
def lines = headers.readLines()
def status = lines.remove(0).split()
def result = [
protocol: status[0],
status: status[1].toInteger(),
reason: status[2]
]
return result
}
private def parseTstatData(Map tstat) {
LOG("parseTstatData(${tstat})")
def events = []
if (tstat.containsKey("error_msg")) {
log.error "Thermostat error: ${tstat.error_msg}"
return null
}
if (tstat.containsKey("success")) {
// this is POST response - ignore
return null
}
if (tstat.containsKey("temp")) {
//Float temp = tstat.temp.toFloat()
def ev = [
name: "temperature",
value: scaleTemperature(tstat.temp.toFloat()),
unit: getTemperatureScale(),
]
events << createEvent(ev)
}
if (tstat.containsKey("t_cool")) {
def ev = [
name: "coolingSetpoint",
value: scaleTemperature(tstat.t_cool.toFloat()),
unit: getTemperatureScale(),
]
events << createEvent(ev)
}
if (tstat.containsKey("t_heat")) {
def ev = [
name: "heatingSetpoint",
value: scaleTemperature(tstat.t_heat.toFloat()),
unit: getTemperatureScale(),
]
events << createEvent(ev)
}
if (tstat.containsKey("tstate")) {
def value = parseThermostatState(tstat.tstate)
if (device.currentState("thermostatOperatingState")?.value != value) {
def ev = [
name: "thermostatOperatingState",
value: value
]
events << createEvent(ev)
}
}
if (tstat.containsKey("fstate")) {
def value = parseFanState(tstat.fstate)
if (device.currentState("fanState")?.value != value) {
def ev = [
name: "fanState",
value: value
]
events << createEvent(ev)
}
}
if (tstat.containsKey("tmode")) {
def value = parseThermostatMode(tstat.tmode)
if (device.currentState("thermostatMode")?.value != value) {
def ev = [
name: "thermostatMode",
value: value
]
events << createEvent(ev)
}
}
if (tstat.containsKey("fmode")) {
def value = parseFanMode(tstat.fmode)
if (device.currentState("thermostatFanMode")?.value != value) {
def ev = [
name: "thermostatFanMode",
value: value
]
events << createEvent(ev)
}
}
if (tstat.containsKey("hold")) {
def value = parseThermostatHold(tstat.hold)
if (device.currentState("hold")?.value != value) {
def ev = [
name: "hold",
value: value
]
events << createEvent(ev)
}
}
LOG("events: ${events}")
return events
}
private def parseThermostatState(val) {
def values = [
"idle", // 0
"heating", // 1
"cooling" // 2
]
return values[val.toInteger()]
}
private def parseFanState(val) {
def values = [
"off", // 0
"on" // 1
]
return values[val.toInteger()]
}
private def parseThermostatMode(val) {
def values = [
"off", // 0
"heat", // 1
"cool", // 2
"auto" // 3
]
return values[val.toInteger()]
}
private def parseFanMode(val) {
def values = [
"auto", // 0
"circulate",// 1 (not supported by CT30)
"on" // 2
]
return values[val.toInteger()]
}
private def parseThermostatHold(val) {
def values = [
"off", // 0
"on" // 1
]
return values[val.toInteger()]
}
private def scaleTemperature(Float temp) {
if (getTemperatureScale() == "C") {
return temperatureFtoC(temp)
}
return temp.round(1)
}
private def temperatureCtoF(Float tempC) {
Float t = (tempC * 1.8) + 32
return t.round(1)
}
private def temperatureFtoC(Float tempF) {
Float t = (tempF - 32) / 1.8
return t.round(1)
}
private def textVersion() {
return "Version 1.0.3 (08/25/2015)"
}
private def textCopyright() {
return "Copyright (c) 2014 Statusbits.com"
}
private def LOG(message) {
//log.trace message
}
private def STATE() {
log.trace "state: ${state}"
log.trace "deviceNetworkId: ${device.deviceNetworkId}"
log.trace "temperature: ${device.currentValue("temperature")}"
log.trace "heatingSetpoint: ${device.currentValue("heatingSetpoint")}"
log.trace "coolingSetpoint: ${device.currentValue("coolingSetpoint")}"
log.trace "thermostatMode: ${device.currentValue("thermostatMode")}"
log.trace "thermostatFanMode: ${device.currentValue("thermostatFanMode")}"
log.trace "thermostatOperatingState: ${device.currentValue("thermostatOperatingState")}"
log.trace "fanState: ${device.currentValue("fanState")}"
log.trace "hold: ${device.currentValue("hold")}"
}

View File

@@ -37,10 +37,7 @@ preferences {
def mainPage() {
def bridges = bridgesDiscovered()
if (state.refreshUsernameNeeded) {
return bridgeLinking()
} else if (state.username && bridges) {
if (state.username && bridges) {
return bulbDiscovery()
} else {
return bridgeDiscovery()
@@ -105,22 +102,13 @@ def bridgeLinking() {
def nextPage = ""
def title = "Linking with your Hue"
def paragraphText
def paragraphText
if (selectedHue) {
if (state.refreshUsernameNeeded) {
paragraphText = "The current Hue username is invalid.\n\nPlease press the button on your Hue Bridge to re-link. "
} else {
paragraphText = "Press the button on your Hue Bridge to setup a link. "
}
} else {
paragraphText = "You haven't selected a Hue Bridge, please Press \"Done\" and select one before clicking next."
}
} else {
paragraphText = "You haven't selected a Hue Bridge, please Press \"Done\" and select one before clicking next."
}
if (state.username) { //if discovery worked
if (state.refreshUsernameNeeded) {
state.refreshUsernameNeeded = false
// Issue one poll with new username to cancel local polling with old username
poll()
}
nextPage = "bulbDiscovery"
title = "Success!"
paragraphText = "Linking to your hub was a success! Please click 'Next'!"
@@ -927,15 +915,8 @@ private handleCommandResponse(body) {
updates[childDeviceNetworkId]."$eventType" = v
}
}
} else if (payload?.error) {
log.warn "Error returned from Hue bridge, error = ${payload?.error}"
// Check for unauthorized user
if (payload?.error?.type?.value == 1) {
log.error "Hue username is not valid"
state.refreshUsernameNeeded = true
state.username = null
}
return []
} else if (payload.error) {
log.warn "Error returned from Hue bridge error = ${body?.error}"
}
}