mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-16 05:10:50 +00:00
Compare commits
37 Commits
DEVC-484
...
PROD_2016.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
20239ca982 | ||
|
|
b20c0e371f | ||
|
|
ee2e1ee04f | ||
|
|
e443cb641c | ||
|
|
b9993a9bf2 | ||
|
|
092971c786 | ||
|
|
a8ee927893 | ||
|
|
51979f0030 | ||
|
|
1dfd1818b4 | ||
|
|
1de73b643c | ||
|
|
e5c21ef720 | ||
|
|
fcb504f57e | ||
|
|
b9229c6ef8 | ||
|
|
91a9856a32 | ||
|
|
a84ffdde91 | ||
|
|
3034cc8bcb | ||
|
|
918e9d9397 | ||
|
|
0c040120cc | ||
|
|
6c84c052cb | ||
|
|
f017bff6ef | ||
|
|
65bb10d6d6 | ||
|
|
3f93de247b | ||
|
|
2b7af3ef8d | ||
|
|
cf9d123aa0 | ||
|
|
8e37b1fce7 | ||
|
|
439dd634bd | ||
|
|
1db5f75ec5 | ||
|
|
7978f45996 | ||
|
|
0ab657d5f2 | ||
|
|
3d88fc0413 | ||
|
|
ede1296b6b | ||
|
|
470cdc7d97 | ||
|
|
9bc3ff5103 | ||
|
|
bae79192c5 | ||
|
|
0f8beee455 | ||
|
|
6beb8bb50c | ||
|
|
4b44460b0b |
@@ -1,10 +1,10 @@
|
|||||||
# SmartThings Public Github Repo
|
# SmartThings Public GitHub Repo
|
||||||
|
|
||||||
An official list of SmartApps and Device Types from SmartThings.
|
An official list of SmartApps and Device Types from SmartThings.
|
||||||
|
|
||||||
Here are some links to help you get started coding right away:
|
Here are some links to help you get started coding right away:
|
||||||
|
|
||||||
* [Github-specific Documentation](http://docs.smartthings.com/en/latest/tools-and-ide/github-integration.html)
|
* [GitHub-specific Documentation](http://docs.smartthings.com/en/latest/tools-and-ide/github-integration.html)
|
||||||
* [Full Documentation](http://docs.smartthings.com)
|
* [Full Documentation](http://docs.smartthings.com)
|
||||||
* [IDE & Simulator](http://ide.smartthings.com)
|
* [IDE & Simulator](http://ide.smartthings.com)
|
||||||
* [Community Forums](http://community.smartthings.com)
|
* [Community Forums](http://community.smartthings.com)
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ metadata {
|
|||||||
definition (name: "Aeon Key Fob", namespace: "smartthings", author: "SmartThings") {
|
definition (name: "Aeon Key Fob", namespace: "smartthings", author: "SmartThings") {
|
||||||
capability "Actuator"
|
capability "Actuator"
|
||||||
capability "Button"
|
capability "Button"
|
||||||
|
capability "Holdable Button"
|
||||||
capability "Configuration"
|
capability "Configuration"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
capability "Battery"
|
capability "Battery"
|
||||||
@@ -118,3 +119,16 @@ def configure() {
|
|||||||
log.debug("Sending configuration: $cmd")
|
log.debug("Sending configuration: $cmd")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def installed() {
|
||||||
|
initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
def updated() {
|
||||||
|
initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
def initialize() {
|
||||||
|
sendEvent(name: "numberOfButtons", value: 4)
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ metadata {
|
|||||||
definition (name: "Aeon Minimote", namespace: "smartthings", author: "SmartThings") {
|
definition (name: "Aeon Minimote", namespace: "smartthings", author: "SmartThings") {
|
||||||
capability "Actuator"
|
capability "Actuator"
|
||||||
capability "Button"
|
capability "Button"
|
||||||
|
capability "Holdable Button"
|
||||||
capability "Configuration"
|
capability "Configuration"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
|
|
||||||
@@ -107,3 +108,16 @@ def configure() {
|
|||||||
log.debug("Sending configuration: $cmds")
|
log.debug("Sending configuration: $cmds")
|
||||||
return cmds
|
return cmds
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def installed() {
|
||||||
|
initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
def updated() {
|
||||||
|
initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
def initialize() {
|
||||||
|
sendEvent(name: "numberOfButtons", value: 4)
|
||||||
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ metadata {
|
|||||||
capability "Switch"
|
capability "Switch"
|
||||||
capability "Refresh"
|
capability "Refresh"
|
||||||
capability "Music Player"
|
capability "Music Player"
|
||||||
capability "Polling"
|
capability "Health Check"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define all commands, ie, if you have a custom action not
|
* Define all commands, ie, if you have a custom action not
|
||||||
@@ -236,7 +236,33 @@ def parse(String event) {
|
|||||||
* @return action(s) to take or null
|
* @return action(s) to take or null
|
||||||
*/
|
*/
|
||||||
def installed() {
|
def installed() {
|
||||||
onAction("refresh")
|
// Notify health check about this device with timeout interval 12 minutes
|
||||||
|
sendEvent(name: "checkInterval", value: 12 * 60, data: [protocol: "lan", hubHardwareId: device.hub.hardwareID], displayed: false)
|
||||||
|
startPoll()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by health check if no events been generated in the last 12 minutes
|
||||||
|
* If device doesn't respond it will be marked offline (not available)
|
||||||
|
*/
|
||||||
|
def ping() {
|
||||||
|
TRACE("ping")
|
||||||
|
boseSendGetNowPlaying()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedule a 2 minute poll of the device to refresh the
|
||||||
|
* tiles so the user gets the correct information.
|
||||||
|
*/
|
||||||
|
def startPoll() {
|
||||||
|
TRACE("startPoll")
|
||||||
|
unschedule()
|
||||||
|
// Schedule 2 minute polling of speaker status (song average length is 3-4 minutes)
|
||||||
|
def sec = Math.round(Math.floor(Math.random() * 60))
|
||||||
|
//def cron = "$sec 0/5 * * * ?" // every 5 min
|
||||||
|
def cron = "$sec 0/2 * * * ?" // every 2 min
|
||||||
|
log.debug "schedule('$cron', boseSendGetNowPlaying)"
|
||||||
|
schedule(cron, boseSendGetNowPlaying)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -316,14 +342,6 @@ def onAction(String user, data=null) {
|
|||||||
return actions
|
return actions
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Called every so often (every 5 minutes actually) to refresh the
|
|
||||||
* tiles so the user gets the correct information.
|
|
||||||
*/
|
|
||||||
def poll() {
|
|
||||||
return boseRefreshNowPlaying()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Joins this speaker into the everywhere zone
|
* Joins this speaker into the everywhere zone
|
||||||
*/
|
*/
|
||||||
@@ -837,6 +855,10 @@ def boseRefreshNowPlaying(delay=0) {
|
|||||||
return boseGET("/now_playing")
|
return boseGET("/now_playing")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def boseSendGetNowPlaying() {
|
||||||
|
sendHubCommand(boseGET("/now_playing"))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Requests the list of presets
|
* Requests the list of presets
|
||||||
*
|
*
|
||||||
@@ -1015,3 +1037,7 @@ def boseGetDeviceID() {
|
|||||||
def getDeviceIP() {
|
def getDeviceIP() {
|
||||||
return parent.resolveDNI2Address(device.deviceNetworkId)
|
return parent.resolveDNI2Address(device.deviceNetworkId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def TRACE(text) {
|
||||||
|
log.trace "${text}"
|
||||||
|
}
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright 2015 SmartThings
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at:
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
|
||||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
|
|
||||||
* for the specific language governing permissions and limitations under the License.
|
|
||||||
*
|
|
||||||
* CentraLite Dimmer
|
|
||||||
*
|
|
||||||
* Author: SmartThings
|
|
||||||
* Date: 2013-12-04
|
|
||||||
*/
|
|
||||||
//DEPRECATED - Using the generic DTH for this device. Users need to be moved before deleting this DTH
|
|
||||||
metadata {
|
|
||||||
definition (name: "CentraLite Dimmer", namespace: "smartthings", author: "SmartThings") {
|
|
||||||
capability "Switch Level"
|
|
||||||
capability "Actuator"
|
|
||||||
capability "Switch"
|
|
||||||
capability "Power Meter"
|
|
||||||
capability "Configuration"
|
|
||||||
capability "Refresh"
|
|
||||||
capability "Sensor"
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
tiles(scale: 2) {
|
|
||||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
|
||||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
|
|
||||||
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
|
||||||
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
|
|
||||||
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
|
||||||
}
|
|
||||||
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
|
||||||
attributeState "level", action:"switch level.setLevel"
|
|
||||||
}
|
|
||||||
tileAttribute ("power", key: "SECONDARY_CONTROL") {
|
|
||||||
attributeState "power", label:'${currentValue} W'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
|
||||||
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
|
||||||
}
|
|
||||||
main "switch"
|
|
||||||
details(["switch", "refresh"])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse incoming device messages to generate events
|
|
||||||
def parse(String description) {
|
|
||||||
log.debug "description is $description"
|
|
||||||
|
|
||||||
def event = zigbee.getEvent(description)
|
|
||||||
if (event) {
|
|
||||||
log.info event
|
|
||||||
if (event.name == "power") {
|
|
||||||
if (device.getDataValue("manufacturer") != "OSRAM") { //OSRAM devices do not reliably update power
|
|
||||||
event.value = (event.value as Integer) / 10 //TODO: The divisor value needs to be set as part of configuration
|
|
||||||
sendEvent(event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sendEvent(event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log.warn "DID NOT PARSE MESSAGE for description : $description"
|
|
||||||
log.debug zigbee.parseDescriptionAsMap(description)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def off() {
|
|
||||||
zigbee.off()
|
|
||||||
}
|
|
||||||
|
|
||||||
def on() {
|
|
||||||
zigbee.on()
|
|
||||||
}
|
|
||||||
|
|
||||||
def setLevel(value) {
|
|
||||||
zigbee.setLevel(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
def refresh() {
|
|
||||||
zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.simpleMeteringPowerRefresh() + zigbee.electricMeasurementPowerRefresh() + zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.simpleMeteringPowerConfig() + zigbee.electricMeasurementPowerConfig()
|
|
||||||
}
|
|
||||||
|
|
||||||
def configure() {
|
|
||||||
log.debug "Configuring Reporting and Bindings."
|
|
||||||
refresh()
|
|
||||||
}
|
|
||||||
@@ -16,7 +16,7 @@ metadata {
|
|||||||
capability "Switch"
|
capability "Switch"
|
||||||
capability "Switch Level"
|
capability "Switch Level"
|
||||||
capability "Button"
|
capability "Button"
|
||||||
capability "Actuator"
|
capability "Actuator"
|
||||||
|
|
||||||
//fingerprint deviceId: "0x1200", inClusters: "0x77 0x86 0x75 0x73 0x85 0x72 0xEF", outClusters: "0x26"
|
//fingerprint deviceId: "0x1200", inClusters: "0x77 0x86 0x75 0x73 0x85 0x72 0xEF", outClusters: "0x26"
|
||||||
}
|
}
|
||||||
@@ -182,3 +182,16 @@ def updateState(String name, String value) {
|
|||||||
state[name] = value
|
state[name] = value
|
||||||
device.updateDataValue(name, value)
|
device.updateDataValue(name, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def installed() {
|
||||||
|
initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
def updated() {
|
||||||
|
initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
def initialize() {
|
||||||
|
sendEvent(name: "numberOfButtons", value: 3)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Connected Cree LED Bulb
|
# Connected Cree LED Bulb
|
||||||
|
|
||||||
|
Cloud Execution
|
||||||
|
|
||||||
Works with:
|
Works with:
|
||||||
|
|
||||||
@@ -23,8 +23,10 @@ Works with:
|
|||||||
|
|
||||||
## Device Health
|
## Device Health
|
||||||
|
|
||||||
A Category C6 Connected Cree LED Bulb with maxReportTime of 5 mins.
|
Connected Cree LED Bulb with cloud polling it every __5min__
|
||||||
Check-in interval = 12 mins
|
SmartThings platform will ping the device after `checkInterval` seconds of inactivity in last attempt to reach the device before marking it `OFFLINE`
|
||||||
|
|
||||||
|
* __12min__ checkInterval
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ def healthPoll() {
|
|||||||
def configure() {
|
def configure() {
|
||||||
unschedule()
|
unschedule()
|
||||||
runEvery5Minutes("healthPoll")
|
runEvery5Minutes("healthPoll")
|
||||||
// Device-Watch allows 2 check-in misses from device
|
// Device-Watch allows 2 check-in misses from device + ping
|
||||||
sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
||||||
zigbee.onOffRefresh() + zigbee.levelRefresh()
|
zigbee.onOffRefresh() + zigbee.levelRefresh()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Z-wave Dimmer Switch
|
# Z-wave Dimmer Switch
|
||||||
|
|
||||||
|
Local Execution on V2 Hubs
|
||||||
|
|
||||||
Works with:
|
Works with:
|
||||||
|
|
||||||
@@ -34,6 +34,8 @@ Not to mention after going OFFLINE when the device is plugged back in, it might
|
|||||||
the device to appear as ONLINE again. This is because if this listening device does not respond to two poll requests in a row,
|
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.
|
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
|
## Troubleshooting
|
||||||
|
|
||||||
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
|
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
|
||||||
|
|||||||
@@ -236,17 +236,17 @@ def refresh() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void indicatorWhenOn() {
|
void indicatorWhenOn() {
|
||||||
sendEvent(name: "indicatorStatus", value: "when on", display: false)
|
sendEvent(name: "indicatorStatus", value: "when on", displayed: false)
|
||||||
sendHubCommand(new physicalgraph.device.HubAction(zwave.configurationV1.configurationSet(configurationValue: [1], parameterNumber: 3, size: 1).format()))
|
sendHubCommand(new physicalgraph.device.HubAction(zwave.configurationV1.configurationSet(configurationValue: [1], parameterNumber: 3, size: 1).format()))
|
||||||
}
|
}
|
||||||
|
|
||||||
void indicatorWhenOff() {
|
void indicatorWhenOff() {
|
||||||
sendEvent(name: "indicatorStatus", value: "when off", display: false)
|
sendEvent(name: "indicatorStatus", value: "when off", displayed: false)
|
||||||
sendHubCommand(new physicalgraph.device.HubAction(zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 3, size: 1).format()))
|
sendHubCommand(new physicalgraph.device.HubAction(zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 3, size: 1).format()))
|
||||||
}
|
}
|
||||||
|
|
||||||
void indicatorNever() {
|
void indicatorNever() {
|
||||||
sendEvent(name: "indicatorStatus", value: "never", display: false)
|
sendEvent(name: "indicatorStatus", value: "never", displayed: false)
|
||||||
sendHubCommand(new physicalgraph.device.HubAction(zwave.configurationV1.configurationSet(configurationValue: [2], parameterNumber: 3, size: 1).format()))
|
sendHubCommand(new physicalgraph.device.HubAction(zwave.configurationV1.configurationSet(configurationValue: [2], parameterNumber: 3, size: 1).format()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ metadata {
|
|||||||
void installed() {
|
void installed() {
|
||||||
// The device refreshes every 5 minutes by default so if we miss 2 refreshes we can consider it offline
|
// The device refreshes every 5 minutes by default so if we miss 2 refreshes we can consider it offline
|
||||||
// Using 12 minutes because in testing, device health team found that there could be "jitter"
|
// Using 12 minutes because in testing, device health team found that there could be "jitter"
|
||||||
sendEvent(name: "checkInterval", value: 60 * 12, data: [protocol: "cloud", hubHardwareId: device.hub.hardwareID], displayed: false)
|
sendEvent(name: "checkInterval", value: 60 * 12, data: [protocol: "cloud"], displayed: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Device Watch will ping the device to proactively determine if the device has gone offline
|
// Device Watch will ping the device to proactively determine if the device has gone offline
|
||||||
|
|||||||
@@ -546,7 +546,7 @@ def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport
|
|||||||
def value = "when off"
|
def value = "when off"
|
||||||
if (cmd.configurationValue[0] == 1) {value = "when on"}
|
if (cmd.configurationValue[0] == 1) {value = "when on"}
|
||||||
if (cmd.configurationValue[0] == 2) {value = "never"}
|
if (cmd.configurationValue[0] == 2) {value = "never"}
|
||||||
[name: "indicatorStatus", value: value, display: false]
|
[name: "indicatorStatus", value: value, displayed: false]
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
def createEvent(physicalgraph.zwave.Command cmd, Map map) {
|
def createEvent(physicalgraph.zwave.Command cmd, Map map) {
|
||||||
@@ -829,7 +829,7 @@ def toggleTiles(color) {
|
|||||||
state.colorTiles.each({
|
state.colorTiles.each({
|
||||||
if ( it == color ) {
|
if ( it == color ) {
|
||||||
log.debug "Turning ${it} on"
|
log.debug "Turning ${it} on"
|
||||||
cmds << sendEvent(name: it, value: "on${it}", display: True, descriptionText: "${device.displayName} ${color} is 'ON'", isStateChange: true)
|
cmds << sendEvent(name: it, value: "on${it}", displayed: True, descriptionText: "${device.displayName} ${color} is 'ON'", isStateChange: true)
|
||||||
} else {
|
} else {
|
||||||
//log.debug "Turning ${it} off"
|
//log.debug "Turning ${it} off"
|
||||||
cmds << sendEvent(name: it, value: "off${it}", displayed: false)
|
cmds << sendEvent(name: it, value: "off${it}", displayed: false)
|
||||||
|
|||||||
@@ -1,96 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright 2015 SmartThings
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at:
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
|
||||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
|
|
||||||
* for the specific language governing permissions and limitations under the License.
|
|
||||||
*
|
|
||||||
* GE/Jasco ZigBee Dimmer
|
|
||||||
*
|
|
||||||
* Author: SmartThings
|
|
||||||
* Date: 2015-07-01
|
|
||||||
*/
|
|
||||||
|
|
||||||
metadata {
|
|
||||||
definition (name: "GE ZigBee Dimmer", namespace: "smartthings", author: "SmartThings") {
|
|
||||||
capability "Switch"
|
|
||||||
capability "Switch Level"
|
|
||||||
capability "Power Meter"
|
|
||||||
capability "Configuration"
|
|
||||||
capability "Refresh"
|
|
||||||
capability "Actuator"
|
|
||||||
capability "Sensor"
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
tiles(scale: 2) {
|
|
||||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
|
||||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
|
|
||||||
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
|
||||||
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
|
|
||||||
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
|
||||||
}
|
|
||||||
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
|
||||||
attributeState "level", action:"switch level.setLevel"
|
|
||||||
}
|
|
||||||
tileAttribute ("power", key: "SECONDARY_CONTROL") {
|
|
||||||
attributeState "power", label:'${currentValue} W'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
|
||||||
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
|
||||||
}
|
|
||||||
main "switch"
|
|
||||||
details(["switch", "refresh"])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse incoming device messages to generate events
|
|
||||||
def parse(String description) {
|
|
||||||
log.debug "description is $description"
|
|
||||||
|
|
||||||
def event = zigbee.getEvent(description)
|
|
||||||
if (event) {
|
|
||||||
log.info event
|
|
||||||
if (event.name == "power") {
|
|
||||||
if (device.getDataValue("manufacturer") != "OSRAM") { //OSRAM devices do not reliably update power
|
|
||||||
event.value = (event.value as Integer) / 10 //TODO: The divisor value needs to be set as part of configuration
|
|
||||||
sendEvent(event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sendEvent(event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log.warn "DID NOT PARSE MESSAGE for description : $description"
|
|
||||||
log.debug zigbee.parseDescriptionAsMap(description)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def off() {
|
|
||||||
zigbee.off()
|
|
||||||
}
|
|
||||||
|
|
||||||
def on() {
|
|
||||||
zigbee.on()
|
|
||||||
}
|
|
||||||
|
|
||||||
def setLevel(value) {
|
|
||||||
zigbee.setLevel(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
def refresh() {
|
|
||||||
zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.simpleMeteringPowerRefresh() + zigbee.electricMeasurementPowerRefresh() + zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.simpleMeteringPowerConfig() + zigbee.electricMeasurementPowerConfig()
|
|
||||||
}
|
|
||||||
|
|
||||||
def configure() {
|
|
||||||
log.debug "Configuring Reporting and Bindings."
|
|
||||||
refresh()
|
|
||||||
}
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright 2015 SmartThings
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at:
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
|
||||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
|
|
||||||
* for the specific language governing permissions and limitations under the License.
|
|
||||||
*
|
|
||||||
* GE/Jasco ZigBee Switch
|
|
||||||
*
|
|
||||||
* Author: SmartThings
|
|
||||||
* Date: 2015-07-01
|
|
||||||
*/
|
|
||||||
|
|
||||||
metadata {
|
|
||||||
// Automatically generated. Make future change here.
|
|
||||||
definition (name: "GE ZigBee Switch", namespace: "smartthings", author: "SmartThings") {
|
|
||||||
capability "Switch"
|
|
||||||
capability "Power Meter"
|
|
||||||
capability "Configuration"
|
|
||||||
capability "Refresh"
|
|
||||||
capability "Actuator"
|
|
||||||
capability "Sensor"
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
tiles(scale: 2) {
|
|
||||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
|
||||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
|
|
||||||
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
|
||||||
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
|
|
||||||
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
|
||||||
}
|
|
||||||
tileAttribute ("power", key: "SECONDARY_CONTROL") {
|
|
||||||
attributeState "power", label:'${currentValue} W'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
|
||||||
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
|
||||||
}
|
|
||||||
main "switch"
|
|
||||||
details(["switch", "refresh"])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse incoming device messages to generate events
|
|
||||||
def parse(String description) {
|
|
||||||
log.debug "description is $description"
|
|
||||||
def event = zigbee.getEvent(description)
|
|
||||||
if (event) {
|
|
||||||
if (event.name == "power") {
|
|
||||||
def powerValue
|
|
||||||
powerValue = (event.value as Integer)/10 //TODO: The divisor value needs to be set as part of configuration
|
|
||||||
sendEvent(name: "power", value: powerValue)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sendEvent(event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log.warn "DID NOT PARSE MESSAGE for description : $description"
|
|
||||||
log.debug zigbee.parseDescriptionAsMap(description)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def off() {
|
|
||||||
zigbee.off()
|
|
||||||
}
|
|
||||||
|
|
||||||
def on() {
|
|
||||||
zigbee.on()
|
|
||||||
}
|
|
||||||
|
|
||||||
def refresh() {
|
|
||||||
zigbee.onOffRefresh() + zigbee.simpleMeteringPowerRefresh() + zigbee.electricMeasurementPowerRefresh() + zigbee.onOffConfig() + zigbee.simpleMeteringPowerConfig() + zigbee.electricMeasurementPowerConfig()
|
|
||||||
}
|
|
||||||
|
|
||||||
def configure() {
|
|
||||||
log.debug "Configuring Reporting and Bindings."
|
|
||||||
refresh()
|
|
||||||
}
|
|
||||||
@@ -43,8 +43,8 @@ def parse(String description) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def push() {
|
def push() {
|
||||||
sendEvent(name: "switch", value: "on", isStateChange: true, display: false)
|
sendEvent(name: "switch", value: "on", isStateChange: true, displayed: false)
|
||||||
sendEvent(name: "switch", value: "off", isStateChange: true, display: false)
|
sendEvent(name: "switch", value: "off", isStateChange: true, displayed: false)
|
||||||
sendEvent(name: "momentary", value: "pushed", isStateChange: true)
|
sendEvent(name: "momentary", value: "pushed", isStateChange: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Nyce Door/Window Sensor (Open/Close Sensor)
|
# Nyce Door/Window Sensor (Open/Close Sensor)
|
||||||
|
|
||||||
|
Cloud Execution
|
||||||
|
|
||||||
Works with:
|
Works with:
|
||||||
|
|
||||||
@@ -23,7 +23,11 @@ Works with:
|
|||||||
|
|
||||||
## Device Health
|
## Device Health
|
||||||
|
|
||||||
A Category C2 Nyce Door/Window sensor that has 12min check-in interval
|
Nyce Door/Window sensor with reporting interval of 5 min.
|
||||||
|
SmartThings platform will ping the device after `checkInterval` seconds of inactivity in last attempt to reach the device before marking it `OFFLINE`
|
||||||
|
|
||||||
|
* __12min__ checkInterval
|
||||||
|
|
||||||
|
|
||||||
## Battery Specification
|
## Battery Specification
|
||||||
|
|
||||||
|
|||||||
@@ -1,145 +0,0 @@
|
|||||||
/*
|
|
||||||
Osram Lightify Gardenspot Mini RGB
|
|
||||||
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
|
|
||||||
metadata {
|
|
||||||
definition (name: "OSRAM LIGHTIFY Gardenspot mini RGB", namespace: "smartthings", author: "SmartThings") {
|
|
||||||
|
|
||||||
capability "Color Temperature"
|
|
||||||
capability "Actuator"
|
|
||||||
capability "Switch"
|
|
||||||
capability "Switch Level"
|
|
||||||
capability "Configuration"
|
|
||||||
capability "Polling"
|
|
||||||
capability "Refresh"
|
|
||||||
capability "Sensor"
|
|
||||||
capability "Color Control"
|
|
||||||
|
|
||||||
attribute "colorName", "string"
|
|
||||||
|
|
||||||
command "setAdjustedColor"
|
|
||||||
}
|
|
||||||
|
|
||||||
// UI tile definitions
|
|
||||||
tiles(scale: 2) {
|
|
||||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
|
||||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
|
|
||||||
attributeState "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
|
||||||
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
|
|
||||||
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
|
||||||
}
|
|
||||||
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
|
||||||
attributeState "level", action:"switch level.setLevel"
|
|
||||||
}
|
|
||||||
tileAttribute ("device.color", key: "COLOR_CONTROL") {
|
|
||||||
attributeState "color", action:"color control.setColor"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
|
||||||
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
|
||||||
}
|
|
||||||
|
|
||||||
main(["switch"])
|
|
||||||
details(["switch", "refresh"])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Globals
|
|
||||||
private getATTRIBUTE_HUE() { 0x0000 }
|
|
||||||
private getATTRIBUTE_SATURATION() { 0x0001 }
|
|
||||||
private getHUE_COMMAND() { 0x00 }
|
|
||||||
private getSATURATION_COMMAND() { 0x03 }
|
|
||||||
private getCOLOR_CONTROL_CLUSTER() { 0x0300 }
|
|
||||||
|
|
||||||
// Parse incoming device messages to generate events
|
|
||||||
def parse(String description) {
|
|
||||||
log.debug "description is $description"
|
|
||||||
|
|
||||||
def event = zigbee.getEvent(description)
|
|
||||||
if (event) {
|
|
||||||
log.debug event
|
|
||||||
if (event.name=="level" && event.value==0) {}
|
|
||||||
else {
|
|
||||||
sendEvent(event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
def zigbeeMap = zigbee.parseDescriptionAsMap(description)
|
|
||||||
def cluster = zigbee.parse(description)
|
|
||||||
|
|
||||||
if (zigbeeMap?.clusterInt == COLOR_CONTROL_CLUSTER) {
|
|
||||||
if(zigbeeMap.attrInt == ATTRIBUTE_HUE){ //Hue Attribute
|
|
||||||
def hueValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 255 * 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)
|
|
||||||
sendEvent(name: "saturation", value: saturationValue, descriptionText: "Color has changed", displayed: false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (cluster && cluster.clusterId == 0x0006 && cluster.command == 0x07) {
|
|
||||||
if (cluster.data[0] == 0x00){
|
|
||||||
log.debug "ON/OFF REPORTING CONFIG RESPONSE: $cluster"
|
|
||||||
sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log.warn "ON/OFF REPORTING CONFIG FAILED- error code:${cluster.data[0]}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log.info "DID NOT PARSE MESSAGE for description : $description"
|
|
||||||
log.debug zigbeeMap
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def on() {
|
|
||||||
zigbee.on()
|
|
||||||
}
|
|
||||||
|
|
||||||
def off() {
|
|
||||||
zigbee.off()
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* PING is used by Device-Watch in attempt to reach the Device
|
|
||||||
* */
|
|
||||||
def ping() {
|
|
||||||
return zigbee.onOffRefresh()
|
|
||||||
}
|
|
||||||
|
|
||||||
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, 0x20, 1, 3600, 0x01) + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION, 0x20, 1, 3600, 0x01)
|
|
||||||
}
|
|
||||||
|
|
||||||
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])
|
|
||||||
|
|
||||||
// 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, 0x20, 1, 3600, 0x01) + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION, 0x20, 1, 3600, 0x01) + zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
|
|
||||||
}
|
|
||||||
|
|
||||||
def setLevel(value) {
|
|
||||||
zigbee.setLevel(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
def setColor(value){
|
|
||||||
log.trace "setColor($value)"
|
|
||||||
zigbee.on() + setHue(value.hue) + "delay 500" + setSaturation(value.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)
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
@@ -1,183 +0,0 @@
|
|||||||
/*
|
|
||||||
Osram Flex RGBW Light Strip
|
|
||||||
|
|
||||||
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: "OSRAM LIGHTIFY LED Flexible Strip RGBW", namespace: "smartthings", author: "SmartThings") {
|
|
||||||
|
|
||||||
capability "Color Temperature"
|
|
||||||
capability "Actuator"
|
|
||||||
capability "Switch"
|
|
||||||
capability "Switch Level"
|
|
||||||
capability "Configuration"
|
|
||||||
capability "Polling"
|
|
||||||
capability "Refresh"
|
|
||||||
capability "Sensor"
|
|
||||||
capability "Color Control"
|
|
||||||
|
|
||||||
attribute "colorName", "string"
|
|
||||||
|
|
||||||
command "setAdjustedColor"
|
|
||||||
|
|
||||||
|
|
||||||
//fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY Flex RGBW"
|
|
||||||
//fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Flex RGBW"
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// UI tile definitions
|
|
||||||
tiles(scale: 2) {
|
|
||||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
|
||||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
|
|
||||||
attributeState "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
|
||||||
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
|
|
||||||
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
|
||||||
}
|
|
||||||
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
|
||||||
attributeState "level", action:"switch level.setLevel"
|
|
||||||
}
|
|
||||||
tileAttribute ("device.color", key: "COLOR_CONTROL") {
|
|
||||||
attributeState "color", action:"color control.setColor"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
controlTile("colorTempSliderControl", "device.colorTemperature", "slider", width: 4, height: 2, inactiveLabel: false, range:"(2700..6500)") {
|
|
||||||
state "colorTemperature", action:"color temperature.setColorTemperature"
|
|
||||||
}
|
|
||||||
valueTile("colorName", "device.colorName", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
|
||||||
state "colorName", label: '${currentValue}'
|
|
||||||
}
|
|
||||||
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
|
||||||
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
|
||||||
}
|
|
||||||
|
|
||||||
main(["switch"])
|
|
||||||
details(["switch", "colorTempSliderControl", "colorName", "refresh"])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Globals
|
|
||||||
private getATTRIBUTE_HUE() { 0x0000 }
|
|
||||||
private getATTRIBUTE_SATURATION() { 0x0001 }
|
|
||||||
private getHUE_COMMAND() { 0x00 }
|
|
||||||
private getSATURATION_COMMAND() { 0x03 }
|
|
||||||
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"
|
|
||||||
|
|
||||||
def event = zigbee.getEvent(description)
|
|
||||||
if (event) {
|
|
||||||
log.debug event
|
|
||||||
if (event.name=="level" && event.value==0) {}
|
|
||||||
else {
|
|
||||||
if (event.name=="colorTemperature") {
|
|
||||||
setGenericName(event.value)
|
|
||||||
}
|
|
||||||
sendEvent(event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
def zigbeeMap = zigbee.parseDescriptionAsMap(description)
|
|
||||||
def cluster = zigbee.parse(description)
|
|
||||||
|
|
||||||
if (zigbeeMap?.clusterInt == COLOR_CONTROL_CLUSTER) {
|
|
||||||
if(zigbeeMap.attrInt == ATTRIBUTE_HUE){ //Hue Attribute
|
|
||||||
def hueValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 255 * 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)
|
|
||||||
sendEvent(name: "saturation", value: saturationValue, descriptionText: "Color has changed", displayed: false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (cluster && cluster.clusterId == 0x0006 && cluster.command == 0x07) {
|
|
||||||
if (cluster.data[0] == 0x00){
|
|
||||||
log.debug "ON/OFF REPORTING CONFIG RESPONSE: " + cluster
|
|
||||||
sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log.warn "ON/OFF REPORTING CONFIG FAILED- error code:${cluster.data[0]}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log.info "DID NOT PARSE MESSAGE for description : $description"
|
|
||||||
log.debug zigbeeMap
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def on() {
|
|
||||||
zigbee.on()
|
|
||||||
}
|
|
||||||
|
|
||||||
def off() {
|
|
||||||
zigbee.off()
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* PING is used by Device-Watch in attempt to reach the Device
|
|
||||||
* */
|
|
||||||
def ping() {
|
|
||||||
return zigbee.onOffRefresh()
|
|
||||||
}
|
|
||||||
|
|
||||||
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, 0x20, 1, 3600, 0x01) + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION, 0x20, 1, 3600, 0x01)
|
|
||||||
}
|
|
||||||
|
|
||||||
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])
|
|
||||||
|
|
||||||
// OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity
|
|
||||||
refresh()
|
|
||||||
}
|
|
||||||
|
|
||||||
def setColorTemperature(value) {
|
|
||||||
setGenericName(value)
|
|
||||||
zigbee.setColorTemperature(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
//Naming based on the wiki article here: http://en.wikipedia.org/wiki/Color_temperature
|
|
||||||
def setGenericName(value){
|
|
||||||
if (value != null) {
|
|
||||||
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 >= 5000) {
|
|
||||||
genericName = "Daylight"
|
|
||||||
}
|
|
||||||
sendEvent(name: "colorName", value: genericName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def setLevel(value) {
|
|
||||||
zigbee.setLevel(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
def setColor(value){
|
|
||||||
log.trace "setColor($value)"
|
|
||||||
zigbee.on() + setHue(value.hue) + "delay 300" + setSaturation(value.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)
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
/*
|
|
||||||
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: "OSRAM LIGHTIFY LED Tunable White 60W", namespace: "smartthings", author: "SmartThings") {
|
|
||||||
|
|
||||||
capability "Color Temperature"
|
|
||||||
capability "Actuator"
|
|
||||||
capability "Switch"
|
|
||||||
capability "Switch Level"
|
|
||||||
capability "Configuration"
|
|
||||||
capability "Refresh"
|
|
||||||
capability "Sensor"
|
|
||||||
|
|
||||||
attribute "colorName", "string"
|
|
||||||
}
|
|
||||||
|
|
||||||
// UI tile definitions
|
|
||||||
tiles(scale: 2) {
|
|
||||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
|
||||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
|
|
||||||
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
|
||||||
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
|
|
||||||
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
|
||||||
}
|
|
||||||
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
|
||||||
attributeState "level", action:"switch level.setLevel"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
|
||||||
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
|
||||||
}
|
|
||||||
|
|
||||||
controlTile("colorTempSliderControl", "device.colorTemperature", "slider", width: 4, height: 2, inactiveLabel: false, range:"(2700..6500)") {
|
|
||||||
state "colorTemperature", action:"color temperature.setColorTemperature"
|
|
||||||
}
|
|
||||||
valueTile("colorName", "device.colorName", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
|
||||||
state "colorName", label: '${currentValue}'
|
|
||||||
}
|
|
||||||
|
|
||||||
main(["switch"])
|
|
||||||
details(["switch", "colorTempSliderControl", "colorName", "refresh"])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse incoming device messages to generate events
|
|
||||||
def parse(String description) {
|
|
||||||
log.debug "description is $description"
|
|
||||||
def event = zigbee.getEvent(description)
|
|
||||||
if (event) {
|
|
||||||
if (event.name=="level" && event.value==0) {}
|
|
||||||
else {
|
|
||||||
if (event.name=="colorTemperature") {
|
|
||||||
setGenericName(event.value)
|
|
||||||
}
|
|
||||||
sendEvent(event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
def cluster = zigbee.parse(description)
|
|
||||||
|
|
||||||
if (cluster && cluster.clusterId == 0x0006 && cluster.command == 0x07) {
|
|
||||||
if (cluster.data[0] == 0x00) {
|
|
||||||
log.debug "ON/OFF REPORTING CONFIG RESPONSE: " + cluster
|
|
||||||
sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log.warn "ON/OFF REPORTING CONFIG FAILED- error code:${cluster.data[0]}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log.warn "DID NOT PARSE MESSAGE for description : $description"
|
|
||||||
log.debug "${cluster}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def off() {
|
|
||||||
zigbee.off()
|
|
||||||
}
|
|
||||||
|
|
||||||
def on() {
|
|
||||||
zigbee.on()
|
|
||||||
}
|
|
||||||
|
|
||||||
def setLevel(value) {
|
|
||||||
zigbee.setLevel(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PING is used by Device-Watch in attempt to reach the Device
|
|
||||||
* */
|
|
||||||
def ping() {
|
|
||||||
return zigbee.onOffRefresh()
|
|
||||||
}
|
|
||||||
|
|
||||||
def refresh() {
|
|
||||||
zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh() + zigbee.onOffConfig(0, 300) + zigbee.levelConfig() + zigbee.colorTemperatureConfig()
|
|
||||||
}
|
|
||||||
|
|
||||||
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])
|
|
||||||
|
|
||||||
// OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity
|
|
||||||
refresh()
|
|
||||||
}
|
|
||||||
|
|
||||||
def setColorTemperature(value) {
|
|
||||||
setGenericName(value)
|
|
||||||
zigbee.setColorTemperature(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
//Naming based on the wiki article here: http://en.wikipedia.org/wiki/Color_temperature
|
|
||||||
def setGenericName(value){
|
|
||||||
if (value != null) {
|
|
||||||
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 >= 5000) {
|
|
||||||
genericName = "Daylight"
|
|
||||||
}
|
|
||||||
sendEvent(name: "colorName", value: genericName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -71,7 +71,7 @@ def parse(String description) {
|
|||||||
|
|
||||||
def event = [:]
|
def event = [:]
|
||||||
def finalResult = isKnownDescription(description)
|
def finalResult = isKnownDescription(description)
|
||||||
if (finalResult != "false") {
|
if (finalResult) {
|
||||||
log.info finalResult
|
log.info finalResult
|
||||||
if (finalResult.type == "update") {
|
if (finalResult.type == "update") {
|
||||||
log.info "$device updates: ${finalResult.value}"
|
log.info "$device updates: ${finalResult.value}"
|
||||||
@@ -212,13 +212,16 @@ def isKnownDescription(description) {
|
|||||||
else if (descMap.cluster == "0B04" || descMap.clusterId == "0B04"){
|
else if (descMap.cluster == "0B04" || descMap.clusterId == "0B04"){
|
||||||
isDescriptionPower(descMap)
|
isDescriptionPower(descMap)
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
return [:]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if(description?.startsWith("on/off:")) {
|
else if(description?.startsWith("on/off:")) {
|
||||||
def switchValue = description?.endsWith("1") ? "on" : "off"
|
def switchValue = description?.endsWith("1") ? "on" : "off"
|
||||||
return [type: "switch", value : switchValue]
|
return [type: "switch", value : switchValue]
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return "false"
|
return [:]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,7 +255,7 @@ def isDescriptionOnOff(descMap) {
|
|||||||
return [type: "switch", value : switchValue]
|
return [type: "switch", value : switchValue]
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return "false"
|
return [:]
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -279,10 +282,9 @@ def isDescriptionLevel(descMap) {
|
|||||||
|
|
||||||
if (dimmerValue != -1){
|
if (dimmerValue != -1){
|
||||||
return [type: "level", value : dimmerValue]
|
return [type: "level", value : dimmerValue]
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return "false"
|
return [:]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,7 +306,7 @@ def isDescriptionPower(descMap) {
|
|||||||
return [type: "power", value : powerValue]
|
return [type: "power", value : powerValue]
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return "false"
|
return [:]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# SmartPower Outlet
|
# SmartPower Outlet
|
||||||
|
|
||||||
|
Local Execution on V2 Hubs
|
||||||
|
|
||||||
Works with:
|
Works with:
|
||||||
|
|
||||||
@@ -23,10 +23,11 @@ Works with:
|
|||||||
|
|
||||||
## Device Health
|
## Device Health
|
||||||
|
|
||||||
A Category C1 smart power outlet with maxReportTime of 5 mins.
|
SmartPower outlet with reporting interval of 5 mins
|
||||||
Check-in interval is double the value of maxReportTime.
|
SmartThings platform will ping the device after `checkInterval` seconds of inactivity in last attempt to reach the device before marking it `OFFLINE`
|
||||||
This gives the device twice the amount of time to respond before it is marked as offline.
|
|
||||||
Check-in interval = 12 mins
|
* V1, TV, HubV2 AppEngine < 1.5.1 - __21min__ checkInterval
|
||||||
|
* HubV2 AppEngine 1.5.1 - __12min__ checkInterval
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
|
|||||||
@@ -145,9 +145,9 @@ def refresh() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
// Device-Watch allows 3 check-in misses from device (plus 1 min lag time)
|
// Device-Watch allows 2 check-in misses from device + ping (plus 1 min lag time)
|
||||||
// enrolls with default periodic reporting until newer 5 min interval is confirmed
|
// 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: 2 * 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
|
// OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity
|
||||||
refresh() + zigbee.onOffConfig(0, 300) + powerConfig()
|
refresh() + zigbee.onOffConfig(0, 300) + powerConfig()
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Smartsense Moisture Sensor
|
# Smartsense Moisture Sensor
|
||||||
|
|
||||||
|
Local Execution on V2 Hubs
|
||||||
|
|
||||||
Works with:
|
Works with:
|
||||||
|
|
||||||
@@ -23,10 +23,11 @@ Works with:
|
|||||||
|
|
||||||
## Device Health
|
## Device Health
|
||||||
|
|
||||||
A Category C2 moisture sensor with maxReportTime of 5 mins.
|
SmartSense Moisture sensor with reporting interval of 5 mins.
|
||||||
Check-in interval is double the value of maxReportTime.
|
SmartThings platform will ping the device after `checkInterval` seconds of inactivity in last attempt to reach the device before marking it `OFFLINE`
|
||||||
This gives the device twice the amount of time to respond before it is marked as offline.
|
|
||||||
Check-in interval = 12 mins
|
* V1, TV, HubV2 AppEngine < 1.5.1 - __121min__ checkInterval
|
||||||
|
* HubV2 AppEngine 1.5.1 - __12min__ checkInterval
|
||||||
|
|
||||||
## Battery Specification
|
## Battery Specification
|
||||||
|
|
||||||
|
|||||||
@@ -293,9 +293,9 @@ def refresh() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
// Device-Watch allows 3 check-in misses from device (plus 1 min lag time)
|
// Device-Watch allows 2 check-in misses from device + ping (plus 1 min lag time)
|
||||||
// enrolls with default periodic reporting until newer 5 min interval is confirmed
|
// enrolls with default periodic reporting until newer 5 min interval is confirmed
|
||||||
sendEvent(name: "checkInterval", value: 3 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
||||||
|
|
||||||
// temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity
|
// temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity
|
||||||
// battery minReport 30 seconds, maxReportTime 6 hrs by default
|
// battery minReport 30 seconds, maxReportTime 6 hrs by default
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Smartsense Motion Sensor
|
# Smartsense Motion Sensor
|
||||||
|
|
||||||
|
Local Execution on V2 Hubs
|
||||||
|
|
||||||
Works with:
|
Works with:
|
||||||
|
|
||||||
@@ -22,10 +22,12 @@ Works with:
|
|||||||
|
|
||||||
## Device Health
|
## Device Health
|
||||||
|
|
||||||
A Category C2 motion sensor with maxReportTime of 5 mins.
|
SmartSense Motion sensor with reporting interval of 5 mins.
|
||||||
Check-in interval is double the value of maxReportTime.
|
SmartThings platform will ping the device after `checkInterval` seconds of inactivity in last attempt to reach the device before marking it `OFFLINE`
|
||||||
This gives the device twice the amount of time to respond before it is marked as offline.
|
|
||||||
Check-in interval = 12 mins
|
* V1, TV, HubV2 AppEngine < 1.5.1 - __121min__ checkInterval
|
||||||
|
* HubV2 AppEngine 1.5.1 - __12min__ checkInterval
|
||||||
|
|
||||||
|
|
||||||
## Battery Specification
|
## Battery Specification
|
||||||
|
|
||||||
|
|||||||
@@ -306,9 +306,9 @@ def refresh() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
// Device-Watch allows 3 check-in misses from device (plus 1 min lag time)
|
// Device-Watch allows 2 check-in misses from device + ping (plus 1 min lag time)
|
||||||
// enrolls with default periodic reporting until newer 5 min interval is confirmed
|
// enrolls with default periodic reporting until newer 5 min interval is confirmed
|
||||||
sendEvent(name: "checkInterval", value: 3 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
||||||
|
|
||||||
// temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity
|
// temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity
|
||||||
// battery minReport 30 seconds, maxReportTime 6 hrs by default
|
// battery minReport 30 seconds, maxReportTime 6 hrs by default
|
||||||
|
|||||||
@@ -1,328 +0,0 @@
|
|||||||
/**
|
|
||||||
* SmartSense Motion/Temp Sensor
|
|
||||||
*
|
|
||||||
* Copyright 2014 SmartThings
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at:
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
|
||||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
|
|
||||||
* for the specific language governing permissions and limitations under the License.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
//DEPRECATED - Using the smartsense-motion-sensor.groovy DTH for this device. Users need to be moved before deleting this DTH
|
|
||||||
import physicalgraph.zigbee.clusters.iaszone.ZoneStatus
|
|
||||||
|
|
||||||
metadata {
|
|
||||||
definition (name: "SmartSense Motion/Temp Sensor", namespace: "smartthings", author: "SmartThings") {
|
|
||||||
capability "Motion Sensor"
|
|
||||||
capability "Configuration"
|
|
||||||
capability "Battery"
|
|
||||||
capability "Temperature Measurement"
|
|
||||||
capability "Refresh"
|
|
||||||
capability "Sensor"
|
|
||||||
|
|
||||||
command "enrollResponse"
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
preferences {
|
|
||||||
section {
|
|
||||||
image(name: 'educationalcontent', multiple: true, images: [
|
|
||||||
"http://cdn.device-gse.smartthings.com/Motion/Motion1.jpg",
|
|
||||||
"http://cdn.device-gse.smartthings.com/Motion/Motion2.jpg",
|
|
||||||
"http://cdn.device-gse.smartthings.com/Motion/Motion3.jpg"
|
|
||||||
])
|
|
||||||
}
|
|
||||||
section {
|
|
||||||
input title: "Temperature Offset", description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter '-5'. If 3 degrees too cold, enter '+3'.", displayDuringSetup: false, type: "paragraph", element: "paragraph"
|
|
||||||
input "tempOffset", "number", title: "Degrees", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tiles(scale: 2) {
|
|
||||||
multiAttributeTile(name:"motion", type: "generic", width: 6, height: 4){
|
|
||||||
tileAttribute ("device.motion", key: "PRIMARY_CONTROL") {
|
|
||||||
attributeState "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0"
|
|
||||||
attributeState "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
valueTile("temperature", "device.temperature", width: 2, height: 2) {
|
|
||||||
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("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) {
|
|
||||||
state "battery", label:'${currentValue}% battery', unit:""
|
|
||||||
}
|
|
||||||
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
|
||||||
state "default", action:"refresh.refresh", icon:"st.secondary.refresh"
|
|
||||||
}
|
|
||||||
|
|
||||||
main(["motion", "temperature"])
|
|
||||||
details(["motion", "temperature", "battery", "refresh"])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def parse(String description) {
|
|
||||||
log.debug "description: $description"
|
|
||||||
|
|
||||||
Map map = [:]
|
|
||||||
if (description?.startsWith('catchall:')) {
|
|
||||||
map = parseCatchAllMessage(description)
|
|
||||||
}
|
|
||||||
else if (description?.startsWith('read attr -')) {
|
|
||||||
map = parseReportAttributeMessage(description)
|
|
||||||
}
|
|
||||||
else if (description?.startsWith('temperature: ')) {
|
|
||||||
map = parseCustomMessage(description)
|
|
||||||
}
|
|
||||||
else if (description?.startsWith('zone status')) {
|
|
||||||
map = parseIasMessage(description)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.debug "Parse returned $map"
|
|
||||||
def result = map ? createEvent(map) : [:]
|
|
||||||
|
|
||||||
if (description?.startsWith('enroll request')) {
|
|
||||||
List cmds = enrollResponse()
|
|
||||||
log.debug "enroll response: ${cmds}"
|
|
||||||
result = cmds?.collect { new physicalgraph.device.HubAction(it) }
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map parseCatchAllMessage(String description) {
|
|
||||||
Map resultMap = [:]
|
|
||||||
def cluster = zigbee.parse(description)
|
|
||||||
if (shouldProcessMessage(cluster)) {
|
|
||||||
switch(cluster.clusterId) {
|
|
||||||
case 0x0001:
|
|
||||||
// 0x07 - configure reporting
|
|
||||||
if (cluster.command != 0x07) {
|
|
||||||
resultMap = getBatteryResult(cluster.data.last())
|
|
||||||
}
|
|
||||||
break
|
|
||||||
|
|
||||||
case 0x0402:
|
|
||||||
if (cluster.command == 0x07) {
|
|
||||||
if (cluster.data[0] == 0x00) {
|
|
||||||
log.debug "TEMP REPORTING CONFIG RESPONSE" + cluster
|
|
||||||
sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log.warn "TEMP REPORTING CONFIG FAILED- error code:${cluster.data[0]}"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// temp is last 2 data values. reverse to swap endian
|
|
||||||
String temp = cluster.data[-2..-1].reverse().collect { cluster.hex1(it) }.join()
|
|
||||||
def value = getTemperature(temp)
|
|
||||||
resultMap = getTemperatureResult(value)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
|
|
||||||
case 0x0406:
|
|
||||||
// 0x07 - configure reporting
|
|
||||||
if (cluster.command != 0x07) {
|
|
||||||
log.debug 'motion'
|
|
||||||
resultMap.name = 'motion'
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return resultMap
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean shouldProcessMessage(cluster) {
|
|
||||||
// 0x0B is default response indicating message got through
|
|
||||||
boolean ignoredMessage = cluster.profileId != 0x0104 ||
|
|
||||||
cluster.command == 0x0B ||
|
|
||||||
(cluster.data.size() > 0 && cluster.data.first() == 0x3e)
|
|
||||||
return !ignoredMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map parseReportAttributeMessage(String description) {
|
|
||||||
Map descMap = (description - "read attr - ").split(",").inject([:]) { map, param ->
|
|
||||||
def nameAndValue = param.split(":")
|
|
||||||
map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
|
|
||||||
}
|
|
||||||
log.debug "Desc Map: $descMap"
|
|
||||||
|
|
||||||
Map resultMap = [:]
|
|
||||||
if (descMap.cluster == "0402" && descMap.attrId == "0000") {
|
|
||||||
def value = getTemperature(descMap.value)
|
|
||||||
resultMap = getTemperatureResult(value)
|
|
||||||
}
|
|
||||||
else if (descMap.cluster == "0001" && descMap.attrId == "0020") {
|
|
||||||
resultMap = getBatteryResult(Integer.parseInt(descMap.value, 16))
|
|
||||||
}
|
|
||||||
else if (descMap.cluster == "0406" && descMap.attrId == "0000") {
|
|
||||||
def value = descMap.value.endsWith("01") ? "active" : "inactive"
|
|
||||||
resultMap = getMotionResult(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
return resultMap
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map parseCustomMessage(String description) {
|
|
||||||
Map resultMap = [:]
|
|
||||||
if (description?.startsWith('temperature: ')) {
|
|
||||||
def value = zigbee.parseHATemperatureValue(description, "temperature: ", getTemperatureScale())
|
|
||||||
resultMap = getTemperatureResult(value)
|
|
||||||
}
|
|
||||||
return resultMap
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map parseIasMessage(String description) {
|
|
||||||
ZoneStatus zs = zigbee.parseZoneStatus(description)
|
|
||||||
|
|
||||||
// Some sensor models that use this DTH use alarm1 and some use alarm2 to signify motion
|
|
||||||
return (zs.isAlarm1Set() || zs.isAlarm2Set()) ? getMotionResult('active') : getMotionResult('inactive')
|
|
||||||
}
|
|
||||||
|
|
||||||
def getTemperature(value) {
|
|
||||||
def celsius = Integer.parseInt(value, 16).shortValue() / 100
|
|
||||||
if(getTemperatureScale() == "C"){
|
|
||||||
return Math.round(celsius)
|
|
||||||
} else {
|
|
||||||
return Math.round(celsiusToFahrenheit(celsius))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map getBatteryResult(rawValue) {
|
|
||||||
log.debug 'Battery'
|
|
||||||
def linkText = getLinkText(device)
|
|
||||||
|
|
||||||
def result = [:]
|
|
||||||
|
|
||||||
def volts = rawValue / 10
|
|
||||||
|
|
||||||
if (!(rawValue == 0 || rawValue == 255)) {
|
|
||||||
def minVolts = 2.1
|
|
||||||
def maxVolts = 3.0
|
|
||||||
def pct = (volts - minVolts) / (maxVolts - minVolts)
|
|
||||||
def roundedPct = Math.round(pct * 100)
|
|
||||||
if (roundedPct <= 0)
|
|
||||||
roundedPct = 1
|
|
||||||
result.name = 'battery'
|
|
||||||
result.value = Math.min(100, roundedPct)
|
|
||||||
result.descriptionText = "${linkText} battery was ${result.value}%"
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map getTemperatureResult(value) {
|
|
||||||
log.debug 'TEMP'
|
|
||||||
if (tempOffset) {
|
|
||||||
def offset = tempOffset as int
|
|
||||||
def v = value as int
|
|
||||||
value = v + offset
|
|
||||||
}
|
|
||||||
def descriptionText
|
|
||||||
if ( temperatureScale == 'C' )
|
|
||||||
descriptionText = '{{ device.displayName }} was {{ value }}°C'
|
|
||||||
else
|
|
||||||
descriptionText = '{{ device.displayName }} was {{ value }}°F'
|
|
||||||
|
|
||||||
return [
|
|
||||||
name: 'temperature',
|
|
||||||
value: value,
|
|
||||||
descriptionText: descriptionText,
|
|
||||||
translatable: true,
|
|
||||||
unit: temperatureScale
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map getMotionResult(value) {
|
|
||||||
log.debug 'motion'
|
|
||||||
String descriptionText = value == 'active' ? "{{ device.displayName }} detected motion" : "{{ device.displayName }} motion has stopped"
|
|
||||||
return [
|
|
||||||
name: 'motion',
|
|
||||||
value: value,
|
|
||||||
descriptionText: descriptionText,
|
|
||||||
translatable: true
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PING is used by Device-Watch in attempt to reach the Device
|
|
||||||
* */
|
|
||||||
def ping() {
|
|
||||||
return zigbee.readAttribute(0x001, 0x0020) // Read the Battery Level
|
|
||||||
}
|
|
||||||
|
|
||||||
def refresh() {
|
|
||||||
log.debug "refresh called"
|
|
||||||
def refreshCmds = [
|
|
||||||
"st rattr 0x${device.deviceNetworkId} 1 0x402 0", "delay 200",
|
|
||||||
"st rattr 0x${device.deviceNetworkId} 1 1 0x20", "delay 200"
|
|
||||||
]
|
|
||||||
|
|
||||||
return refreshCmds + enrollResponse()
|
|
||||||
}
|
|
||||||
|
|
||||||
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 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
|
||||||
|
|
||||||
// temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity
|
|
||||||
// battery minReport 30 seconds, maxReportTime 6 hrs by default
|
|
||||||
return refresh() + zigbee.batteryConfig() + zigbee.temperatureConfig(30, 300) // send refresh cmds as part of config
|
|
||||||
}
|
|
||||||
|
|
||||||
def enrollResponse() {
|
|
||||||
log.debug "Sending enroll response"
|
|
||||||
String zigbeeEui = swapEndianHex(device.hub.zigbeeEui)
|
|
||||||
[
|
|
||||||
//Resending the CIE in case the enroll request is sent before CIE is written
|
|
||||||
"zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}", "delay 200",
|
|
||||||
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
|
|
||||||
//Enroll Response
|
|
||||||
"raw 0x500 {01 23 00 00 00}",
|
|
||||||
"send 0x${device.deviceNetworkId} 1 1", "delay 200"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
private getEndpointId() {
|
|
||||||
new BigInteger(device.endpointId, 16).toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
private hex(value) {
|
|
||||||
new BigInteger(Math.round(value).toString()).toString(16)
|
|
||||||
}
|
|
||||||
|
|
||||||
private String swapEndianHex(String hex) {
|
|
||||||
reverseArray(hex.decodeHex()).encodeHex()
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] reverseArray(byte[] array) {
|
|
||||||
int i = 0;
|
|
||||||
int j = array.length - 1;
|
|
||||||
byte tmp;
|
|
||||||
while (j > i) {
|
|
||||||
tmp = array[j];
|
|
||||||
array[j] = array[i];
|
|
||||||
array[i] = tmp;
|
|
||||||
j--;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
return array
|
|
||||||
}
|
|
||||||
@@ -57,6 +57,7 @@ def parse(String description) {
|
|||||||
|
|
||||||
private Map parseBasicMessage(description) {
|
private Map parseBasicMessage(description) {
|
||||||
def name = parseName(description)
|
def name = parseName(description)
|
||||||
|
def results = [:]
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
def value = parseValue(description)
|
def value = parseValue(description)
|
||||||
def linkText = getLinkText(device)
|
def linkText = getLinkText(device)
|
||||||
@@ -64,7 +65,7 @@ private Map parseBasicMessage(description) {
|
|||||||
def handlerName = value
|
def handlerName = value
|
||||||
def isStateChange = isStateChange(device, name, value)
|
def isStateChange = isStateChange(device, name, value)
|
||||||
|
|
||||||
def results = [
|
results = [
|
||||||
name : name,
|
name : name,
|
||||||
value : value,
|
value : value,
|
||||||
linkText : linkText,
|
linkText : linkText,
|
||||||
@@ -73,8 +74,6 @@ private Map parseBasicMessage(description) {
|
|||||||
isStateChange : isStateChange,
|
isStateChange : isStateChange,
|
||||||
displayed : displayed(description, isStateChange)
|
displayed : displayed(description, isStateChange)
|
||||||
]
|
]
|
||||||
} else {
|
|
||||||
results = [:]
|
|
||||||
}
|
}
|
||||||
log.debug "Parse returned $results.descriptionText"
|
log.debug "Parse returned $results.descriptionText"
|
||||||
return results
|
return results
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Smartsense Multi Sensor
|
# Smartsense Multi Sensor
|
||||||
|
|
||||||
|
Local Execution on V2 Hubs
|
||||||
|
|
||||||
Works with:
|
Works with:
|
||||||
|
|
||||||
@@ -26,10 +26,11 @@ Works with:
|
|||||||
|
|
||||||
## Device Health
|
## Device Health
|
||||||
|
|
||||||
A Category C2 multi sensor with maxReportTime of 5 mins.
|
SmartSense Multi sensor with reporting interval of 5 mins.
|
||||||
Check-in interval is double the value of maxReportTime.
|
SmartThings platform will ping the device after `checkInterval` seconds of inactivity in last attempt to reach the device before marking it `OFFLINE`
|
||||||
This gives the device twice the amount of time to respond before it is marked as offline.
|
|
||||||
Check-in interval = 12 mins
|
* V1, TV, HubV2 AppEngine < 1.5.1 - __121min__ checkInterval
|
||||||
|
* HubV2 AppEngine 1.5.1 - __12min__ checkInterval
|
||||||
|
|
||||||
## Battery Specification
|
## Battery Specification
|
||||||
|
|
||||||
|
|||||||
@@ -400,9 +400,9 @@ def refresh() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
// Device-Watch allows 3 check-in misses from device (plus 1 min lag time)
|
// Device-Watch allows 2 check-in misses from device + ping (plus 1 min lag time)
|
||||||
// enrolls with default periodic reporting until newer 5 min interval is confirmed
|
// enrolls with default periodic reporting until newer 5 min interval is confirmed
|
||||||
sendEvent(name: "checkInterval", value: 3 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
||||||
|
|
||||||
log.debug "Configuring Reporting"
|
log.debug "Configuring Reporting"
|
||||||
|
|
||||||
|
|||||||
@@ -1,503 +0,0 @@
|
|||||||
/**
|
|
||||||
* SmartSense Open/Closed Accelerometer Sensor
|
|
||||||
*
|
|
||||||
* Copyright 2014 SmartThings
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at:
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
|
||||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
|
|
||||||
* for the specific language governing permissions and limitations under the License.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
//DEPRECATED - Using the smartsense-multi-sensor.groovy DTH for this device. Users need to be moved before deleting this DTH
|
|
||||||
import physicalgraph.zigbee.clusters.iaszone.ZoneStatus
|
|
||||||
|
|
||||||
metadata {
|
|
||||||
definition (name: "SmartSense Open/Closed Accelerometer Sensor", namespace: "smartthings", author: "SmartThings", category: "C2") {
|
|
||||||
capability "Battery"
|
|
||||||
capability "Configuration"
|
|
||||||
capability "Contact Sensor"
|
|
||||||
capability "Acceleration Sensor"
|
|
||||||
capability "Refresh"
|
|
||||||
capability "Temperature Measurement"
|
|
||||||
capability "Health Check"
|
|
||||||
capability "Sensor"
|
|
||||||
|
|
||||||
command "enrollResponse"
|
|
||||||
attribute "status", "string"
|
|
||||||
}
|
|
||||||
|
|
||||||
preferences {
|
|
||||||
section {
|
|
||||||
image(name: 'educationalcontent', multiple: true, images: [
|
|
||||||
"http://cdn.device-gse.smartthings.com/Multi/Multi1.jpg",
|
|
||||||
"http://cdn.device-gse.smartthings.com/Multi/Multi2.jpg",
|
|
||||||
"http://cdn.device-gse.smartthings.com/Multi/Multi3.jpg",
|
|
||||||
"http://cdn.device-gse.smartthings.com/Multi/Multi4.jpg"
|
|
||||||
])
|
|
||||||
}
|
|
||||||
section {
|
|
||||||
input title: "Temperature Offset", description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter '-5'. If 3 degrees too cold, enter '+3'.", displayDuringSetup: false, type: "paragraph", element: "paragraph"
|
|
||||||
input "tempOffset", "number", title: "Degrees", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
|
|
||||||
}
|
|
||||||
section {
|
|
||||||
input("garageSensor", "enum", title: "Do you want to use this sensor on a garage door?", description: "Tap to set", options: ["Yes", "No"], defaultValue: "No", required: false, displayDuringSetup: false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tiles(scale: 2) {
|
|
||||||
multiAttributeTile(name:"status", type: "generic", width: 6, height: 4){
|
|
||||||
tileAttribute ("device.status", key: "PRIMARY_CONTROL") {
|
|
||||||
attributeState "open", label:'Open', icon:"st.contact.contact.open", backgroundColor:"#ffa81e"
|
|
||||||
attributeState "closed", label:'Closed', icon:"st.contact.contact.closed", backgroundColor:"#79b821"
|
|
||||||
attributeState "garage-open", label:'Open', icon:"st.doors.garage.garage-open", backgroundColor:"#ffa81e"
|
|
||||||
attributeState "garage-closed", label:'Closed', icon:"st.doors.garage.garage-closed", backgroundColor:"#79b821"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
standardTile("contact", "device.contact", width: 2, height: 2) {
|
|
||||||
state("open", label:'Open', icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
|
|
||||||
state("closed", label:'Closed', icon:"st.contact.contact.closed", backgroundColor:"#79b821")
|
|
||||||
}
|
|
||||||
standardTile("acceleration", "device.acceleration", width: 2, height: 2) {
|
|
||||||
state("active", label:'Active', icon:"st.motion.acceleration.active", backgroundColor:"#53a7c0")
|
|
||||||
state("inactive", label:'Inactive', icon:"st.motion.acceleration.inactive", backgroundColor:"#ffffff")
|
|
||||||
}
|
|
||||||
valueTile("temperature", "device.temperature", width: 2, height: 2) {
|
|
||||||
state("temperature", label:'${currentValue}°',
|
|
||||||
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("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) {
|
|
||||||
state "battery", label:'${currentValue}% battery', unit:""
|
|
||||||
}
|
|
||||||
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
|
||||||
state "default", action:"refresh.refresh", icon:"st.secondary.refresh"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
main(["status", "acceleration", "temperature"])
|
|
||||||
details(["status", "acceleration", "temperature", "battery", "refresh"])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def parse(String description) {
|
|
||||||
Map map = [:]
|
|
||||||
if (description?.startsWith('catchall:')) {
|
|
||||||
map = parseCatchAllMessage(description)
|
|
||||||
}
|
|
||||||
else if (description?.startsWith('temperature: ')) {
|
|
||||||
map = parseCustomMessage(description)
|
|
||||||
}
|
|
||||||
else if (description?.startsWith('zone status')) {
|
|
||||||
map = parseIasMessage(description)
|
|
||||||
}
|
|
||||||
|
|
||||||
def result = map ? createEvent(map) : null
|
|
||||||
|
|
||||||
if (description?.startsWith('enroll request')) {
|
|
||||||
List cmds = enrollResponse()
|
|
||||||
log.debug "enroll response: ${cmds}"
|
|
||||||
result = cmds?.collect { new physicalgraph.device.HubAction(it) }
|
|
||||||
}
|
|
||||||
else if (description?.startsWith('read attr -')) {
|
|
||||||
result = parseReportAttributeMessage(description).each { createEvent(it) }
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map parseCatchAllMessage(String description) {
|
|
||||||
Map resultMap = [:]
|
|
||||||
def cluster = zigbee.parse(description)
|
|
||||||
log.debug cluster
|
|
||||||
if (shouldProcessMessage(cluster)) {
|
|
||||||
switch(cluster.clusterId) {
|
|
||||||
case 0x0001:
|
|
||||||
// 0x07 - configure reporting
|
|
||||||
if (cluster.command != 0x07) {
|
|
||||||
resultMap = getBatteryResult(cluster.data.last())
|
|
||||||
}
|
|
||||||
break
|
|
||||||
|
|
||||||
case 0xFC02:
|
|
||||||
log.debug 'ACCELERATION'
|
|
||||||
break
|
|
||||||
|
|
||||||
case 0x0402:
|
|
||||||
if (cluster.command == 0x07) {
|
|
||||||
if(cluster.data[0] == 0x00) {
|
|
||||||
log.debug "TEMP REPORTING CONFIG RESPONSE" + cluster
|
|
||||||
sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log.warn "TEMP REPORTING CONFIG FAILED- error code:${cluster.data[0]}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// temp is last 2 data values. reverse to swap endian
|
|
||||||
String temp = cluster.data[-2..-1].reverse().collect { cluster.hex1(it) }.join()
|
|
||||||
def value = getTemperature(temp)
|
|
||||||
resultMap = getTemperatureResult(value)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return resultMap
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean shouldProcessMessage(cluster) {
|
|
||||||
// 0x0B is default response indicating message got through
|
|
||||||
boolean ignoredMessage = cluster.profileId != 0x0104 ||
|
|
||||||
cluster.command == 0x0B ||
|
|
||||||
(cluster.data.size() > 0 && cluster.data.first() == 0x3e)
|
|
||||||
return !ignoredMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
private List parseReportAttributeMessage(String description) {
|
|
||||||
Map descMap = (description - "read attr - ").split(",").inject([:]) { map, param ->
|
|
||||||
def nameAndValue = param.split(":")
|
|
||||||
map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
|
|
||||||
}
|
|
||||||
|
|
||||||
List result = []
|
|
||||||
if (descMap.cluster == "0402" && descMap.attrId == "0000") {
|
|
||||||
def value = getTemperature(descMap.value)
|
|
||||||
result << getTemperatureResult(value)
|
|
||||||
}
|
|
||||||
else if (descMap.cluster == "FC02" && descMap.attrId == "0010") {
|
|
||||||
if (descMap.value.size() == 32) {
|
|
||||||
// value will look like 00ae29001403e2290013001629001201
|
|
||||||
// breaking this apart and swapping byte order where appropriate, this breaks down to:
|
|
||||||
// X (0x0012) = 0x0016
|
|
||||||
// Y (0x0013) = 0x03E2
|
|
||||||
// Z (0x0014) = 0x00AE
|
|
||||||
// note that there is a known bug in that the x,y,z attributes are interpreted in the wrong order
|
|
||||||
// this will be fixed in a future update
|
|
||||||
def threeAxisAttributes = descMap.value[0..-9]
|
|
||||||
result << parseAxis(threeAxisAttributes)
|
|
||||||
descMap.value = descMap.value[-2..-1]
|
|
||||||
}
|
|
||||||
result << getAccelerationResult(descMap.value)
|
|
||||||
}
|
|
||||||
else if (descMap.cluster == "FC02" && descMap.attrId == "0012" && descMap.value.size() == 24) {
|
|
||||||
// The size is checked to ensure the attribute report contains X, Y and Z values
|
|
||||||
// If all three axis are not included then the attribute report is ignored
|
|
||||||
result << parseAxis(descMap.value)
|
|
||||||
}
|
|
||||||
else if (descMap.cluster == "0001" && descMap.attrId == "0020") {
|
|
||||||
result << getBatteryResult(Integer.parseInt(descMap.value, 16))
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map parseCustomMessage(String description) {
|
|
||||||
Map resultMap = [:]
|
|
||||||
if (description?.startsWith('temperature: ')) {
|
|
||||||
def value = zigbee.parseHATemperatureValue(description, "temperature: ", getTemperatureScale())
|
|
||||||
resultMap = getTemperatureResult(value)
|
|
||||||
}
|
|
||||||
return resultMap
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map parseIasMessage(String description) {
|
|
||||||
ZoneStatus zs = zigbee.parseZoneStatus(description)
|
|
||||||
Map resultMap = [:]
|
|
||||||
|
|
||||||
if (garageSensor != "Yes"){
|
|
||||||
resultMap = zs.isAlarm1Set() ? getContactResult('open') : getContactResult('closed')
|
|
||||||
}
|
|
||||||
|
|
||||||
return resultMap
|
|
||||||
}
|
|
||||||
|
|
||||||
def updated() {
|
|
||||||
log.debug "updated called"
|
|
||||||
log.info "garage value : $garageSensor"
|
|
||||||
if (garageSensor == "Yes") {
|
|
||||||
def descriptionText = "Updating device to garage sensor"
|
|
||||||
if (device.latestValue("status") == "open") {
|
|
||||||
sendEvent(name: 'status', value: 'garage-open', descriptionText: descriptionText, translatable: true)
|
|
||||||
}
|
|
||||||
else if (device.latestValue("status") == "closed") {
|
|
||||||
sendEvent(name: 'status', value: 'garage-closed', descriptionText: descriptionText, translatable: true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
def descriptionText = "Updating device to open/close sensor"
|
|
||||||
if (device.latestValue("status") == "garage-open") {
|
|
||||||
sendEvent(name: 'status', value: 'open', descriptionText: descriptionText, translatable: true)
|
|
||||||
}
|
|
||||||
else if (device.latestValue("status") == "garage-closed") {
|
|
||||||
sendEvent(name: 'status', value: 'closed', descriptionText: descriptionText, translatable: true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def getTemperature(value) {
|
|
||||||
def celsius = Integer.parseInt(value, 16).shortValue() / 100
|
|
||||||
if(getTemperatureScale() == "C"){
|
|
||||||
return Math.round(celsius)
|
|
||||||
} else {
|
|
||||||
return Math.round(celsiusToFahrenheit(celsius))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map getBatteryResult(rawValue) {
|
|
||||||
log.debug 'Battery'
|
|
||||||
def linkText = getLinkText(device)
|
|
||||||
|
|
||||||
def result = [:]
|
|
||||||
|
|
||||||
def volts = rawValue / 10
|
|
||||||
|
|
||||||
if (!(rawValue == 0 || rawValue == 255)) {
|
|
||||||
def minVolts = 2.1
|
|
||||||
def maxVolts = 3.0
|
|
||||||
def pct = (volts - minVolts) / (maxVolts - minVolts)
|
|
||||||
def roundedPct = Math.round(pct * 100)
|
|
||||||
if (roundedPct <= 0)
|
|
||||||
roundedPct = 1
|
|
||||||
result.name = 'battery'
|
|
||||||
result.value = Math.min(100, roundedPct)
|
|
||||||
result.descriptionText = "${linkText} battery was ${result.value}%"
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map getTemperatureResult(value) {
|
|
||||||
log.debug "Temperature"
|
|
||||||
if (tempOffset) {
|
|
||||||
def offset = tempOffset as int
|
|
||||||
def v = value as int
|
|
||||||
value = v + offset
|
|
||||||
}
|
|
||||||
def descriptionText = temperatureScale == 'C' ? '{{ device.displayName }} was {{ value }}°C':
|
|
||||||
'{{ device.displayName }} was {{ value }}°F'
|
|
||||||
|
|
||||||
return [
|
|
||||||
name: 'temperature',
|
|
||||||
value: value,
|
|
||||||
descriptionText: descriptionText,
|
|
||||||
translatable: true,
|
|
||||||
unit: temperatureScale
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map getContactResult(value) {
|
|
||||||
log.debug "Contact: ${device.displayName} value = ${value}"
|
|
||||||
def descriptionText = value == 'open' ? '{{ device.displayName }} was opened' : '{{ device.displayName }} was closed'
|
|
||||||
sendEvent(name: 'contact', value: value, descriptionText: descriptionText, displayed: false, translatable: true)
|
|
||||||
sendEvent(name: 'status', value: value, descriptionText: descriptionText, translatable: true)
|
|
||||||
}
|
|
||||||
|
|
||||||
private getAccelerationResult(numValue) {
|
|
||||||
log.debug "Acceleration"
|
|
||||||
def name = "acceleration"
|
|
||||||
def value
|
|
||||||
def descriptionText
|
|
||||||
|
|
||||||
if ( numValue.endsWith("1") ) {
|
|
||||||
value = "active"
|
|
||||||
descriptionText = '{{ device.displayName }} was active'
|
|
||||||
} else {
|
|
||||||
value = "inactive"
|
|
||||||
descriptionText = '{{ device.displayName }} was inactive'
|
|
||||||
}
|
|
||||||
|
|
||||||
def isStateChange = isStateChange(device, name, value)
|
|
||||||
return [
|
|
||||||
name: name,
|
|
||||||
value: value,
|
|
||||||
descriptionText: descriptionText,
|
|
||||||
isStateChange: isStateChange,
|
|
||||||
translatable: true
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PING is used by Device-Watch in attempt to reach the Device
|
|
||||||
* */
|
|
||||||
def ping() {
|
|
||||||
return zigbee.readAttribute(0x001, 0x0020) // Read the Battery Level
|
|
||||||
}
|
|
||||||
|
|
||||||
def refresh() {
|
|
||||||
log.debug "Refreshing Values "
|
|
||||||
|
|
||||||
def refreshCmds = []
|
|
||||||
|
|
||||||
if (device.getDataValue("manufacturer") == "SmartThings") {
|
|
||||||
log.debug "Refreshing Values for manufacturer: SmartThings "
|
|
||||||
/* These values of Motion Threshold Multiplier(0x01) and Motion Threshold (0x0276)
|
|
||||||
seem to be giving pretty accurate results for the XYZ co-ordinates for this manufacturer.
|
|
||||||
Separating these out in a separate if-else because I do not want to touch Centralite part
|
|
||||||
as of now.
|
|
||||||
*/
|
|
||||||
refreshCmds += zigbee.writeAttribute(0xFC02, 0x0000, 0x20, 0x01, [mfgCode: manufacturerCode])
|
|
||||||
refreshCmds += zigbee.writeAttribute(0xFC02, 0x0002, 0x21, 0x0276, [mfgCode: manufacturerCode])
|
|
||||||
} else {
|
|
||||||
refreshCmds += zigbee.writeAttribute(0xFC02, 0x0000, 0x20, 0x02, [mfgCode: manufacturerCode])
|
|
||||||
}
|
|
||||||
|
|
||||||
//Common refresh commands
|
|
||||||
refreshCmds += zigbee.readAttribute(0x0402, 0x0000) +
|
|
||||||
zigbee.readAttribute(0x0001, 0x0020) +
|
|
||||||
zigbee.readAttribute(0xFC02, 0x0010, [mfgCode: manufacturerCode])
|
|
||||||
|
|
||||||
return refreshCmds + enrollResponse()
|
|
||||||
}
|
|
||||||
|
|
||||||
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 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
|
||||||
|
|
||||||
log.debug "Configuring Reporting"
|
|
||||||
|
|
||||||
// temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity
|
|
||||||
// battery minReport 30 seconds, maxReportTime 6 hrs by default
|
|
||||||
def configCmds = zigbee.batteryConfig() +
|
|
||||||
zigbee.temperatureConfig(30, 300) +
|
|
||||||
zigbee.configureReporting(0xFC02, 0x0010, 0x18, 10, 3600, 0x01, [mfgCode: manufacturerCode]) +
|
|
||||||
zigbee.configureReporting(0xFC02, 0x0012, 0x29, 1, 3600, 0x0001, [mfgCode: manufacturerCode]) +
|
|
||||||
zigbee.configureReporting(0xFC02, 0x0013, 0x29, 1, 3600, 0x0001, [mfgCode: manufacturerCode]) +
|
|
||||||
zigbee.configureReporting(0xFC02, 0x0014, 0x29, 1, 3600, 0x0001, [mfgCode: manufacturerCode])
|
|
||||||
|
|
||||||
return refresh() + configCmds
|
|
||||||
}
|
|
||||||
|
|
||||||
private getEndpointId() {
|
|
||||||
new BigInteger(device.endpointId, 16).toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
def enrollResponse() {
|
|
||||||
log.debug "Sending enroll response"
|
|
||||||
String zigbeeEui = swapEndianHex(device.hub.zigbeeEui)
|
|
||||||
[
|
|
||||||
//Resending the CIE in case the enroll request is sent before CIE is written
|
|
||||||
"zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}", "delay 200",
|
|
||||||
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
|
|
||||||
//Enroll Response
|
|
||||||
"raw 0x500 {01 23 00 00 00}", "delay 200",
|
|
||||||
"send 0x${device.deviceNetworkId} 1 1", "delay 200"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map parseAxis(String description) {
|
|
||||||
def z = hexToSignedInt(description[0..3])
|
|
||||||
def y = hexToSignedInt(description[10..13])
|
|
||||||
def x = hexToSignedInt(description[20..23])
|
|
||||||
def xyzResults = [x: x, y: y, z: z]
|
|
||||||
|
|
||||||
if (device.getDataValue("manufacturer") == "SmartThings") {
|
|
||||||
// This mapping matches the current behavior of the Device Handler for the Centralite sensors
|
|
||||||
xyzResults.x = z
|
|
||||||
xyzResults.y = y
|
|
||||||
xyzResults.z = -x
|
|
||||||
} else {
|
|
||||||
// The axises reported by the Device Handler differ from the axises reported by the sensor
|
|
||||||
// This may change in the future
|
|
||||||
xyzResults.x = z
|
|
||||||
xyzResults.y = x
|
|
||||||
xyzResults.z = y
|
|
||||||
}
|
|
||||||
|
|
||||||
log.debug "parseAxis -- ${xyzResults}"
|
|
||||||
|
|
||||||
if (garageSensor == "Yes")
|
|
||||||
garageEvent(xyzResults.z)
|
|
||||||
|
|
||||||
getXyzResult(xyzResults, description)
|
|
||||||
}
|
|
||||||
|
|
||||||
private hexToSignedInt(hexVal) {
|
|
||||||
def unsignedVal = hexToInt(hexVal)
|
|
||||||
unsignedVal > 32767 ? unsignedVal - 65536 : unsignedVal
|
|
||||||
}
|
|
||||||
|
|
||||||
def garageEvent(zValue) {
|
|
||||||
def absValue = zValue.abs()
|
|
||||||
def contactValue = null
|
|
||||||
def garageValue = null
|
|
||||||
if (absValue>900) {
|
|
||||||
contactValue = 'closed'
|
|
||||||
garageValue = 'garage-closed'
|
|
||||||
}
|
|
||||||
else if (absValue < 100) {
|
|
||||||
contactValue = 'open'
|
|
||||||
garageValue = 'garage-open'
|
|
||||||
}
|
|
||||||
if (contactValue != null){
|
|
||||||
def descriptionText = contactValue == 'open' ? '{{ device.displayName }} was opened' :'{{ device.displayName }} was closed'
|
|
||||||
sendEvent(name: 'contact', value: contactValue, descriptionText: descriptionText, displayed:false, translatable: true)
|
|
||||||
sendEvent(name: 'status', value: garageValue, descriptionText: descriptionText, translatable: true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map getXyzResult(results, description) {
|
|
||||||
def name = "threeAxis"
|
|
||||||
def value = "${results.x},${results.y},${results.z}"
|
|
||||||
def linkText = getLinkText(device)
|
|
||||||
def descriptionText = "$linkText was $value"
|
|
||||||
def isStateChange = isStateChange(device, name, value)
|
|
||||||
|
|
||||||
[
|
|
||||||
name: name,
|
|
||||||
value: value,
|
|
||||||
unit: null,
|
|
||||||
linkText: linkText,
|
|
||||||
descriptionText: descriptionText,
|
|
||||||
handlerName: name,
|
|
||||||
isStateChange: isStateChange,
|
|
||||||
displayed: false
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
private getManufacturerCode() {
|
|
||||||
if (device.getDataValue("manufacturer") == "SmartThings") {
|
|
||||||
return "0x110A"
|
|
||||||
} else {
|
|
||||||
return "0x104E"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private hexToInt(value) {
|
|
||||||
new BigInteger(value, 16)
|
|
||||||
}
|
|
||||||
|
|
||||||
private hex(value) {
|
|
||||||
new BigInteger(Math.round(value).toString()).toString(16)
|
|
||||||
}
|
|
||||||
|
|
||||||
private String swapEndianHex(String hex) {
|
|
||||||
reverseArray(hex.decodeHex()).encodeHex()
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] reverseArray(byte[] array) {
|
|
||||||
int i = 0;
|
|
||||||
int j = array.length - 1;
|
|
||||||
byte tmp;
|
|
||||||
while (j > i) {
|
|
||||||
tmp = array[j];
|
|
||||||
array[j] = array[i];
|
|
||||||
array[i] = tmp;
|
|
||||||
j--;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
return array
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# Smartsense Open/Closed Sensor
|
# Smartsense Open/Closed Sensor
|
||||||
|
|
||||||
|
Local Execution on V2 Hubs
|
||||||
|
|
||||||
Works with:
|
Works with:
|
||||||
|
|
||||||
@@ -24,10 +24,11 @@ Works with:
|
|||||||
|
|
||||||
## Device Health
|
## Device Health
|
||||||
|
|
||||||
A Category C2 open/closed sensor with maxReportTime of 5 mins.
|
SmartSense Open Closed sensor with reporting interval of 5 mins.
|
||||||
Check-in interval is double the value of maxReportTime.
|
SmartThings platform will ping the device after `checkInterval` seconds of inactivity in last attempt to reach the device before marking it `OFFLINE`
|
||||||
This gives the device twice the amount of time to respond before it is marked as offline.
|
|
||||||
Check-in interval = 12 mins
|
* V1, TV, HubV2 AppEngine < 1.5.1 - __121min__ checkInterval
|
||||||
|
* HubV2 AppEngine 1.5.1 - __12min__ checkInterval
|
||||||
|
|
||||||
## Battery Specification
|
## Battery Specification
|
||||||
|
|
||||||
|
|||||||
@@ -260,9 +260,9 @@ def refresh() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
// Device-Watch allows 3 check-in misses from device (plus 1 min lag time)
|
// Device-Watch allows 2 check-in misses from device + ping (plus 1 min lag time)
|
||||||
// enrolls with default periodic reporting until newer 5 min interval is confirmed
|
// enrolls with default periodic reporting until newer 5 min interval is confirmed
|
||||||
sendEvent(name: "checkInterval", value: 3 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
||||||
|
|
||||||
log.debug "Configuring Reporting, IAS CIE, and Bindings."
|
log.debug "Configuring Reporting, IAS CIE, and Bindings."
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# SmartSense Temp/Humidity Sensor
|
# SmartSense Temp/Humidity Sensor
|
||||||
|
|
||||||
|
Local Execution on V2 Hubs
|
||||||
|
|
||||||
Works with:
|
Works with:
|
||||||
|
|
||||||
@@ -24,10 +24,11 @@ Works with:
|
|||||||
|
|
||||||
## Device Health
|
## Device Health
|
||||||
|
|
||||||
A Category C2 SmartSense Temp/Humidity Sensor with maxReportTime of 5 mins.
|
SmartSense Temp/Humidity Sensor with reporting interval of 5 mins.
|
||||||
Check-in interval is double the value of maxReportTime.
|
SmartThings platform will ping the device after `checkInterval` seconds of inactivity in last attempt to reach the device before marking it `OFFLINE`
|
||||||
This gives the device twice the amount of time to respond before it is marked as offline.
|
|
||||||
Check-in interval = 12 mins
|
* V1, TV, HubV2 AppEngine < 1.5.1 - __121min__ checkInterval
|
||||||
|
* HubV2 AppEngine 1.5.1 - __12min__ checkIntervalr 5 min interval is confirmed
|
||||||
|
|
||||||
## Battery Specification
|
## Battery Specification
|
||||||
|
|
||||||
|
|||||||
@@ -264,9 +264,9 @@ def refresh()
|
|||||||
}
|
}
|
||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
// Device-Watch allows 3 check-in misses from device (plus 1 min lag time)
|
// Device-Watch allows 2 check-in misses from device + ping (plus 1 min lag time)
|
||||||
// enrolls with default periodic reporting until newer 5 min interval is confirmed
|
// enrolls with default periodic reporting until newer 5 min interval is confirmed
|
||||||
sendEvent(name: "checkInterval", value: 3 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
||||||
|
|
||||||
log.debug "Configuring Reporting and Bindings."
|
log.debug "Configuring Reporting and Bindings."
|
||||||
def humidityConfigCmds = [
|
def humidityConfigCmds = [
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ metadata {
|
|||||||
definition (name: "Simulated Minimote", namespace: "smartthings/testing", author: "SmartThings") {
|
definition (name: "Simulated Minimote", namespace: "smartthings/testing", author: "SmartThings") {
|
||||||
capability "Actuator"
|
capability "Actuator"
|
||||||
capability "Button"
|
capability "Button"
|
||||||
|
capability "Holdable Button"
|
||||||
capability "Configuration"
|
capability "Configuration"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
|
|
||||||
@@ -125,3 +126,15 @@ private hold(button) {
|
|||||||
sendEvent(name: "button", value: "held", data: [buttonNumber: button], descriptionText: "$device.displayName button $button was held", isStateChange: true)
|
sendEvent(name: "button", value: "held", data: [buttonNumber: button], descriptionText: "$device.displayName button $button was held", isStateChange: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def installed() {
|
||||||
|
initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
def updated() {
|
||||||
|
initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
def initialize() {
|
||||||
|
sendEvent(name: "numberOfButtons", value: 4)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Tyco Door Window Sensor
|
# Tyco Door Window Sensor
|
||||||
|
|
||||||
|
Cloud Execution
|
||||||
|
|
||||||
Works with:
|
Works with:
|
||||||
|
|
||||||
@@ -23,10 +23,11 @@ Works with:
|
|||||||
|
|
||||||
## Device Health
|
## Device Health
|
||||||
|
|
||||||
Contact sensor with maxReportTime of 5 mins.
|
Tyco Door Window Sensor with reporting interval of 5 mins.
|
||||||
Check-in interval is double the value of maxReportTime for Zigbee device.
|
Check-in interval is double the value of maxReportTime for Zigbee device.
|
||||||
This gives the device twice the amount of time to respond before it is marked as offline.
|
This gives the device twice the amount of time to respond before it is marked as offline.
|
||||||
Check-in interval = 12 min
|
|
||||||
|
* __12min__ checkInterval
|
||||||
|
|
||||||
## Battery Specification
|
## Battery Specification
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ metadata {
|
|||||||
capability "Actuator"
|
capability "Actuator"
|
||||||
capability "Battery"
|
capability "Battery"
|
||||||
capability "Button"
|
capability "Button"
|
||||||
|
capability "Holdable Button"
|
||||||
capability "Configuration"
|
capability "Configuration"
|
||||||
capability "Refresh"
|
capability "Refresh"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# GE Plug-In/In-Wall Smart Dimmer (ZigBee)
|
# GE Plug-In/In-Wall Smart Dimmer (ZigBee)
|
||||||
|
|
||||||
|
Cloud Execution
|
||||||
|
|
||||||
Works with:
|
Works with:
|
||||||
|
|
||||||
@@ -26,11 +26,11 @@ Works with:
|
|||||||
|
|
||||||
## Device Health
|
## Device Health
|
||||||
|
|
||||||
A Zigbee dimmer with maxReportTime of 5 mins.
|
A Zigbee Power Dimmer with reporting interval of 5 mins.
|
||||||
Check-in interval is double the value of maxReportTime.
|
SmartThings platform will ping the device after `checkInterval` seconds of inactivity in last attempt to reach the device before marking it `OFFLINE`
|
||||||
This gives the device twice the amount of time to respond before it is marked as offline.
|
|
||||||
Enrolls with default periodic reporting until newer 5 min interval is confirmed
|
* __12min__ checkInterval
|
||||||
It then enrolls the device with updated checkInterval i.e. 12 mins
|
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
|
|||||||
@@ -114,8 +114,8 @@ def refresh() {
|
|||||||
def configure() {
|
def configure() {
|
||||||
log.debug "Configuring Reporting and Bindings."
|
log.debug "Configuring Reporting and Bindings."
|
||||||
|
|
||||||
// Device-Watch allows 3 check-in misses from device (plus 1 min lag time)
|
// Device-Watch allows 2 check-in misses from device + ping (plus 1 min lag time)
|
||||||
// enrolls with default periodic reporting until newer 5 min interval is confirmed
|
// enrolls with default periodic reporting until newer 5 min interval is confirmed
|
||||||
sendEvent(name: "checkInterval", value: 3 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
||||||
refresh()
|
refresh()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Zigbee Dimmer
|
# Zigbee Dimmer
|
||||||
|
|
||||||
|
Cloud Execution
|
||||||
|
|
||||||
Works with:
|
Works with:
|
||||||
|
|
||||||
@@ -24,11 +24,11 @@ Works with:
|
|||||||
|
|
||||||
## Device Health
|
## Device Health
|
||||||
|
|
||||||
A Zigbee dimmer with maxReportTime of 5 mins.
|
ZigBee Dimmer with reporting interval of 5 mins.
|
||||||
Check-in interval is double the value of maxReportTime.
|
SmartThings platform will ping the device after `checkInterval` seconds of inactivity in last attempt to reach the device before marking it `OFFLINE`
|
||||||
This gives the device twice the amount of time to respond before it is marked as offline.
|
|
||||||
Enrolls with default periodic reporting until newer 5 min interval is confirmed
|
* __12min__ checkInterval
|
||||||
It then enrolls the device with updated checkInterval i.e. 12 mins
|
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
|
|||||||
@@ -102,9 +102,9 @@ def refresh() {
|
|||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
log.debug "Configuring Reporting and Bindings."
|
log.debug "Configuring Reporting and Bindings."
|
||||||
// Device-Watch allows 3 check-in misses from device (plus 1 min lag time)
|
// Device-Watch allows 2 check-in misses from device + ping (plus 1 min lag time)
|
||||||
// enrolls with default periodic reporting until newer 5 min interval is confirmed
|
// 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: 2 * 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
|
// OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity
|
||||||
zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.onOffConfig(0, 300) + zigbee.levelConfig()
|
zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.onOffConfig(0, 300) + zigbee.levelConfig()
|
||||||
|
|||||||
@@ -1,168 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright 2015 SmartThings
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at:
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
|
||||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
|
|
||||||
* for the specific language governing permissions and limitations under the License.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
//@Deprecated - Moved to zll-rgbw-bulb
|
|
||||||
|
|
||||||
/* Philips Hue (via Zigbee)
|
|
||||||
|
|
||||||
Capabilities:
|
|
||||||
Actuator
|
|
||||||
Color Control
|
|
||||||
Configuration
|
|
||||||
Polling
|
|
||||||
Refresh
|
|
||||||
Sensor
|
|
||||||
Switch
|
|
||||||
Switch Level
|
|
||||||
|
|
||||||
Custom Commands:
|
|
||||||
setAdjustedColor
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
metadata {
|
|
||||||
definition (name: "Zigbee Hue Bulb", namespace: "smartthings", author: "SmartThings") {
|
|
||||||
capability "Switch Level"
|
|
||||||
capability "Actuator"
|
|
||||||
capability "Color Control"
|
|
||||||
capability "Switch"
|
|
||||||
capability "Configuration"
|
|
||||||
capability "Polling"
|
|
||||||
capability "Refresh"
|
|
||||||
capability "Sensor"
|
|
||||||
|
|
||||||
command "setAdjustedColor"
|
|
||||||
|
|
||||||
//fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000", outClusters: "0019"
|
|
||||||
}
|
|
||||||
|
|
||||||
// UI tile definitions
|
|
||||||
tiles(scale: 2) {
|
|
||||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
|
||||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
|
|
||||||
attributeState "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
|
||||||
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
|
|
||||||
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
|
||||||
}
|
|
||||||
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
|
||||||
attributeState "level", action:"switch level.setLevel"
|
|
||||||
}
|
|
||||||
tileAttribute ("device.color", key: "COLOR_CONTROL") {
|
|
||||||
attributeState "color", action:"color control.setColor"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
controlTile("colorTempSliderControl", "device.colorTemperature", "slider", width: 4, height: 2, inactiveLabel: false, range:"(2700..6500)") {
|
|
||||||
state "colorTemperature", action:"color temperature.setColorTemperature"
|
|
||||||
}
|
|
||||||
valueTile("colorTemp", "device.colorTemperature", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
|
||||||
state "colorTemperature", label: '${currentValue} K'
|
|
||||||
}
|
|
||||||
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
|
||||||
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
|
||||||
}
|
|
||||||
|
|
||||||
main(["switch"])
|
|
||||||
details(["switch", "colorTempSliderControl", "colorTemp", "refresh"])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Globals
|
|
||||||
private getATTRIBUTE_HUE() { 0x0000 }
|
|
||||||
private getATTRIBUTE_SATURATION() { 0x0001 }
|
|
||||||
private getHUE_COMMAND() { 0x00 }
|
|
||||||
private getSATURATION_COMMAND() { 0x03 }
|
|
||||||
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"
|
|
||||||
|
|
||||||
def finalResult = zigbee.getEvent(description)
|
|
||||||
if (finalResult) {
|
|
||||||
log.debug finalResult
|
|
||||||
sendEvent(finalResult)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
def zigbeeMap = zigbee.parseDescriptionAsMap(description)
|
|
||||||
log.trace "zigbeeMap : $zigbeeMap"
|
|
||||||
|
|
||||||
if (zigbeeMap?.clusterInt == COLOR_CONTROL_CLUSTER) {
|
|
||||||
if(zigbeeMap.attrInt == ATTRIBUTE_HUE){ //Hue Attribute
|
|
||||||
def hueValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 255 * 360)
|
|
||||||
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)
|
|
||||||
sendEvent(name: "saturation", value: saturationValue, displayed:false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log.info "DID NOT PARSE MESSAGE for description : $description"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def on() {
|
|
||||||
zigbee.on() + ["delay 1500"] + zigbee.onOffRefresh()
|
|
||||||
}
|
|
||||||
|
|
||||||
def off() {
|
|
||||||
zigbee.off() + ["delay 1500"] + zigbee.onOffRefresh()
|
|
||||||
}
|
|
||||||
|
|
||||||
def refresh() {
|
|
||||||
refreshAttributes() + configureAttributes()
|
|
||||||
}
|
|
||||||
|
|
||||||
def poll() {
|
|
||||||
refreshAttributes()
|
|
||||||
}
|
|
||||||
|
|
||||||
def configure() {
|
|
||||||
log.debug "Configuring Reporting and Bindings."
|
|
||||||
configureAttributes() + refreshAttributes()
|
|
||||||
}
|
|
||||||
|
|
||||||
def configureAttributes() {
|
|
||||||
zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.colorTemperatureConfig() + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE, 0x20, 1, 3600, 0x01) + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION, 0x20, 1, 3600, 0x01)
|
|
||||||
}
|
|
||||||
|
|
||||||
def refreshAttributes() {
|
|
||||||
zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh() + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
|
|
||||||
}
|
|
||||||
|
|
||||||
def setColorTemperature(value) {
|
|
||||||
zigbee.setColorTemperature(value) + ["delay 1500"] + zigbee.colorTemperatureRefresh()
|
|
||||||
}
|
|
||||||
|
|
||||||
def setLevel(value) {
|
|
||||||
zigbee.setLevel(value) + ["delay 1500"] + zigbee.levelRefresh() //adding refresh because of ZLL bulb not conforming to send-me-a-report
|
|
||||||
}
|
|
||||||
|
|
||||||
def setColor(value){
|
|
||||||
log.trace "setColor($value)"
|
|
||||||
zigbee.on() + setHue(value.hue) + ["delay 300"] + setSaturation(value.saturation) + ["delay 2000"] + refreshAttributes()
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# OSRAM LIGHTIFY LED RGBW Bulb
|
# OSRAM LIGHTIFY LED RGBW Bulb
|
||||||
|
|
||||||
|
Cloud Execution
|
||||||
|
|
||||||
Works with:
|
Works with:
|
||||||
|
|
||||||
@@ -27,11 +27,10 @@ Works with:
|
|||||||
|
|
||||||
## Device Health
|
## Device Health
|
||||||
|
|
||||||
A Category C6 OSRAM LIGHTIFY LED RGBW Bulb with maxReportTime of 5 mins.
|
OSRAM LIGHTIFY LED RGBW Bulb with reporting interval of 5 mins.
|
||||||
Check-in interval is double the value of maxReportTime.
|
SmartThings platform will ping the device after `checkInterval` seconds of inactivity in last attempt to reach the device before marking it `OFFLINE`
|
||||||
This gives the device twice the amount of time to respond before it is marked as offline.
|
|
||||||
Check-in interval = 12 mins
|
|
||||||
|
|
||||||
|
* __12min__ checkInterval
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
|
|||||||
@@ -143,9 +143,9 @@ def refresh() {
|
|||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
log.debug "Configuring Reporting and Bindings."
|
log.debug "Configuring Reporting and Bindings."
|
||||||
// Device-Watch allows 3 check-in misses from device (plus 1 min lag time)
|
// Device-Watch allows 2 check-in misses from device + ping (plus 1 min lag time)
|
||||||
// enrolls with default periodic reporting until newer 5 min interval is confirmed
|
// 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: 2 * 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
|
// OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity
|
||||||
refresh()
|
refresh()
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# ZigBee White Color Temperature Bulb
|
# ZigBee White Color Temperature Bulb
|
||||||
|
|
||||||
|
Cloud Execution
|
||||||
|
|
||||||
Works with:
|
Works with:
|
||||||
|
|
||||||
@@ -25,11 +25,10 @@ Works with:
|
|||||||
|
|
||||||
## Device Health
|
## Device Health
|
||||||
|
|
||||||
Zigbee Bulb with maxReportTime of 5 mins.
|
Zigbee Bulb with reporting interval of 5 mins.
|
||||||
Check-in interval is double the value of maxReportTime.
|
SmartThings platform will ping the device after `checkInterval` seconds of inactivity in last attempt to reach the device before marking it `OFFLINE`
|
||||||
This gives the device twice the amount of time to respond before it is marked as offline.
|
|
||||||
Enrolls with default periodic reporting until newer 5 min interval is confirmed
|
*__12min__ checkInterval
|
||||||
It then enrolls the device with updated checkInterval i.e. 12 mins
|
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
|
|||||||
@@ -33,10 +33,11 @@ metadata {
|
|||||||
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019"
|
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019"
|
||||||
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04", outClusters: "0019"
|
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04", outClusters: "0019"
|
||||||
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY BR Tunable White", deviceJoinName: "OSRAM LIGHTIFY LED Flood BR30 Tunable White"
|
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY BR Tunable White", deviceJoinName: "OSRAM LIGHTIFY LED Flood BR30 Tunable White"
|
||||||
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY RT Tunable White", deviceJoinName: "OSRAM LIGHTIFY RT5/6 Tunable White"
|
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY RT Tunable White", deviceJoinName: "OSRAM LIGHTIFY LED Recessed Kit RT 5/6 Tunable White"
|
||||||
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: "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: "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", 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", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "Z01-A19NAE26", deviceJoinName: "Sengled Element plus"
|
||||||
}
|
}
|
||||||
|
|
||||||
// UI tile definitions
|
// UI tile definitions
|
||||||
@@ -83,105 +84,24 @@ def parse(String description) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Map bindingTable = parseBindingTableResponse(description)
|
def cluster = zigbee.parse(description)
|
||||||
if (bindingTable) {
|
|
||||||
List<String> cmds = []
|
|
||||||
bindingTable.table_entries.inject(cmds) { acc, entry ->
|
|
||||||
// The binding entry is not for our hub and should be deleted
|
|
||||||
if (entry["dstAddr"] != zigbeeEui) {
|
|
||||||
acc.addAll(removeBinding(entry.clusterId, entry.srcAddr, entry.srcEndpoint, entry.dstAddr, entry.dstEndpoint))
|
|
||||||
}
|
|
||||||
acc
|
|
||||||
}
|
|
||||||
// There are more entries that we haven't examined yet
|
|
||||||
if (bindingTable.numTableEntries > bindingTable.startIndex + bindingTable.numEntriesReturned) {
|
|
||||||
def startPos
|
|
||||||
if (cmds) {
|
|
||||||
log.warn "Removing binding entries for other devices: $cmds"
|
|
||||||
// Since we are removing some entries, we should start in the same spot as we just read since values
|
|
||||||
// will fill in the newly vacated spots
|
|
||||||
startPos = bindingTable.startIndex
|
|
||||||
} else {
|
|
||||||
// Since we aren't removing anything we move forward to the next set of table entries
|
|
||||||
startPos = bindingTable.startIndex + bindingTable.numEntriesReturned
|
|
||||||
}
|
|
||||||
cmds.addAll(requestBindingTable(startPos))
|
|
||||||
}
|
|
||||||
sendHubCommand(cmds.collect { it ->
|
|
||||||
new physicalgraph.device.HubAction(it)
|
|
||||||
}, 2000)
|
|
||||||
} else {
|
|
||||||
def cluster = zigbee.parse(description)
|
|
||||||
|
|
||||||
if (cluster && cluster.clusterId == 0x0006 && cluster.command == 0x07) {
|
if (cluster && cluster.clusterId == 0x0006 && cluster.command == 0x07) {
|
||||||
if (cluster.data[0] == 0x00) {
|
if (cluster.data[0] == 0x00) {
|
||||||
log.debug "ON/OFF REPORTING CONFIG RESPONSE: " + cluster
|
log.debug "ON/OFF REPORTING CONFIG RESPONSE: " + cluster
|
||||||
sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
||||||
}
|
|
||||||
else {
|
|
||||||
log.warn "ON/OFF REPORTING CONFIG FAILED- error code:${cluster.data[0]}"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
log.warn "DID NOT PARSE MESSAGE for description : $description"
|
log.warn "ON/OFF REPORTING CONFIG FAILED- error code:${cluster.data[0]}"
|
||||||
log.debug "${cluster}"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
log.warn "DID NOT PARSE MESSAGE for description : $description"
|
||||||
|
log.debug "${cluster}"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def parseBindingTableResponse(description) {
|
|
||||||
Map descMap = zigbee.parseDescriptionAsMap(description)
|
|
||||||
if (descMap["clusterInt"] == 0x8033) {
|
|
||||||
def header_field_lengths = ["transactionSeqNo": 1, "status": 1, "numTableEntries": 1, "startIndex": 1, "numEntriesReturned": 1]
|
|
||||||
def field_values = [:]
|
|
||||||
def data = descMap["data"]
|
|
||||||
header_field_lengths.each { k, v ->
|
|
||||||
field_values[k] = Integer.parseInt(data.take(v).join(""), 16);
|
|
||||||
data = data.drop(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Map> table = []
|
|
||||||
if (field_values.numEntriesReturned) {
|
|
||||||
def table_entry_lengths = ["srcAddr": 8, "srcEndpoint": 1, "clusterId": 2, "dstAddrMode": 1]
|
|
||||||
for (def i : 0..(field_values.numEntriesReturned - 1)) {
|
|
||||||
def entryMap = [:]
|
|
||||||
table_entry_lengths.each { k, v ->
|
|
||||||
def val = data.take(v).reverse().join("")
|
|
||||||
entryMap[k] = val.length() < 8 ? Integer.parseInt(val, 16) : val
|
|
||||||
data = data.drop(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (entryMap.dstAddrMode) {
|
|
||||||
case 0x01:
|
|
||||||
entryMap["dstAddr"] = data.take(2).reverse().join("")
|
|
||||||
data = data.drop(2)
|
|
||||||
break
|
|
||||||
case 0x03:
|
|
||||||
entryMap["dstAddr"] = data.take(8).reverse().join("")
|
|
||||||
data = data.drop(8)
|
|
||||||
entryMap["dstEndpoint"] = Integer.parseInt(data.take(1).join(""), 16)
|
|
||||||
data = data.drop(1)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
table << entryMap
|
|
||||||
}
|
|
||||||
}
|
|
||||||
field_values["table_entries"] = table
|
|
||||||
return field_values
|
|
||||||
}
|
|
||||||
return [:]
|
|
||||||
}
|
|
||||||
|
|
||||||
def requestBindingTable(startPos=0) {
|
|
||||||
return ["zdo mgmt-bind 0x${zigbee.deviceNetworkId} $startPos"]
|
|
||||||
}
|
|
||||||
|
|
||||||
def removeBinding(cluster, srcAddr, srcEndpoint, destAddr, destEndpoint) {
|
|
||||||
return ["zdo unbind unicast 0x${zigbee.deviceNetworkId} {${srcAddr}} $srcEndpoint $cluster {${destAddr}} $destEndpoint"]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def off() {
|
def off() {
|
||||||
zigbee.off()
|
zigbee.off()
|
||||||
}
|
}
|
||||||
@@ -207,11 +127,12 @@ def refresh() {
|
|||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
log.debug "Configuring Reporting and Bindings."
|
log.debug "Configuring Reporting and Bindings."
|
||||||
// Device-Watch allows 3 check-in misses from device (plus 1 min lag time)
|
// Device-Watch allows 2 check-in misses from device + ping (plus 1 min lag time)
|
||||||
// enrolls with default periodic reporting until newer 5 min interval is confirmed
|
// 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: 2 * 10 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
||||||
|
|
||||||
refresh() + requestBindingTable(0) + ["delay 2000"]
|
// OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity
|
||||||
|
refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
def setColorTemperature(value) {
|
def setColorTemperature(value) {
|
||||||
|
|||||||
@@ -27,6 +27,10 @@ metadata {
|
|||||||
fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019"
|
fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019"
|
||||||
fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019"
|
fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019"
|
||||||
fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", "manufacturer":"OSRAM", "model":"Classic A60 RGBW", deviceJoinName: "OSRAM LIGHTIFY LED Classic A60 RGBW"
|
fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", "manufacturer":"OSRAM", "model":"Classic A60 RGBW", deviceJoinName: "OSRAM LIGHTIFY LED Classic A60 RGBW"
|
||||||
|
fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "PAR 16 50 RGBW - LIGHTIFY", deviceJoinName: "OSRAM LIGHTIFY RGBW PAR 16 50"
|
||||||
|
fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Flex RGBW", deviceJoinName: "OSRAM LIGHTIFY Flex RGBW"
|
||||||
|
fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Gardenpole RGBW-Lightify", deviceJoinName: "OSRAM LIGHTIFY Gardenpole RGBW"
|
||||||
|
fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY Outdoor Flex RGBW", deviceJoinName: "OSRAM LIGHTIFY Outdoor Flex RGBW"
|
||||||
}
|
}
|
||||||
|
|
||||||
// UI tile definitions
|
// UI tile definitions
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ metadata {
|
|||||||
|
|
||||||
fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000, 0B04, FC0F", outClusters: "0019", "manufacturer":"OSRAM", "model":"Classic A60 TW", deviceJoinName: "OSRAM LIGHTIFY LED Classic A60 Tunable White"
|
fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000, 0B04, FC0F", outClusters: "0019", "manufacturer":"OSRAM", "model":"Classic A60 TW", deviceJoinName: "OSRAM LIGHTIFY LED Classic A60 Tunable White"
|
||||||
fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000, FC0F", outClusters: "0019", "manufacturer":"OSRAM", "model":"PAR16 50 TW", deviceJoinName: "OSRAM LIGHTIFY LED PAR16 50 Tunable White"
|
fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000, FC0F", outClusters: "0019", "manufacturer":"OSRAM", "model":"PAR16 50 TW", deviceJoinName: "OSRAM LIGHTIFY LED PAR16 50 Tunable White"
|
||||||
|
fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Classic B40 TW - LIGHTIFY", deviceJoinName: "OSRAM LIGHTIFY Classic B40 Tunable White"
|
||||||
}
|
}
|
||||||
|
|
||||||
// UI tile definitions
|
// UI tile definitions
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Z-wave Dimmer
|
# Z-wave Dimmer Switch Generic
|
||||||
|
|
||||||
|
|
||||||
|
Cloud Execution
|
||||||
|
|
||||||
Works with:
|
Works with:
|
||||||
|
|
||||||
@@ -32,6 +32,8 @@ Not to mention after going OFFLINE when the device is plugged back in, it might
|
|||||||
the device to appear as ONLINE again. This is because if this listening device does not respond to two poll requests in a row,
|
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.
|
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
|
## Troubleshooting
|
||||||
|
|
||||||
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
|
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport
|
|||||||
def value = "when off"
|
def value = "when off"
|
||||||
if (cmd.configurationValue[0] == 1) {value = "when on"}
|
if (cmd.configurationValue[0] == 1) {value = "when on"}
|
||||||
if (cmd.configurationValue[0] == 2) {value = "never"}
|
if (cmd.configurationValue[0] == 2) {value = "never"}
|
||||||
[name: "indicatorStatus", value: value, display: false]
|
[name: "indicatorStatus", value: value, displayed: false]
|
||||||
}
|
}
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.hailv1.Hail cmd) {
|
def zwaveEvent(physicalgraph.zwave.commands.hailv1.Hail cmd) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Z-wave Switch
|
# Z-wave Switch
|
||||||
|
|
||||||
|
Cloud Execution
|
||||||
|
|
||||||
Works with:
|
Works with:
|
||||||
|
|
||||||
@@ -32,6 +32,8 @@ Not to mention after going OFFLINE when the device is plugged back in, it might
|
|||||||
the device to appear as ONLINE again. This is because if this listening device does not respond to two poll requests in a row,
|
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.
|
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
|
## Troubleshooting
|
||||||
|
|
||||||
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
|
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
# Z-Wave Switch
|
# Z-Wave Switch
|
||||||
|
|
||||||
|
Local Execution on V2 Hubs
|
||||||
|
|
||||||
Works with:
|
Works with:
|
||||||
|
|
||||||
@@ -34,6 +35,7 @@ Not to mention after going OFFLINE when the device is plugged back in, it might
|
|||||||
the device to appear as ONLINE again. This is because if this listening device does not respond to two poll requests in a row,
|
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.
|
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
|
## Troubleshooting
|
||||||
|
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport
|
|||||||
def value = "when off"
|
def value = "when off"
|
||||||
if (cmd.configurationValue[0] == 1) {value = "when on"}
|
if (cmd.configurationValue[0] == 1) {value = "when on"}
|
||||||
if (cmd.configurationValue[0] == 2) {value = "never"}
|
if (cmd.configurationValue[0] == 2) {value = "never"}
|
||||||
[name: "indicatorStatus", value: value, display: false]
|
[name: "indicatorStatus", value: value, displayed: false]
|
||||||
}
|
}
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.hailv1.Hail cmd) {
|
def zwaveEvent(physicalgraph.zwave.commands.hailv1.Hail cmd) {
|
||||||
@@ -174,17 +174,17 @@ def refresh() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void indicatorWhenOn() {
|
void indicatorWhenOn() {
|
||||||
sendEvent(name: "indicatorStatus", value: "when on", display: false)
|
sendEvent(name: "indicatorStatus", value: "when on", displayed: false)
|
||||||
sendHubCommand(new physicalgraph.device.HubAction(zwave.configurationV1.configurationSet(configurationValue: [1], parameterNumber: 3, size: 1).format()))
|
sendHubCommand(new physicalgraph.device.HubAction(zwave.configurationV1.configurationSet(configurationValue: [1], parameterNumber: 3, size: 1).format()))
|
||||||
}
|
}
|
||||||
|
|
||||||
void indicatorWhenOff() {
|
void indicatorWhenOff() {
|
||||||
sendEvent(name: "indicatorStatus", value: "when off", display: false)
|
sendEvent(name: "indicatorStatus", value: "when off", displayed: false)
|
||||||
sendHubCommand(new physicalgraph.device.HubAction(zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 3, size: 1).format()))
|
sendHubCommand(new physicalgraph.device.HubAction(zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 3, size: 1).format()))
|
||||||
}
|
}
|
||||||
|
|
||||||
void indicatorNever() {
|
void indicatorNever() {
|
||||||
sendEvent(name: "indicatorStatus", value: "never", display: false)
|
sendEvent(name: "indicatorStatus", value: "never", displayed: false)
|
||||||
sendHubCommand(new physicalgraph.device.HubAction(zwave.configurationV1.configurationSet(configurationValue: [2], parameterNumber: 3, size: 1).format()))
|
sendHubCommand(new physicalgraph.device.HubAction(zwave.configurationV1.configurationSet(configurationValue: [2], parameterNumber: 3, size: 1).format()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,9 +19,9 @@
|
|||||||
author: "SmartThings",
|
author: "SmartThings",
|
||||||
description: "Control your Bose SoundTouch speakers",
|
description: "Control your Bose SoundTouch speakers",
|
||||||
category: "SmartThings Labs",
|
category: "SmartThings Labs",
|
||||||
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
|
iconUrl: "https://d3azp77rte0gip.cloudfront.net/smartapps/fcf1d93a-ba0b-4324-b96f-e5b5487dfaf5/images/BoseST_icon.png",
|
||||||
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
|
iconX2Url: "https://d3azp77rte0gip.cloudfront.net/smartapps/fcf1d93a-ba0b-4324-b96f-e5b5487dfaf5/images/BoseST_icon@2x.png",
|
||||||
iconX3Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
|
iconX3Url: "https://d3azp77rte0gip.cloudfront.net/smartapps/fcf1d93a-ba0b-4324-b96f-e5b5487dfaf5/images/BoseST_icon@2x-1.png",
|
||||||
singleInstance: true
|
singleInstance: true
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -104,7 +104,7 @@ def deviceDiscovery()
|
|||||||
|
|
||||||
return dynamicPage(name:"deviceDiscovery", title:"Discovery Started!", nextPage:"", refreshInterval:refreshInterval, install:true, uninstall: true) {
|
return dynamicPage(name:"deviceDiscovery", title:"Discovery Started!", nextPage:"", refreshInterval:refreshInterval, install:true, uninstall: true) {
|
||||||
section("Please wait while we discover your ${getDeviceName()}. Discovery can take five minutes or more, so sit back and relax! Select your device below once discovered.") {
|
section("Please wait while we discover your ${getDeviceName()}. Discovery can take five minutes or more, so sit back and relax! Select your device below once discovered.") {
|
||||||
input "selecteddevice", "enum", required:false, title:"Select ${getDeviceName()} (${numFound} found)", multiple:true, options:devices
|
input "selecteddevice", "enum", required:false, title:"Select ${getDeviceName()} (${numFound} found)", multiple:true, options:devices, submitOnChange: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,6 +196,8 @@ def addDevice(){
|
|||||||
d = addChildDevice(getNameSpace(), getDeviceName(), dni, newDevice?.value.hub, [label:"${deviceName}"])
|
d = addChildDevice(getNameSpace(), getDeviceName(), dni, newDevice?.value.hub, [label:"${deviceName}"])
|
||||||
d.boseSetDeviceID(newDevice.value.deviceID)
|
d.boseSetDeviceID(newDevice.value.deviceID)
|
||||||
log.trace "Created ${d.displayName} with id $dni"
|
log.trace "Created ${d.displayName} with id $dni"
|
||||||
|
// sync DTH with device, done here as it currently don't work from the DTH's installed() method
|
||||||
|
d.refresh()
|
||||||
} else {
|
} else {
|
||||||
log.trace "${d.displayName} with id $dni already exists"
|
log.trace "${d.displayName} with id $dni already exists"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -516,7 +516,7 @@ def pollResponse(response, data) {
|
|||||||
def hub = getChildDevice("harmony-${it.key}")
|
def hub = getChildDevice("harmony-${it.key}")
|
||||||
if (hub) {
|
if (hub) {
|
||||||
if (it.value.response.data.currentAvActivity == "-1") {
|
if (it.value.response.data.currentAvActivity == "-1") {
|
||||||
hub.sendEvent(name: "currentActivity", value: "--", descriptionText: "There isn't any activity running", display: false)
|
hub.sendEvent(name: "currentActivity", value: "--", descriptionText: "There isn't any activity running", displayed: false)
|
||||||
} else {
|
} else {
|
||||||
def currentActivity
|
def currentActivity
|
||||||
def activityDTH = getChildDevice("harmony-${it.key}-${it.value.response.data.currentAvActivity}")
|
def activityDTH = getChildDevice("harmony-${it.key}-${it.value.response.data.currentAvActivity}")
|
||||||
@@ -524,7 +524,7 @@ def pollResponse(response, data) {
|
|||||||
currentActivity = activityDTH.device.displayName
|
currentActivity = activityDTH.device.displayName
|
||||||
else
|
else
|
||||||
currentActivity = getActivityName(it.value.response.data.currentAvActivity,it.key)
|
currentActivity = getActivityName(it.value.response.data.currentAvActivity,it.key)
|
||||||
hub.sendEvent(name: "currentActivity", value: currentActivity, descriptionText: "Current activity is ${currentActivity}", display: false)
|
hub.sendEvent(name: "currentActivity", value: currentActivity, descriptionText: "Current activity is ${currentActivity}", displayed: false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -576,7 +576,7 @@ def getActivityList() {
|
|||||||
}
|
}
|
||||||
activities += [id: "off", name: "Activity OFF", type: "0"]
|
activities += [id: "off", name: "Activity OFF", type: "0"]
|
||||||
}
|
}
|
||||||
hub.sendEvent(name: "activities", value: new groovy.json.JsonBuilder(activities).toString(), descriptionText: "Activities are ${activities.collect { it.name }?.join(', ')}", display: false)
|
hub.sendEvent(name: "activities", value: new groovy.json.JsonBuilder(activities).toString(), descriptionText: "Activities are ${activities.collect { it.name }?.join(', ')}", displayed: false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user