Compare commits

..

1 Commits

Author SHA1 Message Date
Amol Mundayoor
e1673099f1 MSA-1252: Adding simulator tags to allow Zw Multichannel capability be simulated. 2016-05-04 13:38:38 -05:00
158 changed files with 2594 additions and 6553 deletions

View File

@@ -19,7 +19,7 @@ buildscript {
username smartThingsArtifactoryUserName
password smartThingsArtifactoryPassword
}
url "https://artifactory.smartthings.com/libs-release-local"
url "http://artifactory.smartthings.com/libs-release-local"
}
}
}
@@ -27,37 +27,9 @@ buildscript {
repositories {
mavenLocal()
jcenter()
maven {
credentials {
username smartThingsArtifactoryUserName
password smartThingsArtifactoryPassword
}
url "https://artifactory.smartthings.com/libs-release-local"
}
}
sourceSets {
devicetypes {
groovy {
srcDirs = ['devicetypes']
}
}
smartapps {
groovy {
srcDirs = ['smartapps']
}
}
}
dependencies {
devicetypesCompile 'org.codehaus.groovy:groovy-all:2.4.7'
devicetypesCompile 'smartthings:appengine-z-wave:0.1.2'
devicetypesCompile 'smartthings:appengine-zigbee:0.1.11'
smartappsCompile 'org.codehaus.groovy:groovy-all:2.4.7'
smartappsCompile 'smartthings:appengine-common:0.1.8'
smartappsCompile 'org.codehaus.groovy.modules.http-builder:http-builder:0.7.1'
smartappsCompile 'org.grails:grails-web:2.3.11'
smartappsCompile 'org.json:json:20140107'
}
slackSendMessage {

View File

@@ -5,9 +5,7 @@ machine:
dependencies:
override:
- ./gradlew dependencies -PsmartThingsArtifactoryUserName="$ARTIFACTORY_USERNAME" -PsmartThingsArtifactoryPassword="$ARTIFACTORY_PASSWORD"
post:
- ./gradlew compileSmartappsGroovy compileDevicetypesGroovy -PsmartThingsArtifactoryUserName="$ARTIFACTORY_USERNAME" -PsmartThingsArtifactoryPassword="$ARTIFACTORY_PASSWORD"
- echo "Nothing to do."
test:
override:

View File

@@ -0,0 +1,47 @@
/**
* Zw Multichannel
*
* Copyright 2016 SmartThings
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*
*/
metadata {
definition (name: "Zw Multichannel", namespace: "capabilities", author: "SmartThings") {
capability "Zw Multichannel"
}
simulator {
status "ZWEvent":""
status "ZWInfo":""
}
tiles {
valueTile("zwEvent", "device.epEvent", label:"${name}", width:2, height:2) {}
valueTile("zwInfo", "device.epInfo", label:"${name}", width:2, height:2) {}
main("zwEvent")
details(["zwEvent","zwInfo"])
}
}
// parse events into attributes
def parse(String description) {
def pair = description.split(":")
createEvent(name: pair[0].trim(), value: pair[1].trim())
}
// handle commands
def enableEpEvents(data) {
'[enableEpEvents]${data}'
}
def epCmd(num, str) {
'[epCmd]${num}:${str}'
}

View File

@@ -15,7 +15,6 @@
*/
metadata {
definition (name: "Netatmo Additional Module", namespace: "dianoga", author: "Brian Steere") {
capability "Sensor"
capability "Relative Humidity Measurement"
capability "Temperature Measurement"

View File

@@ -15,7 +15,6 @@
*/
metadata {
definition (name: "Netatmo Basestation", namespace: "dianoga", author: "Brian Steere") {
capability "Sensor"
capability "Relative Humidity Measurement"
capability "Temperature Measurement"

View File

@@ -15,7 +15,6 @@
*/
metadata {
definition (name: "Netatmo Outdoor Module", namespace: "dianoga", author: "Brian Steere") {
capability "Sensor"
capability "Relative Humidity Measurement"
capability "Temperature Measurement"
}

View File

@@ -15,8 +15,6 @@
*/
metadata {
definition (name: "Netatmo Rain", namespace: "dianoga", author: "Brian Steere") {
capability "Sensor"
attribute "rain", "number"
attribute "rainSumHour", "number"
attribute "rainSumDay", "number"

View File

@@ -33,8 +33,8 @@ metadata {
tiles(scale: 2) {
multiAttributeTile(name:"FGMS", type:"lighting", width:6, height:4) {//with generic type secondary control text is not displayed in Android app
tileAttribute("device.motion", key:"PRIMARY_CONTROL") {
attributeState("inactive", label:"no motion", icon:"st.motion.motion.inactive", backgroundColor:"#79b821")
attributeState("active", label:"motion", icon:"st.motion.motion.active", backgroundColor:"#ffa81e")
attributeState("inactive", icon:"st.motion.motion.inactive", backgroundColor:"#79b821")
attributeState("active", icon:"st.motion.motion.active", backgroundColor:"#ffa81e")
}
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
@@ -278,4 +278,4 @@ private encap(physicalgraph.zwave.Command cmd) {
} else {
crc16(cmd)
}
}
}

View File

@@ -274,7 +274,6 @@ private Map makeTemperatureResult(value) {
name: 'temperature',
value: "" + value,
descriptionText: "${linkText} is ${value}°${temperatureScale}",
unit: temperatureScale
]
}

View File

@@ -254,8 +254,7 @@ private Map getTemperatureResult(value) {
return [
name: 'temperature',
value: value,
descriptionText: descriptionText,
unit: temperatureScale
descriptionText: descriptionText
]
}

View File

@@ -28,7 +28,6 @@ metadata {
attribute "powerSupply", "enum", ["USB Cable", "Battery"]
fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x7A", outClusters: "0x5A"
fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x7A,0x5A"
}
simulator {
@@ -353,7 +352,7 @@ def configure() {
motionSensitivity == "minimum" ? 0 : 64)
//5. report every x minutes (threshold reports don't work on battery power, default 8 mins)
request << zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: timeOptionValueMap[reportInterval] ?: (8*60)) //association group 1
request << zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: timeOptionValueMap[reportInterval] ?: 8*60) //association group 1
request << zwave.configurationV1.configurationSet(parameterNumber: 112, size: 4, scaledConfigurationValue: 6*60*60) //association group 2

View File

@@ -21,8 +21,6 @@ metadata {
capability "Sensor"
capability "Battery"
command "configureAfterSecure"
fingerprint deviceId: "0x0701", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x98,0x7A", outClusters:"0x5A"
}

View File

@@ -12,6 +12,16 @@
*
*/
/*
* Purpose: Arrival Sensor HA DTH File
*
* Filename: Arrival-Sensor-HA.src/Arrival-Sensor-HA.groovy
*
* Change History:
* 1. 20160115 TW - Update/Edit to support i18n translations
* 2. 20160121 TW - Update to V4 battery calcs, added pref's page title translations
*/
metadata {
definition (name: "Arrival Sensor HA", namespace: "smartthings", author: "SmartThings") {
capability "Tone"

View File

@@ -1,3 +1,4 @@
#==============================================================================
# Copyright 2016 SmartThings
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
@@ -11,6 +12,15 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#==============================================================================
# Purpose: Arrival Sensor HA i18n Translation File
#
# Filename: Arrival-Sensor-HA.src/i18n/messages.properties
#
# Change History:
# 1. 20160115 TW Initial release with informal Korean translation.
# 2. 20160121 TW Added def preference section titles.
#==============================================================================
# Korean (ko)
# Device Preferences
'''Give your device a name'''.ko=기기 이름 설정

View File

@@ -87,27 +87,16 @@ def beep() {
up to this long from the time you send the message to the time you hear a sound.
*/
// Used source endpoint of 0x02 because we are using smartthings manufacturer specific cluster.
[
"raw 0xFC05 {15 0A 11 00 00 15 01}",
"delay 200",
"send 0x$zigbee.deviceNetworkId 0x02 0x$zigbee.endpointId",
"delay 7000",
"raw 0xFC05 {15 0A 11 00 00 15 01}",
"delay 200",
"send 0x$zigbee.deviceNetworkId 0x02 0x$zigbee.endpointId",
"delay 7000",
"raw 0xFC05 {15 0A 11 00 00 15 01}",
"delay 200",
"send 0x$zigbee.deviceNetworkId 0x02 0x$zigbee.endpointId",
"delay 7000",
"raw 0xFC05 {15 0A 11 00 00 15 01}",
"delay 200",
"send 0x$zigbee.deviceNetworkId 0x02 0x$zigbee.endpointId",
"delay 7000",
"raw 0xFC05 {15 0A 11 00 00 15 01}",
"delay 200",
"send 0x$zigbee.deviceNetworkId 0x02 0x$zigbee.endpointId",
"raw 0xFC05 {15 0A 11 00 00 15 01}"
]
}

View File

@@ -47,9 +47,6 @@ metadata {
command "everywhereJoin"
command "everywhereLeave"
command "forceOff"
command "forceOn"
}
/**
@@ -67,10 +64,8 @@ metadata {
}
standardTile("switch", "device.switch", width: 1, height: 1, canChangeIcon: true) {
state "on", label: '${name}', action: "forceOff", icon: "st.Electronics.electronics16", backgroundColor: "#79b821", nextState:"turningOff"
state "turningOff", label:'TURNING OFF', icon:"st.Electronics.electronics16", backgroundColor:"#ffffff"
state "off", label: '${name}', action: "forceOn", icon: "st.Electronics.electronics16", backgroundColor: "#ffffff", nextState:"turningOn"
state "turningOn", label:'TURNING ON', icon:"st.Electronics.electronics16", backgroundColor:"#79b821"
state "off", label: '${name}', action: "switch.on", icon: "st.Electronics.electronics16", backgroundColor: "#ffffff"
state "on", label: '${name}', action: "switch.off", icon: "st.Electronics.electronics16", backgroundColor: "#79b821"
}
valueTile("1", "device.station1", decoration: "flat", canChangeIcon: false) {
state "station1", label:'${currentValue}', action:"preset1"
@@ -143,22 +138,8 @@ metadata {
* one place.
*
*/
def off() {
if (device.currentState("switch")?.value == "on") {
onAction("off")
}
}
def forceOff() {
onAction("off")
}
def on() {
if (device.currentState("switch")?.value == "off") {
onAction("on")
}
}
def forceOn() {
onAction("on")
}
def off() { onAction("off") }
def on() { onAction("on") }
def volup() { onAction("volup") }
def voldown() { onAction("voldown") }
def preset1() { onAction("1") }
@@ -257,11 +238,11 @@ def onAction(String user, data=null) {
def actions = null
switch (user) {
case "on":
boseSetPowerState(true)
actions = boseSetPowerState(true)
break
case "off":
boseSetNowPlaying(null, "STANDBY")
boseSetPowerState(false)
actions = boseSetPowerState(false)
break
case "volume":
actions = boseSetVolume(data)
@@ -766,16 +747,8 @@ def cb_boseSetInput(xml, input) {
*/
def boseSetPowerState(boolean enable) {
log.info "boseSetPowerState(${enable})"
// Fix to get faster update of power status back from speaker after sending on/off
// Instead of queuing the command to be sent after the refresh send it directly via sendHubCommand
// Note: This is a temporary hack that should be replaced by a re-design of the
// DTH to use sendHubCommand for all commands
sendHubCommand(bosePOST("/key", "<key state=\"press\" sender=\"Gabbo\">POWER</key>"))
sendHubCommand(bosePOST("/key", "<key state=\"release\" sender=\"Gabbo\">POWER</key>"))
sendHubCommand(boseGET("/now_playing"))
if (enable) {
queueCallback('nowPlaying', "cb_boseConfirmPowerOn", 5)
}
queueCallback('nowPlaying', "cb_boseSetPowerState", enable ? "POWERON" : "POWEROFF")
return boseRefreshNowPlaying()
}
/**
@@ -814,11 +787,10 @@ def cb_boseSetPowerState(xml, state) {
*/
def cb_boseConfirmPowerOn(xml, tries) {
def result = []
def attempt = tries as Integer
log.warn "boseConfirmPowerOn() attempt #$attempt"
if (xml.attributes()['source'] == "STANDBY" && attempt > 0) {
log.warn "boseConfirmPowerOn() attempt #" + tries
if (xml.attributes()['source'] == "STANDBY" && tries > 0) {
result << boseRefreshNowPlaying()
queueCallback('nowPlaying', "cb_boseConfirmPowerOn", attempt-1)
queueCallback('nowPlaying', "cb_boseConfirmPowerOn", tries-1)
}
return result
}

View File

@@ -105,21 +105,11 @@ def parseDescriptionAsMap(description) {
// Commands to device
def on() {
[
'zcl on-off on',
'delay 200',
"send 0x${zigbee.deviceNetworkId} 0x01 0x${zigbee.endpointId}",
'delay 500'
]
'zcl on-off on'
}
def off() {
[
'zcl on-off off',
'delay 200',
"send 0x${zigbee.deviceNetworkId} 0x01 0x${zigbee.endpointId}",
'delay 500'
]
'zcl on-off off'
}
def setLevel(value) {

View File

@@ -89,17 +89,14 @@ def parse(String description) {
log.debug "TEMP"
map.name = "temperature"
map.value = getTemperature(descMap.value)
map.unit = temperatureScale
} else if (descMap.cluster == "0201" && descMap.attrId == "0011") {
log.debug "COOLING SETPOINT"
map.name = "coolingSetpoint"
map.value = getTemperature(descMap.value)
map.unit = temperatureScale
} else if (descMap.cluster == "0201" && descMap.attrId == "0012") {
log.debug "HEATING SETPOINT"
map.name = "heatingSetpoint"
map.value = getTemperature(descMap.value)
map.unit = temperatureScale
} else if (descMap.cluster == "0201" && descMap.attrId == "001c") {
log.debug "MODE"
map.name = "thermostatMode"
@@ -172,7 +169,7 @@ def setHeatingSetpoint(degrees) {
def degreesInteger = Math.round(degrees)
log.debug "setHeatingSetpoint({$degreesInteger} ${temperatureScale})"
sendEvent("name": "heatingSetpoint", "value": degreesInteger, "unit": temperatureScale)
sendEvent("name": "heatingSetpoint", "value": degreesInteger)
def celsius = (getTemperatureScale() == "C") ? degreesInteger : (fahrenheitToCelsius(degreesInteger) as Double).round(2)
"st wattr 0x${device.deviceNetworkId} 1 0x201 0x12 0x29 {" + hex(celsius * 100) + "}"
@@ -183,7 +180,7 @@ def setCoolingSetpoint(degrees) {
if (degrees != null) {
def degreesInteger = Math.round(degrees)
log.debug "setCoolingSetpoint({$degreesInteger} ${temperatureScale})"
sendEvent("name": "coolingSetpoint", "value": degreesInteger, "unit": temperatureScale)
sendEvent("name": "coolingSetpoint", "value": degreesInteger)
def celsius = (getTemperatureScale() == "C") ? degreesInteger : (fahrenheitToCelsius(degreesInteger) as Double).round(2)
"st wattr 0x${device.deviceNetworkId} 1 0x201 0x11 0x29 {" + hex(celsius * 100) + "}"
}

View File

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

View File

@@ -1,34 +0,0 @@
# Connected Cree LED Bulb
Works with:
* [Connected Cree LED Bulb](https://support.smartthings.com/hc/en-us/articles/204258280-Cree-Connected-LED-Bulb)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
## Capabilities
* **Actuator** - represents that a Device has commands
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
* **Polling** - represents that poll() can be implemented for the device
* **Refresh** - _refresh()_ command for status updates
* **Switch** - can detect state (possible values: on/off)
* **Switch Level** - represents current light level, usually 0-100 in percent
* **Health Check** - indicates ability to get device health notifications
## Device Health
A Category C6 Connected Cree LED Bulb with maxReportTime of 5 mins.
Check-in interval = 12 mins
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
Pairing needs to be tried again by placing the device closer to the hub.
Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link:
* [Cree Connected LED Bulb Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/204258280-Cree-Connected-LED-Bulb)

View File

@@ -14,17 +14,18 @@
*
*/
//@Deprecated: Moved to ZLL Dimmer Bulb
metadata {
definition (name: "Cree Bulb", namespace: "smartthings", author: "SmartThings") {
capability "Actuator"
capability "Configuration"
capability "Polling"
capability "Refresh"
capability "Switch"
capability "Switch Level"
capability "Health Check"
fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,1000", outClusters: "0000,0019"
//fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,1000", outClusters: "0000,0019"
}
// simulator metadata
@@ -85,28 +86,15 @@ def setLevel(value) {
zigbee.setLevel(value) + ["delay 500"] + zigbee.levelRefresh() //adding refresh because of ZLL bulb not conforming to send-me-a-report
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
return zigbee.levelRefresh()
}
def refresh() {
zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.onOffConfig() + zigbee.levelConfig()
}
def healthPoll() {
def cmds = zigbee.onOffRefresh() + zigbee.levelRefresh()
cmds.each{ sendHubCommand(new physicalgraph.device.HubAction(it))}
def poll() {
zigbee.onOffRefresh() + zigbee.levelRefresh()
}
def configure() {
unschedule()
schedule("0 0/5 * * * ? *", "healthPoll")
log.debug "Configuring Reporting and Bindings."
// Device-Watch allows 2 check-in misses from device
sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
// minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity
zigbee.onOffConfig(0, 300) + zigbee.levelConfig() + zigbee.onOffRefresh() + zigbee.levelRefresh()
zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.onOffRefresh() + zigbee.levelRefresh()
}

View File

@@ -21,9 +21,7 @@ metadata {
capability "Refresh"
capability "Sensor"
fingerprint mfr:"0063", prod:"4457", deviceJoinName: "Z-Wave Wall Dimmer"
fingerprint mfr:"0063", prod:"4944", deviceJoinName: "Z-Wave Wall Dimmer"
fingerprint mfr:"0063", prod:"5044", deviceJoinName: "Z-Wave Plug-In Dimmer"
fingerprint inClusters: "0x26"
}
simulator {
@@ -44,10 +42,6 @@ metadata {
reply "200163,delay 5000,2602": "command: 2603, payload: 63"
}
preferences {
input "ledIndicator", "enum", title: "LED Indicator", description: "Turn LED indicator... ", required: false, options:["on": "When On", "off": "When Off", "never": "Never"], defaultValue: "off"
}
tiles(scale: 2) {
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
@@ -76,28 +70,11 @@ metadata {
}
main(["switch"])
details(["switch", "level", "refresh"])
details(["switch", "level", "indicator", "refresh"])
}
}
def updated(){
switch (ledIndicator) {
case "on":
indicatorWhenOn()
break
case "off":
indicatorWhenOff()
break
case "never":
indicatorNever()
break
default:
indicatorWhenOn()
break
}
}
def parse(String description) {
def result = null
if (description != "updated") {
@@ -161,7 +138,6 @@ def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerS
log.debug "productTypeId: ${cmd.productTypeId}"
def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)
updateDataValue("MSR", msr)
updateDataValue("manufacturer", cmd.manufacturerName)
createEvent([descriptionText: "$device.displayName MSR: $msr", isStateChange: false])
}
@@ -225,19 +201,19 @@ def refresh() {
delayBetween(commands,100)
}
void indicatorWhenOn() {
sendEvent(name: "indicatorStatus", value: "when on", display: false)
sendHubCommand(new physicalgraph.device.HubAction(zwave.configurationV1.configurationSet(configurationValue: [1], parameterNumber: 3, size: 1).format()))
def indicatorWhenOn() {
sendEvent(name: "indicatorStatus", value: "when on")
zwave.configurationV1.configurationSet(configurationValue: [1], parameterNumber: 3, size: 1).format()
}
void indicatorWhenOff() {
sendEvent(name: "indicatorStatus", value: "when off", display: false)
sendHubCommand(new physicalgraph.device.HubAction(zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 3, size: 1).format()))
def indicatorWhenOff() {
sendEvent(name: "indicatorStatus", value: "when off")
zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 3, size: 1).format()
}
void indicatorNever() {
sendEvent(name: "indicatorStatus", value: "never", display: false)
sendHubCommand(new physicalgraph.device.HubAction(zwave.configurationV1.configurationSet(configurationValue: [2], parameterNumber: 3, size: 1).format()))
def indicatorNever() {
sendEvent(name: "indicatorStatus", value: "never")
zwave.configurationV1.configurationSet(configurationValue: [2], parameterNumber: 3, size: 1).format()
}
def invertSwitch(invert=true) {
@@ -247,4 +223,4 @@ def invertSwitch(invert=true) {
else {
zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 4, size: 1).format()
}
}
}

View File

@@ -152,11 +152,11 @@ def generateEvent(Map results) {
sendValue = location.temperatureScale == "C"? roundC(sendValue) : sendValue
isChange = isTemperatureStateChange(device, name, value.toString())
isDisplayed = isChange
event << [value: sendValue, unit: temperatureScale, isStateChange: isChange, displayed: isDisplayed]
event << [value: sendValue, isStateChange: isChange, displayed: isDisplayed]
} else if (name=="maxCoolingSetpoint" || name=="minCoolingSetpoint" || name=="maxHeatingSetpoint" || name=="minHeatingSetpoint") {
def sendValue = convertTemperatureIfNeeded(value.toDouble(), "F", 1) //API return temperature value in F
sendValue = location.temperatureScale == "C"? roundC(sendValue) : sendValue
event << [value: sendValue, unit: temperatureScale, displayed: false]
event << [value: sendValue, displayed: false]
} else if (name=="heatMode" || name=="coolMode" || name=="autoMode" || name=="auxHeatMode"){
isChange = isStateChange(device, name, value.toString())
event << [value: value.toString(), isStateChange: isChange, displayed: false]
@@ -234,9 +234,9 @@ void setHeatingSetpoint(setpoint) {
def heatingValue = location.temperatureScale == "C"? convertCtoF(heatingSetpoint) : heatingSetpoint
def sendHoldType = holdType ? (holdType=="Temporary")? "nextTransition" : (holdType=="Permanent")? "indefinite" : "indefinite" : "indefinite"
if (parent.setHold(heatingValue, coolingValue, deviceId, sendHoldType)) {
sendEvent("name":"heatingSetpoint", "value":heatingSetpoint, "unit":location.temperatureScale)
sendEvent("name":"coolingSetpoint", "value":coolingSetpoint, "unit":location.temperatureScale)
if (parent.setHold(this, heatingValue, coolingValue, deviceId, sendHoldType)) {
sendEvent("name":"heatingSetpoint", "value":heatingSetpoint)
sendEvent("name":"coolingSetpoint", "value":coolingSetpoint)
log.debug "Done setHeatingSetpoint> coolingSetpoint: ${coolingSetpoint}, heatingSetpoint: ${heatingSetpoint}"
generateSetpointEvent()
generateStatusEvent()
@@ -271,9 +271,9 @@ void setCoolingSetpoint(setpoint) {
def heatingValue = location.temperatureScale == "C"? convertCtoF(heatingSetpoint) : heatingSetpoint
def sendHoldType = holdType ? (holdType=="Temporary")? "nextTransition" : (holdType=="Permanent")? "indefinite" : "indefinite" : "indefinite"
if (parent.setHold(heatingValue, coolingValue, deviceId, sendHoldType)) {
sendEvent("name":"heatingSetpoint", "value":heatingSetpoint, "unit":location.temperatureScale)
sendEvent("name":"coolingSetpoint", "value":coolingSetpoint, "unit":location.temperatureScale)
if (parent.setHold(this, heatingValue, coolingValue, deviceId, sendHoldType)) {
sendEvent("name":"heatingSetpoint", "value":heatingSetpoint)
sendEvent("name":"coolingSetpoint", "value":coolingSetpoint)
log.debug "Done setCoolingSetpoint>> coolingSetpoint = ${coolingSetpoint}, heatingSetpoint = ${heatingSetpoint}"
generateSetpointEvent()
generateStatusEvent()
@@ -287,14 +287,14 @@ void resumeProgram() {
log.debug "resumeProgram() is called"
sendEvent("name":"thermostatStatus", "value":"resuming schedule", "description":statusText, displayed: false)
def deviceId = device.deviceNetworkId.split(/\./).last()
if (parent.resumeProgram(deviceId)) {
if (parent.resumeProgram(this, deviceId)) {
sendEvent("name":"thermostatStatus", "value":"setpoint is updating", "description":statusText, displayed: false)
runIn(5, "poll")
log.debug "resumeProgram() is done"
sendEvent("name":"resumeProgram", "value":"resume", descriptionText: "resumeProgram is done", displayed: false, isStateChange: true)
} else {
sendEvent("name":"thermostatStatus", "value":"failed resume click refresh", "description":statusText, displayed: false)
log.error "Error resumeProgram() check parent.resumeProgram(deviceId)"
log.error "Error resumeProgram() check parent.resumeProgram(this, deviceId)"
}
}
@@ -406,7 +406,7 @@ def generateOperatingStateEvent(operatingState) {
def off() {
log.debug "off"
def deviceId = device.deviceNetworkId.split(/\./).last()
if (parent.setMode ("off", deviceId))
if (parent.setMode (this,"off", deviceId))
generateModeEvent("off")
else {
log.debug "Error setting new mode."
@@ -420,7 +420,7 @@ def off() {
def heat() {
log.debug "heat"
def deviceId = device.deviceNetworkId.split(/\./).last()
if (parent.setMode ("heat", deviceId))
if (parent.setMode (this,"heat", deviceId))
generateModeEvent("heat")
else {
log.debug "Error setting new mode."
@@ -438,7 +438,7 @@ def emergencyHeat() {
def auxHeatOnly() {
log.debug "auxHeatOnly"
def deviceId = device.deviceNetworkId.split(/\./).last()
if (parent.setMode ("auxHeatOnly", deviceId))
if (parent.setMode (this,"auxHeatOnly", deviceId))
generateModeEvent("auxHeatOnly")
else {
log.debug "Error setting new mode."
@@ -452,7 +452,7 @@ def auxHeatOnly() {
def cool() {
log.debug "cool"
def deviceId = device.deviceNetworkId.split(/\./).last()
if (parent.setMode ("cool", deviceId))
if (parent.setMode (this,"cool", deviceId))
generateModeEvent("cool")
else {
log.debug "Error setting new mode."
@@ -466,7 +466,7 @@ def cool() {
def auto() {
log.debug "auto"
def deviceId = device.deviceNetworkId.split(/\./).last()
if (parent.setMode ("auto", deviceId))
if (parent.setMode (this,"auto", deviceId))
generateModeEvent("auto")
else {
log.debug "Error setting new mode."
@@ -489,7 +489,7 @@ def fanOn() {
def coolingValue = location.temperatureScale == "C"? convertCtoF(coolingSetpoint) : coolingSetpoint
def heatingValue = location.temperatureScale == "C"? convertCtoF(heatingSetpoint) : heatingSetpoint
if (parent.setFanMode(heatingValue, coolingValue, deviceId, sendHoldType, fanMode)) {
if (parent.setFanMode(this, heatingValue, coolingValue, deviceId, sendHoldType, fanMode)) {
generateFanModeEvent(fanMode)
} else {
log.debug "Error setting new mode."
@@ -510,7 +510,7 @@ def fanAuto() {
def coolingValue = location.temperatureScale == "C"? convertCtoF(coolingSetpoint) : coolingSetpoint
def heatingValue = location.temperatureScale == "C"? convertCtoF(heatingSetpoint) : heatingSetpoint
if (parent.setFanMode(heatingValue, coolingValue, deviceId, sendHoldType, fanMode)) {
if (parent.setFanMode(this, heatingValue, coolingValue, deviceId, sendHoldType, fanMode)) {
generateFanModeEvent(fanMode)
} else {
log.debug "Error setting new mode."
@@ -556,12 +556,12 @@ def generateSetpointEvent() {
if (mode == "heat") {
sendEvent("name":"thermostatSetpoint", "value":heatingSetpoint, "unit":location.temperatureScale)
sendEvent("name":"thermostatSetpoint", "value":heatingSetpoint )
}
else if (mode == "cool") {
sendEvent("name":"thermostatSetpoint", "value":coolingSetpoint, "unit":location.temperatureScale)
sendEvent("name":"thermostatSetpoint", "value":coolingSetpoint)
} else if (mode == "auto") {
@@ -573,7 +573,7 @@ def generateSetpointEvent() {
} else if (mode == "auxHeatOnly") {
sendEvent("name":"thermostatSetpoint", "value":heatingSetpoint, "unit":location.temperatureScale)
sendEvent("name":"thermostatSetpoint", "value":heatingSetpoint)
}
@@ -608,7 +608,7 @@ void raiseSetpoint() {
targetvalue = maxCoolingSetpoint
}
sendEvent("name":"thermostatSetpoint", "value":targetvalue, "unit":location.temperatureScale, displayed: false)
sendEvent("name":"thermostatSetpoint", "value":targetvalue, displayed: false)
log.info "In mode $mode raiseSetpoint() to $targetvalue"
runIn(3, "alterSetpoint", [data: [value:targetvalue], overwrite: true]) //when user click button this runIn will be overwrite
@@ -644,7 +644,7 @@ void lowerSetpoint() {
targetvalue = minCoolingSetpoint
}
sendEvent("name":"thermostatSetpoint", "value":targetvalue, "unit":location.temperatureScale, displayed: false)
sendEvent("name":"thermostatSetpoint", "value":targetvalue, displayed: false)
log.info "In mode $mode lowerSetpoint() to $targetvalue"
runIn(3, "alterSetpoint", [data: [value:targetvalue], overwrite: true]) //when user click button this runIn will be overwrite
@@ -690,10 +690,10 @@ void alterSetpoint(temp) {
def coolingValue = location.temperatureScale == "C"? convertCtoF(targetCoolingSetpoint) : targetCoolingSetpoint
def heatingValue = location.temperatureScale == "C"? convertCtoF(targetHeatingSetpoint) : targetHeatingSetpoint
if (parent.setHold(heatingValue, coolingValue, deviceId, sendHoldType)) {
if (parent.setHold(this, heatingValue, coolingValue, deviceId, sendHoldType)) {
sendEvent("name": "thermostatSetpoint", "value": temp.value, displayed: false)
sendEvent("name": "heatingSetpoint", "value": targetHeatingSetpoint, "unit": location.temperatureScale)
sendEvent("name": "coolingSetpoint", "value": targetCoolingSetpoint, "unit": location.temperatureScale)
sendEvent("name": "heatingSetpoint", "value": targetHeatingSetpoint)
sendEvent("name": "coolingSetpoint", "value": targetCoolingSetpoint)
log.debug "alterSetpoint in mode $mode succeed change setpoint to= ${temp.value}"
} else {
log.error "Error alterSetpoint()"

View File

@@ -21,7 +21,6 @@ metadata {
attribute "tamper", "enum", ["detected", "clear"]
attribute "heatAlarm", "enum", ["overheat detected", "clear", "rapid temperature rise", "underheat detected"]
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x86, 0x72, 0x5A, 0x59, 0x85, 0x73, 0x84, 0x80, 0x71, 0x56, 0x70, 0x31, 0x8E, 0x22, 0x9C, 0x98, 0x7A", outClusters: "0x20, 0x8B"
fingerprint mfr:"010F", prod:"0C02", model:"1002"
}
simulator {
//battery

View File

@@ -682,7 +682,7 @@ def setHeatingSetpoint(degrees) {
def temperatureScale = getTemperatureScale()
def degreesInteger = degrees as Integer
sendEvent("name":"heatingSetpoint", "value":degreesInteger, "unit":temperatureScale)
sendEvent("name":"heatingSetpoint", "value":degreesInteger)
def celsius = (getTemperatureScale() == "C") ? degreesInteger : (fahrenheitToCelsius(degreesInteger) as Double).round(2)
"st wattr 0x${device.deviceNetworkId} 1 0x201 0x12 0x29 {" + hex(celsius*100) + "}"
@@ -691,7 +691,7 @@ def setHeatingSetpoint(degrees) {
def setCoolingSetpoint(degrees) {
def degreesInteger = degrees as Integer
sendEvent("name":"coolingSetpoint", "value":degreesInteger, "unit":temperatureScale)
sendEvent("name":"coolingSetpoint", "value":degreesInteger)
def celsius = (getTemperatureScale() == "C") ? degreesInteger : (fahrenheitToCelsius(degreesInteger) as Double).round(2)
"st wattr 0x${device.deviceNetworkId} 1 0x201 0x11 0x29 {" + hex(celsius*100) + "}"

View File

@@ -1,7 +1,7 @@
/**
* GE Link Bulb
*
* Copyright 2016 SmartThings
* 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:
@@ -53,8 +53,6 @@ metadata {
capability "Polling"
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,1000", outClusters: "0019", manufacturer: "GE_Appliances", model: "ZLL Light", deviceJoinName: "GE Link Bulb"
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,1000", outClusters: "0019", manufacturer: "GE", model: "SoftWhite", deviceJoinName: "GE Link Soft White Bulb"
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,1000", outClusters: "0019", manufacturer: "GE", model: "Daylight", deviceJoinName: "GE Link Daylight Bulb"
}
// UI tile definitions

View File

@@ -16,7 +16,6 @@ metadata {
capability "Switch"
capability "Refresh"
capability "Sensor"
capability "Health Check"
command "setAdjustedColor"
command "reset"
@@ -38,13 +37,16 @@ metadata {
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
attributeState "level", action:"switch level.setLevel", range:"(0..100)"
}
tileAttribute ("device.level", key: "SECONDARY_CONTROL") {
attributeState "level", label: 'Level ${currentValue}%'
}
tileAttribute ("device.color", key: "COLOR_CONTROL") {
attributeState "color", action:"setAdjustedColor"
}
}
standardTile("reset", "device.reset", height: 2, width: 2, inactiveLabel: false, decoration: "flat") {
state "default", label:"Reset To White", action:"reset", icon:"st.lights.philips.hue-single"
state "default", label:"Reset Color", action:"reset", icon:"st.lights.philips.hue-single"
}
standardTile("refresh", "device.refresh", height: 2, width: 2, inactiveLabel: false, decoration: "flat") {
@@ -52,14 +54,10 @@ metadata {
}
main(["rich-control"])
details(["rich-control", "reset", "refresh"])
details(["rich-control", "colorTempSliderControl", "colorTemp", "reset", "refresh"])
}
}
void installed() {
sendEvent(name: "checkInterval", value: 60 * 12, data: [protocol: "lan", hubHardwareId: device.hub.hardwareID], displayed: false)
}
// parse events into attributes
def parse(description) {
log.debug "parse() - $description"
@@ -80,78 +78,118 @@ def parse(description) {
// handle commands
void on() {
log.trace parent.on(this)
sendEvent(name: "switch", value: "on")
}
void off() {
log.trace parent.off(this)
sendEvent(name: "switch", value: "off")
}
void nextLevel() {
def level = device.latestValue("level") as Integer ?: 0
if (level <= 100) {
level = Math.min(25 * (Math.round(level / 25) + 1), 100) as Integer
}
else {
level = 25
}
setLevel(level)
}
void setLevel(percent) {
log.debug "Executing 'setLevel'"
if (verifyPercent(percent)) {
log.trace parent.setLevel(this, percent)
parent.setLevel(this, percent)
sendEvent(name: "level", value: percent, descriptionText: "Level has changed to ${percent}%")
sendEvent(name: "switch", value: "on")
}
}
void setSaturation(percent) {
log.debug "Executing 'setSaturation'"
if (verifyPercent(percent)) {
log.trace parent.setSaturation(this, percent)
parent.setSaturation(this, percent)
sendEvent(name: "saturation", value: percent, displayed: false)
}
}
void setHue(percent) {
log.debug "Executing 'setHue'"
if (verifyPercent(percent)) {
log.trace parent.setHue(this, percent)
parent.setHue(this, percent)
sendEvent(name: "hue", value: percent, displayed: false)
}
}
void setColor(value) {
log.debug "setColor: ${value}, $this"
def events = []
def validValues = [:]
if (verifyPercent(value.hue)) {
events << createEvent(name: "hue", value: value.hue, displayed: false)
validValues.hue = value.hue
}
if (verifyPercent(value.saturation)) {
events << createEvent(name: "saturation", value: value.saturation, displayed: false)
validValues.saturation = value.saturation
}
if (value.hex != null) {
if (value.hex ==~ /^\#([A-Fa-f0-9]){6}$/) {
events << createEvent(name: "color", value: value.hex)
validValues.hex = value.hex
} else {
log.warn "$value.hex is not a valid color"
}
}
if (verifyPercent(value.level)) {
events << createEvent(name: "level", value: value.level, descriptionText: "Level has changed to ${value.level}%")
validValues.level = value.level
}
if (value.switch == "off" || (value.level != null && value.level <= 0)) {
events << createEvent(name: "switch", value: "off")
validValues.switch = "off"
} else {
events << createEvent(name: "switch", value: "on")
validValues.switch = "on"
}
if (!validValues.isEmpty()) {
log.trace parent.setColor(this, validValues)
if (!events.isEmpty()) {
parent.setColor(this, validValues)
}
events.each {
sendEvent(it)
}
}
void reset() {
log.debug "Executing 'reset'"
def value = [hue:20, saturation:2]
setAdjustedColor(value)
def value = [level:100, saturation:56, hue:23]
setAdjustedColor(value)
parent.poll()
}
void setAdjustedColor(value) {
if (value) {
log.trace "setAdjustedColor: ${value}"
def adjusted = value + [:]
adjusted.hue = adjustOutgoingHue(value.hue)
// Needed because color picker always sends 100
adjusted.level = null
setColor(adjusted)
setColor(adjusted)
} else {
log.warn "Invalid color input $value"
log.warn "Invalid color input"
}
}
void setColorTemperature(value) {
if (value) {
log.trace "setColorTemperature: ${value}k"
parent.setColorTemperature(this, value)
sendEvent(name: "colorTemperature", value: value)
sendEvent(name: "switch", value: "on")
} else {
log.warn "Invalid color temperature"
}
}
@@ -160,6 +198,22 @@ void refresh() {
parent.manualRefresh()
}
def adjustOutgoingHue(percent) {
def adjusted = percent
if (percent > 31) {
if (percent < 63.0) {
adjusted = percent + (7 * (percent -30 ) / 32)
}
else if (percent < 73.0) {
adjusted = 69 + (5 * (percent - 62) / 10)
}
else {
adjusted = percent + (2 * (100 - percent) / 28)
}
}
log.info "percent: $percent, adjusted: $adjusted"
adjusted
}
def verifyPercent(percent) {
if (percent == null)
@@ -171,7 +225,3 @@ def verifyPercent(percent) {
return false
}
}
def ping() {
log.debug "${parent.ping(this)}"
}

View File

@@ -7,13 +7,8 @@
metadata {
// Automatically generated. Make future change here.
definition (name: "Hue Bridge", namespace: "smartthings", author: "SmartThings") {
attribute "serialNumber", "string"
attribute "networkAddress", "string"
// Used to indicate if bridge is reachable or not, i.e. is the bridge connected to the network
// Possible values "Online" or "Offline"
attribute "status", "string"
// Id is the number on the back of the hub, Hue uses last six digits of Mac address
// This is also used in the Hue application as ID
attribute "idNumber", "string"
}
simulator {
@@ -22,23 +17,22 @@ metadata {
tiles(scale: 2) {
multiAttributeTile(name:"rich-control"){
tileAttribute ("device.status", key: "PRIMARY_CONTROL") {
attributeState "Offline", label: '${currentValue}', action: "", icon: "st.Lighting.light99-hue", backgroundColor: "#ffffff"
attributeState "Online", label: '${currentValue}', action: "", icon: "st.Lighting.light99-hue", backgroundColor: "#79b821"
tileAttribute ("", key: "PRIMARY_CONTROL") {
attributeState "default", label: "Hue Bridge", action: "", icon: "st.Lighting.light99-hue", backgroundColor: "#F3C200"
}
tileAttribute ("serialNumber", key: "SECONDARY_CONTROL") {
attributeState "default", label:'SN: ${currentValue}'
}
valueTile("doNotRemove", "v", decoration: "flat", height: 2, width: 6, inactiveLabel: false) {
state "default", label:'If removed, Hue lights will not work properly'
}
valueTile("serialNumber", "device.serialNumber", decoration: "flat", height: 1, width: 2, inactiveLabel: false) {
state "default", label:'SN: ${currentValue}'
}
valueTile("idNumber", "device.idNumber", decoration: "flat", height: 2, width: 6, inactiveLabel: false) {
state "default", label:'ID: ${currentValue}'
}
valueTile("networkAddress", "device.networkAddress", decoration: "flat", height: 2, width: 6, inactiveLabel: false) {
state "default", label:'IP: ${currentValue}'
valueTile("networkAddress", "device.networkAddress", decoration: "flat", height: 2, width: 4, inactiveLabel: false) {
state "default", label:'${currentValue}', height: 1, width: 2, inactiveLabel: false
}
main (["rich-control"])
details(["rich-control", "doNotRemove", "idNumber", "networkAddress"])
details(["rich-control", "networkAddress"])
}
}
@@ -62,7 +56,7 @@ def parse(description) {
log.trace "HUE BRIDGE, GENERATING EVENT: $map.name: $map.value"
results << createEvent(name: "${map.name}", value: "${map.value}")
} else {
log.trace "Parsing description"
log.trace "Parsing description"
def msg = parseLanMessage(description)
if (msg.body) {
def contentType = msg.headers["Content-Type"]
@@ -72,13 +66,13 @@ def parse(description) {
log.info "Bridge response: $msg.body"
} else {
// Sending Bulbs List to parent"
if (parent.isInBulbDiscovery())
log.info parent.bulbListHandler(device.hub.id, msg.body)
if (parent.state.inBulbDiscovery)
log.info parent.bulbListHandler(device.hub.id, msg.body)
}
}
else if (contentType?.contains("xml")) {
log.debug "HUE BRIDGE ALREADY PRESENT"
parent.hubVerification(device.hub.id, msg.body)
parent.hubVerification(device.hub.id, msg.body)
}
}
}

View File

@@ -17,7 +17,6 @@ metadata {
capability "Switch"
capability "Refresh"
capability "Sensor"
capability "Health Check"
command "setAdjustedColor"
command "reset"
@@ -39,21 +38,24 @@ metadata {
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
attributeState "level", action:"switch level.setLevel", range:"(0..100)"
}
tileAttribute ("device.level", key: "SECONDARY_CONTROL") {
attributeState "level", label: 'Level ${currentValue}%'
}
tileAttribute ("device.color", key: "COLOR_CONTROL") {
attributeState "color", action:"setAdjustedColor"
}
}
controlTile("colorTempSliderControl", "device.colorTemperature", "slider", width: 4, height: 2, inactiveLabel: false, range:"(2000..6500)") {
state "colorTemperature", action:"color temperature.setColorTemperature"
}
controlTile("colorTempSliderControl", "device.colorTemperature", "slider", width: 4, height: 2, inactiveLabel: false, range:"(2000..6500)") {
state "colorTemperature", action:"color temperature.setColorTemperature"
}
valueTile("colorTemp", "device.colorTemperature", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "colorTemperature", label: 'WHITES'
}
valueTile("colorTemp", "device.colorTemperature", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "colorTemperature", label: '${currentValue} K'
}
standardTile("reset", "device.reset", height: 2, width: 2, inactiveLabel: false, decoration: "flat") {
state "default", label:"Reset To White", action:"reset", icon:"st.lights.philips.hue-single"
state "default", label:"Reset Color", action:"reset", icon:"st.lights.philips.hue-single"
}
standardTile("refresh", "device.refresh", height: 2, width: 2, inactiveLabel: false, decoration: "flat") {
@@ -65,10 +67,6 @@ metadata {
}
}
void installed() {
sendEvent(name: "checkInterval", value: 60 * 12, data: [protocol: "lan", hubHardwareId: device.hub.hardwareID], displayed: false)
}
// parse events into attributes
def parse(description) {
log.debug "parse() - $description"
@@ -89,86 +87,118 @@ def parse(description) {
// handle commands
void on() {
log.trace parent.on(this)
sendEvent(name: "switch", value: "on")
}
void off() {
log.trace parent.off(this)
sendEvent(name: "switch", value: "off")
}
void nextLevel() {
def level = device.latestValue("level") as Integer ?: 0
if (level <= 100) {
level = Math.min(25 * (Math.round(level / 25) + 1), 100) as Integer
}
else {
level = 25
}
setLevel(level)
}
void setLevel(percent) {
log.debug "Executing 'setLevel'"
if (verifyPercent(percent)) {
log.trace parent.setLevel(this, percent)
parent.setLevel(this, percent)
sendEvent(name: "level", value: percent, descriptionText: "Level has changed to ${percent}%")
sendEvent(name: "switch", value: "on")
}
}
void setSaturation(percent) {
log.debug "Executing 'setSaturation'"
if (verifyPercent(percent)) {
log.trace parent.setSaturation(this, percent)
parent.setSaturation(this, percent)
sendEvent(name: "saturation", value: percent, displayed: false)
}
}
void setHue(percent) {
log.debug "Executing 'setHue'"
if (verifyPercent(percent)) {
log.trace parent.setHue(this, percent)
parent.setHue(this, percent)
sendEvent(name: "hue", value: percent, displayed: false)
}
}
void setColor(value) {
log.debug "setColor: ${value}, $this"
def events = []
def validValues = [:]
if (verifyPercent(value.hue)) {
events << createEvent(name: "hue", value: value.hue, displayed: false)
validValues.hue = value.hue
}
if (verifyPercent(value.saturation)) {
events << createEvent(name: "saturation", value: value.saturation, displayed: false)
validValues.saturation = value.saturation
}
if (value.hex != null) {
if (value.hex ==~ /^\#([A-Fa-f0-9]){6}$/) {
events << createEvent(name: "color", value: value.hex)
validValues.hex = value.hex
} else {
log.warn "$value.hex is not a valid color"
}
}
if (verifyPercent(value.level)) {
events << createEvent(name: "level", value: value.level, descriptionText: "Level has changed to ${value.level}%")
validValues.level = value.level
}
if (value.switch == "off" || (value.level != null && value.level <= 0)) {
events << createEvent(name: "switch", value: "off")
validValues.switch = "off"
} else {
events << createEvent(name: "switch", value: "on")
validValues.switch = "on"
}
if (!validValues.isEmpty()) {
log.trace parent.setColor(this, validValues)
if (!events.isEmpty()) {
parent.setColor(this, validValues)
}
events.each {
sendEvent(it)
}
}
void reset() {
log.debug "Executing 'reset'"
setColorTemperature(4000)
def value = [level:100, saturation:56, hue:23]
setAdjustedColor(value)
parent.poll()
}
void setAdjustedColor(value) {
if (value) {
log.trace "setAdjustedColor: ${value}"
def adjusted = value + [:]
adjusted.hue = adjustOutgoingHue(value.hue)
// Needed because color picker always sends 100
adjusted.level = null
setColor(adjusted)
setColor(adjusted)
} else {
log.warn "Invalid color input $value"
log.warn "Invalid color input"
}
}
void setColorTemperature(value) {
if (value) {
log.trace "setColorTemperature: ${value}k"
log.trace parent.setColorTemperature(this, value)
parent.setColorTemperature(this, value)
sendEvent(name: "colorTemperature", value: value)
sendEvent(name: "switch", value: "on")
} else {
log.warn "Invalid color temperature $value"
log.warn "Invalid color temperature"
}
}
@@ -177,6 +207,23 @@ void refresh() {
parent.manualRefresh()
}
def adjustOutgoingHue(percent) {
def adjusted = percent
if (percent > 31) {
if (percent < 63.0) {
adjusted = percent + (7 * (percent -30 ) / 32)
}
else if (percent < 73.0) {
adjusted = 69 + (5 * (percent - 62) / 10)
}
else {
adjusted = percent + (2 * (100 - percent) / 28)
}
}
log.info "percent: $percent, adjusted: $adjusted"
adjusted
}
def verifyPercent(percent) {
if (percent == null)
return false
@@ -187,7 +234,3 @@ def verifyPercent(percent) {
return false
}
}
def ping() {
log.trace "${parent.ping(this)}"
}

View File

@@ -14,7 +14,6 @@ metadata {
capability "Switch"
capability "Refresh"
capability "Sensor"
capability "Health Check"
command "refresh"
}
@@ -34,6 +33,9 @@ metadata {
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
attributeState "level", action:"switch level.setLevel", range:"(0..100)"
}
tileAttribute ("device.level", key: "SECONDARY_CONTROL") {
attributeState "level", label: 'Level ${currentValue}%'
}
}
controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 2, inactiveLabel: false, range:"(0..100)") {
@@ -49,10 +51,6 @@ metadata {
}
}
void installed() {
sendEvent(name: "checkInterval", value: 60 * 12, data: [protocol: "lan", hubHardwareId: device.hub.hardwareID], displayed: false)
}
// parse events into attributes
def parse(description) {
log.debug "parse() - $description"
@@ -73,16 +71,20 @@ def parse(description) {
// handle commands
void on() {
log.trace parent.on(this)
sendEvent(name: "switch", value: "on")
}
void off() {
log.trace parent.off(this)
sendEvent(name: "switch", value: "off")
}
void setLevel(percent) {
log.debug "Executing 'setLevel'"
if (percent != null && percent >= 0 && percent <= 100) {
parent.setLevel(this, percent)
sendEvent(name: "level", value: percent)
sendEvent(name: "switch", value: "on")
} else {
log.warn "$percent is not 0-100"
}
@@ -92,7 +94,3 @@ void refresh() {
log.debug "Executing 'refresh'"
parent.manualRefresh()
}
def ping() {
log.debug "${parent.ping(this)}"
}

View File

@@ -1,112 +0,0 @@
/**
* Hue White Ambiance Bulb
*
* Philips Hue Type "Color Temperature Light"
*
* Author: SmartThings
*/
// for the UI
metadata {
// Automatically generated. Make future change here.
definition (name: "Hue White Ambiance Bulb", namespace: "smartthings", author: "SmartThings") {
capability "Switch Level"
capability "Actuator"
capability "Color Temperature"
capability "Switch"
capability "Refresh"
capability "Health Check"
command "refresh"
}
simulator {
// TODO: define status and reply messages here
}
tiles (scale: 2){
multiAttributeTile(name:"rich-control", 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", range:"(0..100)"
}
}
controlTile("colorTempSliderControl", "device.colorTemperature", "slider", width: 4, height: 2, inactiveLabel: false, range:"(2200..6500)") {
state "colorTemperature", action:"color temperature.setColorTemperature"
}
valueTile("colorTemp", "device.colorTemperature", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "colorTemperature", label: 'WHITES'
}
standardTile("refresh", "device.refresh", height: 2, width: 2, inactiveLabel: false, decoration: "flat") {
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
}
main(["rich-control"])
details(["rich-control", "colorTempSliderControl", "colorTemp", "refresh"])
}
}
void installed() {
sendEvent(name: "checkInterval", value: 60 * 12, data: [protocol: "lan", hubHardwareId: device.hub.hardwareID], displayed: false)
}
// parse events into attributes
def parse(description) {
log.debug "parse() - $description"
def results = []
def map = description
if (description instanceof String) {
log.debug "Hue Ambience Bulb stringToMap - ${map}"
map = stringToMap(description)
}
if (map?.name && map?.value) {
results << createEvent(name: "${map?.name}", value: "${map?.value}")
}
results
}
// handle commands
void on() {
log.trace parent.on(this)
}
void off() {
log.trace parent.off(this)
}
void setLevel(percent) {
log.debug "Executing 'setLevel'"
if (percent != null && percent >= 0 && percent <= 100) {
log.trace parent.setLevel(this, percent)
} else {
log.warn "$percent is not 0-100"
}
}
void setColorTemperature(value) {
if (value) {
log.trace "setColorTemperature: ${value}k"
log.trace parent.setColorTemperature(this, value)
} else {
log.warn "Invalid color temperature"
}
}
void refresh() {
log.debug "Executing 'refresh'"
parent.manualRefresh()
}
def ping() {
log.debug "${parent.ping(this)}"
}

View File

@@ -1,3 +1,4 @@
#==============================================================================
# Copyright 2016 SmartThings
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
@@ -11,6 +12,15 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#==============================================================================
# Purpose: Mobile Presence i18n Translation File
#
# Filename: mobile-presence.src/i18n/messages.properties
#
# Change History:
# 1. 20160205 TW Initial release with informal Korean translation.
# 2. 20160224 TW Updated with formal Korean translation.
#==============================================================================
# Korean (ko)
# Device Preferences
'''Give your device a name'''.ko=기기 이름 설정

View File

@@ -1,4 +1,5 @@
/*
===============================================================================
* Copyright 2016 SmartThings
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
@@ -12,6 +13,14 @@
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
===============================================================================
* Purpose: Mobile Presence DTH File
*
* Filename: mobile-presence.src/mobile-presence.groovy
*
* Change History:
* 1. 20160205 TW - Update/Edit to support i18n translations
===============================================================================
*/
metadata {

View File

@@ -13,7 +13,6 @@
* for the specific language governing permissions and limitations under the License.
*
*/
import physicalgraph.zigbee.clusters.iaszone.ZoneStatus
metadata {
definition (name: "NYCE Motion Sensor", namespace: "smartthings", author: "SmartThings") {
@@ -144,14 +143,51 @@ private Map parseReportAttributeMessage(String description) {
private Map parseIasMessage(String description) {
ZoneStatus zs = zigbee.parseZoneStatus(description)
Map resultMap = [:]
List parsedMsg = description.split(' ')
String msgCode = parsedMsg[2]
Map resultMap = [:]
switch(msgCode) {
case '0x0030': // Closed/No Motion/Dry
log.debug 'no motion'
resultMap.name = 'motion'
resultMap.value = 'inactive'
break
resultMap.name = 'motion'
resultMap.value = zs.isAlarm2Set() ? 'active' : 'inactive'
log.debug(zs.isAlarm2Set() ? 'motion' : 'no motion')
case '0x0032': // Open/Motion/Wet
log.debug 'motion'
resultMap.name = 'motion'
resultMap.value = 'active'
break
return resultMap
case '0x0032': // Tamper Alarm
log.debug 'motion with tamper alarm'
resultMap.name = 'motion'
resultMap.value = 'active'
break
case '0x0033': // Battery Alarm
break
case '0x0034': // Supervision Report
log.debug 'no motion with tamper alarm'
resultMap.name = 'motion'
resultMap.value = 'inactive'
break
case '0x0035': // Restore Report
break
case '0x0036': // Trouble/Failure
log.debug 'motion with failure alarm'
resultMap.name = 'motion'
resultMap.value = 'active'
break
case '0x0038': // Test Mode
break
}
return resultMap
}
def refresh()

View File

@@ -13,10 +13,7 @@
* for the specific language governing permissions and limitations under the License.
*
*/
import physicalgraph.zigbee.clusters.iaszone.ZoneStatus
metadata {
definition (name: "NYCE Open/Closed Sensor", namespace: "smartthings", author: "NYCE") {
capability "Battery"
@@ -222,33 +219,40 @@ private Map parseReportAttributeMessage(String description) {
}
private List parseIasMessage(String description) {
ZoneStatus zs = zigbee.parseZoneStatus(description)
log.debug "parseIasMessage: $description"
List parsedMsg = description.split(" ")
String msgCode = parsedMsg[2]
List resultListMap = []
Map resultMap_battery = [:]
Map resultMap_battery_state = [:]
Map resultMap_sensor = [:]
resultMap_sensor.name = "contact"
resultMap_sensor.value = zs.isAlarm1Set() ? "open" : "closed"
// Relevant bit field definitions from ZigBee spec
def BATTERY_BIT = ( 1 << 3 )
def TROUBLE_BIT = ( 1 << 6 )
def SENSOR_BIT = ( 1 << 0 ) // it's ALARM1 bit from the ZCL spec
// Convert hex string to integer
def zoneStatus = Integer.parseInt(msgCode[-4..-1],16)
log.debug "parseIasMessage: zoneStatus: ${zoneStatus}"
// Check each relevant bit, create map for it, and add to list
log.debug "parseIasMessage: Battery Status ${zs.battery}"
log.debug "parseIasMessage: Trouble Status ${zs.trouble}"
log.debug "parseIasMessage: Sensor Status ${zs.alarm1}"
log.debug "parseIasMessage: Battery Status ${zoneStatus & BATTERY_BIT}"
log.debug "parseIasMessage: Trouble Status ${zoneStatus & TROUBLE_BIT}"
log.debug "parseIasMessage: Sensor Status ${zoneStatus & SENSOR_BIT}"
/* Comment out this path to check the battery state to avoid overwriting the
battery value (Change log #2), but keep these conditions for later use
resultMap_battery_state.name = "battery_state"
if (zs.isTroubleSet()) {
if (zoneStatus & TROUBLE_BIT) {
resultMap_battery_state.value = "failed"
resultMap_battery.name = "battery"
resultMap_battery.value = 0
}
else {
if (zs.isBatterySet()) {
if (zoneStatus & BATTERY_BIT) {
resultMap_battery_state.value = "low"
// to generate low battery notification by the platform
@@ -266,6 +270,9 @@ private List parseIasMessage(String description) {
}
*/
resultMap_sensor.name = "contact"
resultMap_sensor.value = (zoneStatus & SENSOR_BIT) ? "open" : "closed"
resultListMap << resultMap_battery_state
resultListMap << resultMap_battery
resultListMap << resultMap_sensor

View File

@@ -91,7 +91,7 @@ def parse(String description) {
if (descMap.cluster == "0300") {
if(descMap.attrId == "0000"){ //Hue Attribute
def hueValue = Math.round(convertHexToInt(descMap.value) / 255 * 100)
def hueValue = Math.round(convertHexToInt(descMap.value) / 255 * 360)
log.debug "Hue value returned is $hueValue"
sendEvent(name: "hue", value: hueValue, displayed:false)
}
@@ -203,7 +203,7 @@ def setLevel(value) {
//input Hue Integer values; returns color name for saturation 100%
private getColorName(hueValue){
if(hueValue>100 || hueValue<0)
if(hueValue>360 || hueValue<0)
return
hueValue = Math.round(hueValue / 100 * 360)

View File

@@ -1,4 +1,4 @@
/*
/*
Osram Flex RGBW Light Strip
Osram bulbs have a firmware issue causing it to forget its dimming level when turned off (via commands). Handling
@@ -8,7 +8,7 @@
metadata {
definition (name: "OSRAM LIGHTIFY LED Flexible Strip RGBW", namespace: "smartthings", author: "SmartThings") {
capability "Color Temperature"
capability "Actuator"
capability "Switch"
@@ -18,7 +18,7 @@ metadata {
capability "Refresh"
capability "Sensor"
capability "Color Control"
attribute "colorName", "string"
command "setAdjustedColor"
@@ -49,7 +49,7 @@ metadata {
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
}
controlTile("colorTempSliderControl", "device.colorTemperature", "slider", height: 1, width: 2, inactiveLabel: false, range:"(2700..6500)") {
state "colorTemperature", action:"color temperature.setColorTemperature"
}
@@ -118,7 +118,7 @@ def parse(String description) {
}
}
else if(descMap.attrId == "0000"){ //Hue Attribute
def hueValue = Math.round(convertHexToInt(descMap.value) / 255 * 100)
def hueValue = Math.round(convertHexToInt(descMap.value) / 255 * 360)
log.debug "Hue value returned is $hueValue"
sendEvent(name: "hue", value: hueValue, displayed:false)
}
@@ -274,7 +274,7 @@ private getGenericName(value){
//input Hue Integer values; returns color name for saturation 100%
private getColorName(hueValue){
if(hueValue>100 || hueValue<0)
if(hueValue>360 || hueValue<0)
return
hueValue = Math.round(hueValue / 100 * 360)
@@ -449,7 +449,7 @@ def setColor(value){
def level = hex(value.level * 255 / 100)
cmd << zigbeeSetLevel(level)
}
if (value.switch == "off") {
cmd << "delay 150"
cmd << off()

View File

@@ -19,6 +19,11 @@ metadata {
capability "Sensor"
attribute "colorName", "string"
// indicates that device keeps track of heartbeat (in state.heartbeat)
attribute "heartbeat", "string"
}
// simulator metadata
@@ -70,6 +75,9 @@ metadata {
def parse(String description) {
//log.trace description
// save heartbeat (i.e. last time we got a message from device)
state.heartbeat = Calendar.getInstance().getTimeInMillis()
if (description?.startsWith("catchall:")) {
if(description?.endsWith("0100") ||description?.endsWith("1001") || description?.matches("on/off\\s*:\\s*1"))
{
@@ -124,6 +132,7 @@ def off() {
}
def refresh() {
sendEvent(name: "heartbeat", value: "alive", displayed:false)
[
"st rattr 0x${device.deviceNetworkId} ${endpointId} 6 0", "delay 500",
"st rattr 0x${device.deviceNetworkId} ${endpointId} 8 0", "delay 500",

View File

@@ -47,21 +47,9 @@ def parse(String description) {
// Commands to device
def on() {
[
'zcl on-off on',
'delay 200',
"send 0x${zigbee.deviceNetworkId} 0x01 0x${zigbee.endpointId}",
'delay 500'
]
'zcl on-off on'
}
def off() {
[
'zcl on-off off',
'delay 200',
"send 0x${zigbee.deviceNetworkId} 0x01 0x${zigbee.endpointId}",
'delay 500'
]
'zcl on-off off'
}

View File

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

View File

@@ -1,38 +0,0 @@
# SmartPower Outlet
Works with:
* [Samsung SmartPower Outlet](https://shop.smartthings.com/#!/products/smartpower-outlet)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
## Capabilities
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
* **Actuator** - represents that a Device has commands
* **Switch** - can detect state (possible values: on/off)
* **Refresh** - _refresh()_ command for status updates
* **Power Meter** - detects power meter for device in either w or kw.
* **Health Check** - indicates ability to get device health notifications
* **Sensor** - detects sensor events
## Device Health
A Category C1 smart power outlet with maxReportTime of 5 mins.
Check-in interval is double the value of maxReportTime.
This gives the device twice the amount of time to respond before it is marked as offline.
Check-in interval = 12 mins
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
Pairing needs to be tried again by placing the device closer to the hub.
Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following links
for the different models:
* [SmartPower Outlet Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/201084854-SmartPower-Outlet)
* [Samsung SmartThings Outlet Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/205957620)

View File

@@ -1,3 +1,4 @@
#==============================================================================
# Copyright 2016 SmartThings
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
@@ -11,6 +12,14 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#==============================================================================
# Purpose: SmartPower Outlet i18n Translation File
#
# Filename: SmartPower-Outlet.src/i18n/messages.properties
#
# Change History:
# 1. 20160116 TW Initial release with informal Korean translation.
#==============================================================================
# Korean (ko)
# Device Preferences
'''Give your device a name'''.ko=기기 이름 설정

View File

@@ -1,4 +1,5 @@
/*
===============================================================================
* Copyright 2016 SmartThings
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
@@ -12,11 +13,18 @@
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
===============================================================================
* Purpose: SmartPower Outlet DTH File
*
* Filename: SmartPower-Outlet.src/SmartPower-Outlet.groovy
*
* Change History:
* 1. 20160117 TW - Update/Edit to support i18n translations
===============================================================================
*/
metadata {
// Automatically generated. Make future change here.
definition (name: "SmartPower Outlet", namespace: "smartthings", author: "SmartThings", category: "C1") {
definition (name: "SmartPower Outlet", namespace: "smartthings", author: "SmartThings") {
capability "Actuator"
capability "Switch"
capability "Power Meter"
@@ -25,6 +33,9 @@ metadata {
capability "Sensor"
capability "Health Check"
// indicates that device keeps track of heartbeat (in state.heartbeat)
attribute "heartbeat", "string"
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3200", deviceJoinName: "Outlet"
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3200-Sgb", deviceJoinName: "Outlet"
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "4257050-RZHAC", deviceJoinName: "Outlet"
@@ -78,6 +89,9 @@ metadata {
def parse(String description) {
log.debug "description is $description"
// save heartbeat (i.e. last time we got a message from device)
state.heartbeat = Calendar.getInstance().getTimeInMillis()
def finalResult = zigbee.getKnownDescription(description)
//TODO: Remove this after getKnownDescription can parse it automatically
@@ -116,22 +130,14 @@ def off() {
def on() {
zigbee.on()
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
return zigbee.onOffRefresh()
}
def refresh() {
zigbee.onOffRefresh() + zigbee.electricMeasurementPowerRefresh()
sendEvent(name: "heartbeat", value: "alive", displayed:false)
zigbee.onOffRefresh() + zigbee.refreshData("0x0B04", "0x050B")
}
def configure() {
// Device-Watch allows 2 check-in misses from device
sendEvent(name: "checkInterval", value: 60 * 12, 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) + powerConfig() + refresh()
zigbee.onOffConfig() + powerConfig() + refresh()
}
//power config for devices with min reporting interval as 1 seconds and reporting interval if no activity as 10min (600s)

View File

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

View File

@@ -1,44 +0,0 @@
# Smartsense Moisture Sensor
Works with:
* [Samsung SmartThings Moisture Sensor](https://shop.smartthings.com/#!/products/samsung-smartthings-water-leak-sensor)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Battery](#battery-specification)
## Capabilities
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
* **Battery** - defines device uses a battery
* **Refresh** - _refresh()_ command for status updates
* **Temperature Measurement** - defines device measures current temperature
* **Water Sensor** - can detect presence of water (dry or wet)
* **Health Check** - indicates ability to get device health notifications
## Device Health
A Category C2 moisture sensor with maxReportTime of 5 mins.
Check-in interval is double the value of maxReportTime.
This gives the device twice the amount of time to respond before it is marked as offline.
Check-in interval = 12 mins
## Battery Specification
One CR2 3V battery required.
## Troubleshooting
If the sensor doesn't pair when trying from the SmartThings mobile app, it is possible that the sensor is out of range.
Pairing needs to be tried again by placing the sensor closer to the hub.
Instructions related to pairing, resetting and removing the different sensors from SmartThings can be found in the following links
for the different models:
* [SmartSense Moisture Sensor Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/202847044-SmartSense-Moisture-Sensor)
* [Samsung SmartThings Water Leak Sensor Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/205957630)
Other troubleshooting tips are listed as follows:
* [Troubleshooting: Samsung SmartThings Water Leak Sensor wont pair after removing pull-tab](https://support.smartthings.com/hc/en-us/articles/204966616-Troubleshooting-Samsung-SmartThings-device-won-t-pair-after-removing-pull-tab)

View File

@@ -1,3 +1,4 @@
#==============================================================================
# Copyright 2016 SmartThings
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
@@ -11,6 +12,14 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#==============================================================================
# Purpose: SmartSense Moisture Sensor i18n Translation File
#
# Filename: SmartSense-Moisture-Sensor.src/i18n/messages.properties
#
# Change History:
# 1. 20160116 TW Initial release with formal Korean translation.
#==============================================================================
# Korean (ko)
# Device Preferences
'''Dry'''.ko=건조

View File

@@ -1,4 +1,5 @@
/*
===============================================================================
* Copyright 2016 SmartThings
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
@@ -12,19 +13,25 @@
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
===============================================================================
* Purpose: SmartSense Moisture Sensor DTH File
*
* Filename: SmartSense-Moisture-Sensor.src/SmartSense-Moisture-Sensor.groovy
*
* Change History:
* 1. 20160116 TW - Update/Edit to support i18n translations
* 2. 20160125 TW = Incorporated new battery mapping from TM
===============================================================================
*/
import physicalgraph.zigbee.clusters.iaszone.ZoneStatus
metadata {
definition (name: "SmartSense Moisture Sensor",namespace: "smartthings", author: "SmartThings", category: "C2") {
definition (name: "SmartSense Moisture Sensor",namespace: "smartthings", author: "SmartThings") {
capability "Configuration"
capability "Battery"
capability "Refresh"
capability "Temperature Measurement"
capability "Water Sensor"
capability "Health Check"
capability "Sensor"
command "enrollResponse"
@@ -172,17 +179,50 @@ private Map parseCustomMessage(String description) {
}
private Map parseIasMessage(String description) {
ZoneStatus zs = zigbee.parseZoneStatus(description)
List parsedMsg = description.split(' ')
String msgCode = parsedMsg[2]
return zs.isAlarm1Set() ? getMoistureResult('wet') : getMoistureResult('dry')
Map resultMap = [:]
switch(msgCode) {
case '0x0020': // Closed/No Motion/Dry
resultMap = getMoistureResult('dry')
break
case '0x0021': // Open/Motion/Wet
resultMap = getMoistureResult('wet')
break
case '0x0022': // Tamper Alarm
break
case '0x0023': // Battery Alarm
break
case '0x0024': // Supervision Report
log.debug 'dry with tamper alarm'
resultMap = getMoistureResult('dry')
break
case '0x0025': // Restore Report
log.debug 'water with tamper alarm'
resultMap = getMoistureResult('wet')
break
case '0x0026': // Trouble/Failure
break
case '0x0028': // Test Mode
break
}
return resultMap
}
def getTemperature(value) {
def celsius = Integer.parseInt(value, 16).shortValue() / 100
if(getTemperatureScale() == "C"){
return Math.round(celsius)
return celsius
} else {
return Math.round(celsiusToFahrenheit(celsius))
return celsiusToFahrenheit(celsius) as Integer
}
}
@@ -225,10 +265,7 @@ private Map getBatteryResult(rawValue) {
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.value = Math.min(100, roundedPct)
result.value = Math.min(100, (int) pct * 100)
result.descriptionText = "{{ device.displayName }} battery was {{ value }}%"
}
}
@@ -254,8 +291,7 @@ private Map getTemperatureResult(value) {
name: 'temperature',
value: value,
descriptionText: descriptionText,
translatable: true,
unit: temperatureScale
translatable: true
]
}
@@ -274,13 +310,6 @@ private Map getMoistureResult(value) {
]
}
/**
* 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 Temperature and Battery"
def refreshCmds = [
@@ -292,19 +321,21 @@ def refresh() {
}
def configure() {
// Device-Watch allows 2 check-in misses from device
sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
String zigbeeEui = swapEndianHex(device.hub.zigbeeEui)
log.debug "Configuring Reporting, IAS CIE, and Bindings."
def enrollCmds = [
def configCmds = [
"zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}", "delay 200",
"send 0x${device.deviceNetworkId} 1 1", "delay 500",
]
// temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity
// battery minReport 30 seconds, maxReportTime 6 hrs by default
return enrollCmds + zigbee.batteryConfig() + zigbee.temperatureConfig(30, 300) + refresh() // send refresh cmds as part of config
"zdo bind 0x${device.deviceNetworkId} ${endpointId} 1 1 {${device.zigbeeId}} {}", "delay 500",
"zcl global send-me-a-report 1 0x20 0x20 30 21600 {01}", //checkin time 6 hrs
"send 0x${device.deviceNetworkId} 1 1", "delay 500",
"zdo bind 0x${device.deviceNetworkId} ${endpointId} 1 0x402 {${device.zigbeeId}} {}", "delay 500",
"zcl global send-me-a-report 0x402 0 0x29 30 3600 {6400}",
"send 0x${device.deviceNetworkId} 1 1", "delay 500"
]
return configCmds + refresh() // send refresh cmds as part of config
}
def enrollResponse() {

View File

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

View File

@@ -1,45 +0,0 @@
# Smartsense Motion Sensor
Works with:
* [Samsung SmartThings Motion Sensor](https://shop.smartthings.com/#!/products/samsung-smartthings-motion-sensor)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Battery](#battery-specification)
## Capabilities
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
* **Motion Sensor** - can detect motion
* **Battery** - defines device uses a battery
* **Refresh** - _refresh()_ command for status updates
* **Health Check** - indicates ability to get device health notifications
## Device Health
A Category C2 motion sensor with maxReportTime of 5 mins.
Check-in interval is double the value of maxReportTime.
This gives the device twice the amount of time to respond before it is marked as offline.
Check-in interval = 12 mins
## Battery Specification
One CR2477 (for Samsung SmartThings Motion Sensor) / CR123A (SmartSense Motion Sensor) 3V battery is required.
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the sensor is out of range.
Pairing needs to be tried again by placing the sensor closer to the hub.
Instructions related to pairing, resetting and removing the different motion sensors from SmartThings can be found in the following links
for the different models:
* [SmartSense Motion Sensor (original model) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/200903280-SmartSense-Motion-Sensor-original-model-)
* [SmartSense Motion Sensor (2014 model) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/203077520-SmartSense-Motion-Sensor-2014-model-)
* [Samsung SmartThings Motion Sensor (2015 model) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/205957580-Samsung-SmartThings-Motion-Sensor-2015-model-)
Other troubleshooting tips are listed as follows:
* [Troubleshooting: Samsung SmartThings Motion Sensor is stuck showing "Motion Detected" or "No Motion"](https://support.smartthings.com/hc/en-us/articles/200961130-Troubleshooting-Samsung-SmartThings-Motion-Sensor-is-stuck-showing-Motion-Detected-or-No-Motion-)
* [Troubleshooting: Samsung SmartThings Motion Sensor wont pair after removing pull-tab](https://support.smartthings.com/hc/en-us/articles/204966616-Troubleshooting-Samsung-SmartThings-device-won-t-pair-after-removing-pull-tab)

View File

@@ -1,3 +1,4 @@
#==============================================================================
# Copyright 2016 SmartThings
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
@@ -11,6 +12,15 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#==============================================================================
# Purpose: SmartSense Motion Sensor i18n Translation File
#
# Filename: SmartSense-Motion-Sensor.src/i18n/messages.properties
#
# Change History:
# 1. 20160116 TW Initial release with formal Korean translation.
# 2. 20160224 TW Updated formal Korean translations from Mike Stoller.
#==============================================================================
# Korean (ko)
# Device Preferences
'''battery'''.ko=배터리

View File

@@ -1,4 +1,5 @@
/*
===============================================================================
* Copyright 2016 SmartThings
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
@@ -12,19 +13,25 @@
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
===============================================================================
* Purpose: SmartSense Motion Sensor DTH File
*
* Filename: SmartSense-Motion-Sensor.src/SmartSense-Motion-Sensor.groovy
*
* Change History:
* 1. 20160116 TW - Update/Edit to support i18n translations
* 2. 20160125 TW = Incorporated new battery mapping from TM
===============================================================================
*/
import physicalgraph.zigbee.clusters.iaszone.ZoneStatus
metadata {
definition (name: "SmartSense Motion Sensor", namespace: "smartthings", author: "SmartThings", category: "C2") {
definition (name: "SmartSense Motion Sensor", namespace: "smartthings", author: "SmartThings") {
capability "Motion Sensor"
capability "Configuration"
capability "Battery"
capability "Temperature Measurement"
capability "Refresh"
capability "Health Check"
capability "Sensor"
command "enrollResponse"
@@ -185,18 +192,52 @@ private Map parseCustomMessage(String description) {
}
private Map parseIasMessage(String description) {
ZoneStatus zs = zigbee.parseZoneStatus(description)
List parsedMsg = description.split(' ')
String msgCode = parsedMsg[2]
// 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')
Map resultMap = [:]
switch(msgCode) {
case '0x0020': // Closed/No Motion/Dry
resultMap = getMotionResult('inactive')
break
case '0x0021': // Open/Motion/Wet
resultMap = getMotionResult('active')
break
case '0x0022': // Tamper Alarm
log.debug 'motion with tamper alarm'
resultMap = getMotionResult('active')
break
case '0x0023': // Battery Alarm
break
case '0x0024': // Supervision Report
log.debug 'no motion with tamper alarm'
resultMap = getMotionResult('inactive')
break
case '0x0025': // Restore Report
break
case '0x0026': // Trouble/Failure
log.debug 'motion with failure alarm'
resultMap = getMotionResult('active')
break
case '0x0028': // Test Mode
break
}
return resultMap
}
def getTemperature(value) {
def celsius = Integer.parseInt(value, 16).shortValue() / 100
if(getTemperatureScale() == "C"){
return Math.round(celsius)
return celsius
} else {
return Math.round(celsiusToFahrenheit(celsius))
return celsiusToFahrenheit(celsius) as Integer
}
}
@@ -240,10 +281,7 @@ private Map getBatteryResult(rawValue) {
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.value = Math.min(100, roundedPct)
result.value = Math.min(100, (int) pct * 100)
result.descriptionText = "{{ device.displayName }} battery was {{ value }}%"
}
}
@@ -269,8 +307,7 @@ private Map getTemperatureResult(value) {
name: 'temperature',
value: value,
descriptionText: descriptionText,
translatable: true,
unit: temperatureScale
translatable: true
]
}
@@ -285,13 +322,6 @@ private Map getMotionResult(value) {
]
}
/**
* 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 = [
@@ -303,19 +333,22 @@ def refresh() {
}
def configure() {
// Device-Watch allows 2 check-in misses from device
sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
String zigbeeEui = swapEndianHex(device.hub.zigbeeEui)
log.debug "Configuring Reporting, IAS CIE, and Bindings."
def enrollCmds = [
def configCmds = [
"zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}", "delay 200",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
"zdo bind 0x${device.deviceNetworkId} ${endpointId} 1 1 {${device.zigbeeId}} {}", "delay 200",
"zcl global send-me-a-report 1 0x20 0x20 30 21600 {01}", //checkin time 6 hrs
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
"zdo bind 0x${device.deviceNetworkId} ${endpointId} 1 0x402 {${device.zigbeeId}} {}", "delay 200",
"zcl global send-me-a-report 0x402 0 0x29 300 3600 {6400}",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500"
]
// temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity
// battery minReport 30 seconds, maxReportTime 6 hrs by default
return enrollCmds + zigbee.batteryConfig() + zigbee.temperatureConfig(30, 300) + refresh() // send refresh cmds as part of config
return configCmds + refresh() // send refresh cmds as part of config
}
def enrollResponse() {

View File

@@ -15,7 +15,6 @@
*/
//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") {
@@ -25,7 +24,7 @@ metadata {
capability "Temperature Measurement"
capability "Refresh"
capability "Sensor"
command "enrollResponse"
}
@@ -74,7 +73,7 @@ metadata {
def parse(String description) {
log.debug "description: $description"
Map map = [:]
if (description?.startsWith('catchall:')) {
map = parseCatchAllMessage(description)
@@ -88,10 +87,10 @@ def parse(String description) {
else if (description?.startsWith('zone status')) {
map = parseIasMessage(description)
}
log.debug "Parse returned $map"
def result = map ? createEvent(map) : null
if (description?.startsWith('enroll request')) {
List cmds = enrollResponse()
log.debug "enroll response: ${cmds}"
@@ -129,7 +128,7 @@ private Map parseCatchAllMessage(String description) {
private boolean shouldProcessMessage(cluster) {
// 0x0B is default response indicating message got through
// 0x07 is bind message
boolean ignoredMessage = cluster.profileId != 0x0104 ||
boolean ignoredMessage = cluster.profileId != 0x0104 ||
cluster.command == 0x0B ||
cluster.command == 0x07 ||
(cluster.data.size() > 0 && cluster.data.first() == 0x3e)
@@ -142,7 +141,7 @@ private Map parseReportAttributeMessage(String description) {
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)
@@ -154,11 +153,11 @@ private Map parseReportAttributeMessage(String description) {
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: ')) {
@@ -169,8 +168,44 @@ private Map parseCustomMessage(String description) {
}
private Map parseIasMessage(String description) {
ZoneStatus zs = zigbee.parseZoneStatus(description)
return (zs.isAlarm1Set() || zs.isAlarm2Set()) ? getMotionResult('active') : getMotionResult('inactive')
List parsedMsg = description.split(' ')
String msgCode = parsedMsg[2]
Map resultMap = [:]
switch(msgCode) {
case '0x0020': // Closed/No Motion/Dry
resultMap = getMotionResult('inactive')
break
case '0x0021': // Open/Motion/Wet
resultMap = getMotionResult('active')
break
case '0x0022': // Tamper Alarm
log.debug 'motion with tamper alarm'
resultMap = getMotionResult('active')
break
case '0x0023': // Battery Alarm
break
case '0x0024': // Supervision Report
log.debug 'no motion with tamper alarm'
resultMap = getMotionResult('inactive')
break
case '0x0025': // Restore Report
break
case '0x0026': // Trouble/Failure
log.debug 'motion with failure alarm'
resultMap = getMotionResult('active')
break
case '0x0028': // Test Mode
break
}
return resultMap
}
def getTemperature(value) {
@@ -205,10 +240,7 @@ private Map getBatteryResult(rawValue) {
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.value = Math.min(100, roundedPct)
result.value = Math.min(100, (int) pct * 100)
result.descriptionText = "${linkText} battery was ${result.value}%"
}
}
@@ -228,8 +260,7 @@ private Map getTemperatureResult(value) {
return [
name: 'temperature',
value: value,
descriptionText: descriptionText,
unit: temperatureScale
descriptionText: descriptionText
]
}

View File

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

View File

@@ -1,45 +0,0 @@
# Smartsense Multi Sensor
Works with:
* [Samsung SmartThings Multi Sensor](https://shop.smartthings.com/#!/products/smartsense-multi)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Battery](#battery-specification)
## Capabilities
* **Three Axis** - monitors the state of a single axis
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
* **Battery** - defines device uses a battery
* **Sensor** - detects sensor events
* **Contact Sensor** - can detect contact (possible values: open,closed)
* **Acceleration Sensor** - allows for acceleration detection.
* **Refresh** - _refresh()_ command for status updates
* **Temperature Measurement** - defines device measures current temperature
* **Health Check** - indicates ability to get device health notifications
## Device Health
A Category C2 multi sensor with maxReportTime of 5 mins.
Check-in interval is double the value of maxReportTime.
This gives the device twice the amount of time to respond before it is marked as offline.
Check-in interval = 12 mins
## Battery Specification
One CR2450 (for Samsung SmartThings Multipurpose Sensor) battery / Two AAAA (for SmartSense Multi Sensor) batteries required.
## Troubleshooting
If the sensor doesn't pair when trying from the SmartThings mobile app, it is possible that the sensor is out of range.
Pairing needs to be tried again by placing the sensor closer to the hub.
Other troubleshooting tips are listed as follows:
* [Troubleshooting: Samsung SmartThings Multipurpose Sensor is stuck on "open" or "closed"](https://support.smartthings.com/hc/en-us/articles/200955940-Troubleshooting-Samsung-SmartThings-Multipurpose-Sensor-is-stuck-on-open-or-closed-)
* [Troubleshooting: Temperature reading for the Samsung SmartThings Multipurpose Sensor is off](https://support.smartthings.com/hc/en-us/articles/200756845-Troubleshooting-Temperature-reading-for-the-Samsung-SmartThings-Multipurpose-Sensor-is-off)
* [Troubleshooting: Samsung SmartThings Multipurpose Sensor wont pair after removing pull-tab](https://support.smartthings.com/hc/en-us/articles/204966616-Troubleshooting-Samsung-SmartThings-device-won-t-pair-after-removing-pull-tab)

View File

@@ -1,3 +1,4 @@
#==============================================================================
# Copyright 2016 SmartThings
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
@@ -11,6 +12,14 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#==============================================================================
# Purpose: SmartSense Multi Sensor i18n Translation File
#
# Filename: SmartSense-Multi-Sensor.src/i18n/messages.properties
#
# Change History:
# 1. 20160117 TW Initial release with informal Korean translation.
#==============================================================================
# Korean (ko)
# Device Preferences
'''Yes'''.ko=

View File

@@ -1,4 +1,5 @@
/*
===============================================================================
* Copyright 2016 SmartThings
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
@@ -12,11 +13,19 @@
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
===============================================================================
* Purpose: SmartSense Multi Sensor DTH File
*
* Filename: SmartSense-Multi-Sensor.src/SmartSense-Multi-Sensor.groovy
*
* Change History:
* 1. 20160117 TW - Update/Edit to support i18n translations
* 2. 20160125 TW = Incorporated new battery mapping from TM
===============================================================================
*/
import physicalgraph.zigbee.clusters.iaszone.ZoneStatus
metadata {
definition (name: "SmartSense Multi Sensor", namespace: "smartthings", author: "SmartThings", category: "C2") {
definition (name: "SmartSense Multi Sensor", namespace: "smartthings", author: "SmartThings") {
capability "Three Axis"
capability "Battery"
@@ -225,13 +234,47 @@ private Map parseCustomMessage(String description) {
}
private Map parseIasMessage(String description) {
ZoneStatus zs = zigbee.parseZoneStatus(description)
List parsedMsg = description.split(' ')
String msgCode = parsedMsg[2]
Map resultMap = [:]
switch(msgCode) {
case '0x0020': // Closed/No Motion/Dry
if (garageSensor != "Yes"){
resultMap = zs.isAlarm1Set() ? getContactResult('open') : getContactResult('closed')
resultMap = getContactResult('closed')
}
break
case '0x0021': // Open/Motion/Wet
if (garageSensor != "Yes"){
resultMap = getContactResult('open')
}
break
case '0x0022': // Tamper Alarm
break
case '0x0023': // Battery Alarm
break
case '0x0024': // Supervision Report
if (garageSensor != "Yes"){
resultMap = getContactResult('closed')
}
break
case '0x0025': // Restore Report
if (garageSensor != "Yes"){
resultMap = getContactResult('open')
}
break
case '0x0026': // Trouble/Failure
break
case '0x0028': // Test Mode
break
}
return resultMap
}
@@ -261,9 +304,9 @@ def updated() {
def getTemperature(value) {
def celsius = Integer.parseInt(value, 16).shortValue() / 100
if(getTemperatureScale() == "C"){
return Math.round(celsius)
return celsius
} else {
return Math.round(celsiusToFahrenheit(celsius))
return celsiusToFahrenheit(celsius) as Integer
}
}
@@ -305,10 +348,7 @@ private Map getBatteryResult(rawValue) {
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.value = Math.min(100, roundedPct)
result.value = Math.min(100, (int) pct * 100)
result.descriptionText = "{{ device.displayName }} battery was {{ value }}%"
}
}
@@ -328,11 +368,10 @@ private Map getTemperatureResult(value) {
'{{ device.displayName }} was {{ value }}°F'
return [
name: 'temperature',
value: value,
descriptionText: descriptionText,
translatable: true,
unit: temperatureScale
name: 'temperature',
value: value,
descriptionText: descriptionText,
translatable: true
]
}
@@ -367,13 +406,6 @@ private getAccelerationResult(numValue) {
]
}
/**
* 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 "
@@ -381,40 +413,76 @@ def refresh() {
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])
refreshCmds = refreshCmds + [
/* These values of Motion Threshold Multiplier(01) and Motion Threshold (7602)
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.
*/
"zcl mfg-code ${manufacturerCode}", "delay 200",
"zcl global write 0xFC02 0 0x20 {01}", "delay 200",
"send 0x${device.deviceNetworkId} 1 1", "delay 400",
"zcl mfg-code ${manufacturerCode}", "delay 200",
"zcl global write 0xFC02 2 0x21 {7602}", "delay 200",
"send 0x${device.deviceNetworkId} 1 1", "delay 400",
]
} else {
refreshCmds += zigbee.writeAttribute(0xFC02, 0x0000, 0x20, 0x02, [mfgCode: manufacturerCode])
refreshCmds = refreshCmds + [
/* sensitivity - default value (8) */
"zcl mfg-code ${manufacturerCode}", "delay 200",
"zcl global write 0xFC02 0 0x20 {02}", "delay 200",
"send 0x${device.deviceNetworkId} 1 1", "delay 400",
]
}
//Common refresh commands
refreshCmds += zigbee.readAttribute(0x0402, 0x0000) +
zigbee.readAttribute(0x0001, 0x0020) +
zigbee.readAttribute(0xFC02, 0x0010, [mfgCode: manufacturerCode])
refreshCmds = refreshCmds + [
"st rattr 0x${device.deviceNetworkId} 1 0x402 0", "delay 200",
"st rattr 0x${device.deviceNetworkId} 1 1 0x20", "delay 200",
"zcl mfg-code ${manufacturerCode}", "delay 200",
"zcl global read 0xFC02 0x0010",
"send 0x${device.deviceNetworkId} 1 1","delay 400"
]
return refreshCmds + enrollResponse()
}
def configure() {
// Device-Watch allows 2 check-in misses from device
sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
String zigbeeEui = swapEndianHex(device.hub.zigbeeEui)
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 = enrollResponse() +
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])
def configCmds = [
"zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}", "delay 200",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
"zdo bind 0x${device.deviceNetworkId} ${endpointId} 1 1 {${device.zigbeeId}} {}", "delay 200",
"zcl global send-me-a-report 1 0x20 0x20 30 21600 {01}", "delay 200", //checkin time 6 hrs
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
"zdo bind 0x${device.deviceNetworkId} ${endpointId} 1 0x402 {${device.zigbeeId}} {}", "delay 200",
"zcl global send-me-a-report 0x402 0 0x29 30 3600 {6400}", "delay 200",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
"zdo bind 0x${device.deviceNetworkId} ${endpointId} 1 0xFC02 {${device.zigbeeId}} {}", "delay 200",
"zcl mfg-code ${manufacturerCode}", "delay 200",
"zcl global send-me-a-report 0xFC02 0x0010 0x18 10 3600 {01}", "delay 200",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
"zcl mfg-code ${manufacturerCode}", "delay 200",
"zcl global send-me-a-report 0xFC02 0x0012 0x29 1 3600 {0100}", "delay 200",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
"zcl mfg-code ${manufacturerCode}", "delay 200",
"zcl global send-me-a-report 0xFC02 0x0013 0x29 1 3600 {0100}", "delay 200",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
"zcl mfg-code ${manufacturerCode}", "delay 200",
"zcl global send-me-a-report 0xFC02 0x0014 0x29 1 3600 {0100}", "delay 200",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500"
]
return configCmds + refresh()
}

View File

@@ -14,10 +14,9 @@
*
*/
//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") {
definition (name: "SmartSense Open/Closed Accelerometer Sensor", namespace: "smartthings", author: "SmartThings") {
capability "Battery"
capability "Configuration"
capability "Contact Sensor"
@@ -25,7 +24,6 @@ import physicalgraph.zigbee.clusters.iaszone.ZoneStatus
capability "Refresh"
capability "Temperature Measurement"
capability "Health Check"
capability "Sensor"
command "enrollResponse"
}
@@ -173,9 +171,40 @@ private Map parseCustomMessage(String description) {
}
private Map parseIasMessage(String description) {
ZoneStatus zs = zigbee.parseZoneStatus(description)
List parsedMsg = description.split(' ')
String msgCode = parsedMsg[2]
return zs.isAlarm1Set() ? getContactResult('open') : getContactResult('closed')
Map resultMap = [:]
switch(msgCode) {
case '0x0020': // Closed/No Motion/Dry
resultMap = getContactResult('closed')
break
case '0x0021': // Open/Motion/Wet
resultMap = getContactResult('open')
break
case '0x0022': // Tamper Alarm
break
case '0x0023': // Battery Alarm
break
case '0x0024': // Supervision Report
resultMap = getContactResult('closed')
break
case '0x0025': // Restore Report
resultMap = getContactResult('open')
break
case '0x0026': // Trouble/Failure
break
case '0x0028': // Test Mode
break
}
return resultMap
}
def getTemperature(value) {
@@ -205,10 +234,7 @@ def getTemperature(value) {
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.value = Math.min(100, roundedPct)
result.value = Math.min(100, (int) pct * 100)
result.descriptionText = "${linkText} battery was ${result.value}%"
}
@@ -225,10 +251,9 @@ def getTemperature(value) {
}
def descriptionText = "${linkText} was ${value}°${temperatureScale}"
return [
name: 'temperature',
value: value,
descriptionText: descriptionText,
unit: temperatureScale
name: 'temperature',
value: value,
descriptionText: descriptionText
]
}
@@ -275,7 +300,6 @@ def getTemperature(value) {
}
def configure() {
sendEvent(name: "checkInterval", value: 7200, displayed: false)
String zigbeeEui = swapEndianHex(device.hub.zigbeeEui)
log.debug "Configuring Reporting, IAS CIE, and Bindings."

View File

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

View File

@@ -1,41 +0,0 @@
# Smartsense Open/Closed Sensor
Works with:
* [Samsung SmartThings Open/Closed Sensor](https://shop.smartthings.com/#!/packs/smartsense-open-closed-sensor/)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Battery](#battery-specification)
## Capabilities
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
* **Battery** - defines device uses a battery
* **Contact Sensor** - can detect contact (possible values: open,closed)
* **Refresh** - _refresh()_ command for status updates
* **Temperature Measurement** - defines device measures current temperature
* **Health Check** - indicates ability to get device health notifications
* **Sensor** - detects sensor events
## Device Health
A Category C2 open/closed sensor with maxReportTime of 5 mins.
Check-in interval is double the value of maxReportTime.
This gives the device twice the amount of time to respond before it is marked as offline.
Check-in interval = 12 mins
## Battery Specification
One CR2 3V battery required.
## Troubleshooting
If the sensor doesn't pair when trying from the SmartThings mobile app, it is possible that the sensor is out of range.
Pairing needs to be tried again by placing the sensor closer to the hub.
Instructions related to pairing, resetting and removing the sensor from SmartThings can be found in the following link:
* [SmartSense Open/Closed Sensor Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/202836844-SmartSense-Open-Closed-Sensor)

View File

@@ -13,35 +13,32 @@
* for the specific language governing permissions and limitations under the License.
*
*/
import physicalgraph.zigbee.clusters.iaszone.ZoneStatus
metadata {
definition (name: "SmartSense Open/Closed Sensor", namespace: "smartthings", author: "SmartThings", category: "C2") {
definition (name: "SmartSense Open/Closed Sensor", namespace: "smartthings", author: "SmartThings") {
capability "Battery"
capability "Configuration"
capability "Contact Sensor"
capability "Refresh"
capability "Temperature Measurement"
capability "Health Check"
capability "Sensor"
command "enrollResponse"
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3300-S"
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3300"
fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3320-L", deviceJoinName: "Iris Contact Sensor"
}
simulator {
}
preferences {
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:"contact", type: "generic", width: 6, height: 4){
tileAttribute ("device.contact", key: "PRIMARY_CONTROL") {
@@ -74,10 +71,10 @@ metadata {
details(["contact","temperature","battery","refresh"])
}
}
def parse(String description) {
log.debug "description: $description"
Map map = [:]
if (description?.startsWith('catchall:')) {
map = parseCatchAllMessage(description)
@@ -91,10 +88,10 @@ def parse(String description) {
else if (description?.startsWith('zone status')) {
map = parseIasMessage(description)
}
log.debug "Parse returned $map"
def result = map ? createEvent(map) : null
if (description?.startsWith('enroll request')) {
List cmds = enrollResponse()
log.debug "enroll response: ${cmds}"
@@ -102,7 +99,7 @@ def parse(String description) {
}
return result
}
private Map parseCatchAllMessage(String description) {
Map resultMap = [:]
def cluster = zigbee.parse(description)
@@ -128,7 +125,7 @@ private Map parseCatchAllMessage(String description) {
private boolean shouldProcessMessage(cluster) {
// 0x0B is default response indicating message got through
// 0x07 is bind message
boolean ignoredMessage = cluster.profileId != 0x0104 ||
boolean ignoredMessage = cluster.profileId != 0x0104 ||
cluster.command == 0x0B ||
cluster.command == 0x07 ||
(cluster.data.size() > 0 && cluster.data.first() == 0x3e)
@@ -138,14 +135,14 @@ private boolean shouldProcessMessage(cluster) {
private int getHumidity(value) {
return Math.round(Double.parseDouble(value))
}
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)
@@ -154,10 +151,10 @@ private Map parseReportAttributeMessage(String description) {
else if (descMap.cluster == "0001" && descMap.attrId == "0020") {
resultMap = getBatteryResult(Integer.parseInt(descMap.value, 16))
}
return resultMap
}
private Map parseCustomMessage(String description) {
Map resultMap = [:]
if (description?.startsWith('temperature: ')) {
@@ -168,10 +165,42 @@ private Map parseCustomMessage(String description) {
}
private Map parseIasMessage(String description) {
ZoneStatus zs = zigbee.parseZoneStatus(description)
return zs.isAlarm1Set() ? getContactResult('open') : getContactResult('closed')
}
List parsedMsg = description.split(' ')
String msgCode = parsedMsg[2]
Map resultMap = [:]
switch(msgCode) {
case '0x0020': // Closed/No Motion/Dry
resultMap = getContactResult('closed')
break
case '0x0021': // Open/Motion/Wet
resultMap = getContactResult('open')
break
case '0x0022': // Tamper Alarm
break
case '0x0023': // Battery Alarm
break
case '0x0024': // Supervision Report
resultMap = getContactResult('closed')
break
case '0x0025': // Restore Report
resultMap = getContactResult('open')
break
case '0x0026': // Trouble/Failure
break
case '0x0028': // Test Mode
break
}
return resultMap
}
def getTemperature(value) {
def celsius = Integer.parseInt(value, 16).shortValue() / 100
if(getTemperatureScale() == "C"){
@@ -184,11 +213,11 @@ def getTemperature(value) {
private Map getBatteryResult(rawValue) {
log.debug 'Battery'
def linkText = getLinkText(device)
def result = [
name: 'battery'
]
def volts = rawValue / 10
def descriptionText
if (rawValue == 0 || rawValue == 255) {}
@@ -199,10 +228,7 @@ private Map getBatteryResult(rawValue) {
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.value = Math.min(100, roundedPct)
result.value = Math.min(100, (int) pct * 100)
result.descriptionText = "${linkText} battery was ${result.value}%"
}
@@ -221,8 +247,7 @@ private Map getTemperatureResult(value) {
return [
name: 'temperature',
value: value,
descriptionText: descriptionText,
unit: temperatureScale
descriptionText: descriptionText
]
}
@@ -237,13 +262,6 @@ private Map getContactResult(value) {
]
}
/**
* 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 Temperature and Battery"
def refreshCmds = [
@@ -255,19 +273,22 @@ def refresh() {
}
def configure() {
// Device-Watch allows 2 check-in misses from device
sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
String zigbeeEui = swapEndianHex(device.hub.zigbeeEui)
log.debug "Configuring Reporting, IAS CIE, and Bindings."
def enrollCmds = [
def configCmds = [
"zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}", "delay 200",
"send 0x${device.deviceNetworkId} 1 1", "delay 500",
]
// temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity
// battery minReport 30 seconds, maxReportTime 6 hrs by default
return enrollCmds + zigbee.batteryConfig() + zigbee.temperatureConfig(30, 300) + refresh() // send refresh cmds as part of config
"zdo bind 0x${device.deviceNetworkId} ${endpointId} 1 1 {${device.zigbeeId}} {}", "delay 500",
"zcl global send-me-a-report 1 0x20 0x20 30 21600 {01}", //checkin time 6 hrs
"send 0x${device.deviceNetworkId} 1 1", "delay 500",
"zdo bind 0x${device.deviceNetworkId} ${endpointId} 1 0x402 {${device.zigbeeId}} {}", "delay 500",
"zcl global send-me-a-report 0x402 0 0x29 30 3600 {6400}",
"send 0x${device.deviceNetworkId} 1 1", "delay 500"
]
return configCmds + refresh() // send refresh cmds as part of config
}
def enrollResponse() {

View File

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

View File

@@ -1,41 +0,0 @@
# SmartSense Temp/Humidity Sensor
Works with:
* [Samsung SmartSense Temp/Humidity Sensor](https://shop.smartthings.com/#!/products/smartsense-temp-humidity-sensor)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Battery](#battery-specification)
## Capabilities
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
* **Battery** - defines device uses a battery
* **Relative Humidity Measurement** - defines device measures relative humidity
* **Refresh** - _refresh()_ command for status updates
* **Temperature Measurement** - defines device measures current temperature
* **Health Check** - indicates ability to get device health notifications
* **Sensor** - detects sensor events
## Device Health
A Category C2 SmartSense Temp/Humidity Sensor with maxReportTime of 5 mins.
Check-in interval is double the value of maxReportTime.
This gives the device twice the amount of time to respond before it is marked as offline.
Check-in interval = 12 mins
## Battery Specification
One CR2 battery is required.
## Troubleshooting
If the sensor doesn't pair when trying from the SmartThings mobile app, it is possible that the sensor is out of range.
Pairing needs to be tried by placing the sensor closer to the hub.
Instructions related to pairing, resetting and removing the sensor from SmartThings can be found in the following link:
* [Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/203040294)

View File

@@ -14,14 +14,13 @@
*
*/
metadata {
definition (name: "SmartSense Temp/Humidity Sensor",namespace: "smartthings", author: "SmartThings", category: "C2") {
definition (name: "SmartSense Temp/Humidity Sensor",namespace: "smartthings", author: "SmartThings") {
capability "Configuration"
capability "Battery"
capability "Refresh"
capability "Temperature Measurement"
capability "Relative Humidity Measurement"
capability "Health Check"
capability "Sensor"
fingerprint endpointId: "01", inClusters: "0001,0003,0020,0402,0B05,FC45", outClusters: "0019,0003"
}
@@ -206,10 +205,7 @@ private Map getBatteryResult(rawValue) {
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.value = Math.min(100, roundedPct)
result.value = Math.min(100, (int) pct * 100)
result.descriptionText = "${linkText} battery was ${result.value}%"
}
@@ -228,8 +224,7 @@ private Map getTemperatureResult(value) {
return [
name: 'temperature',
value: value,
descriptionText: descriptionText,
unit: temperatureScale
descriptionText: descriptionText
]
}
@@ -242,13 +237,6 @@ private Map getHumidityResult(value) {
]
}
/**
* 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 temperature, humidity, and battery"
@@ -264,19 +252,22 @@ def refresh()
}
def configure() {
// Device-Watch allows 2 check-in misses from device
sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
log.debug "Configuring Reporting and Bindings."
def humidityConfigCmds = [
def configCmds = [
"zdo bind 0x${device.deviceNetworkId} 1 1 1 {${device.zigbeeId}} {}", "delay 500",
"zcl global send-me-a-report 1 0x20 0x20 30 21600 {01}", //checkin time 6 hrs
"send 0x${device.deviceNetworkId} 1 1", "delay 500",
"zdo bind 0x${device.deviceNetworkId} 1 1 0x402 {${device.zigbeeId}} {}", "delay 500",
"zcl global send-me-a-report 0x402 0 0x29 30 3600 {6400}",
"send 0x${device.deviceNetworkId} 1 1", "delay 500",
"zdo bind 0x${device.deviceNetworkId} 1 1 0xFC45 {${device.zigbeeId}} {}", "delay 500",
"zcl global send-me-a-report 0xFC45 0 0x29 30 3600 {6400}",
"send 0x${device.deviceNetworkId} 1 1", "delay 500"
]
// temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity
// battery minReport 30 seconds, maxReportTime 6 hrs by default
return humidityConfigCmds + zigbee.batteryConfig() + zigbee.temperatureConfig(30, 300) + refresh() // send refresh cmds as part of config
return configCmds + refresh() // send refresh cmds as part of config
}
private hex(value) {

View File

@@ -16,8 +16,6 @@
metadata {
definition (name: "Simulated Alarm", namespace: "smartthings/testing", author: "SmartThings") {
capability "Alarm"
capability "Sensor"
capability "Actuator"
}
simulator {

View File

@@ -1,8 +1,6 @@
metadata {
definition (name: "Simulated Color Control", namespace: "smartthings/testing", author: "SmartThings") {
capability "Color Control"
capability "Sensor"
capability "Actuator"
}
simulator {

View File

@@ -15,7 +15,6 @@ metadata {
// Automatically generated. Make future change here.
definition (name: "Simulated Contact Sensor", namespace: "smartthings/testing", author: "bob") {
capability "Contact Sensor"
capability "Sensor"
command "open"
command "close"

View File

@@ -15,8 +15,6 @@ metadata {
// Automatically generated. Make future change here.
definition (name: "Simulated Lock", namespace: "smartthings/testing", author: "bob") {
capability "Lock"
capability "Sensor"
capability "Actuator"
}
// Simulated lock

View File

@@ -15,7 +15,6 @@ metadata {
// Automatically generated. Make future change here.
definition (name: "Simulated Motion Sensor", namespace: "smartthings/testing", author: "bob") {
capability "Motion Sensor"
capability "Sensor"
command "active"
command "inactive"

View File

@@ -15,7 +15,6 @@ metadata {
// Automatically generated. Make future change here.
definition (name: "Simulated Presence Sensor", namespace: "smartthings/testing", author: "bob") {
capability "Presence Sensor"
capability "Sensor"
command "arrived"
command "departed"

View File

@@ -16,8 +16,6 @@ metadata {
definition (name: "Simulated Switch", namespace: "smartthings/testing", author: "bob") {
capability "Switch"
capability "Relay Switch"
capability "Sensor"
capability "Actuator"
command "onPhysical"
command "offPhysical"

View File

@@ -16,7 +16,6 @@ metadata {
definition (name: "Simulated Temperature Sensor", namespace: "smartthings/testing", author: "SmartThings") {
capability "Temperature Measurement"
capability "Switch Level"
capability "Sensor"
command "up"
command "down"

View File

@@ -16,8 +16,6 @@ metadata {
definition (name: "Simulated Thermostat", namespace: "smartthings/testing", author: "SmartThings") {
capability "Thermostat"
capability "Relative Humidity Measurement"
capability "Sensor"
capability "Actuator"
command "tempUp"
command "tempDown"

View File

@@ -15,7 +15,6 @@ metadata {
// Automatically generated. Make future change here.
definition (name: "Simulated Water Sensor", namespace: "smartthings/testing", author: "SmartThings") {
capability "Water Sensor"
capability "Sensor"
command "wet"
command "dry"

View File

@@ -1,42 +0,0 @@
# Device Tiles Examples and Reference
This package contains examples of Device tiles, organized by tile type.
## Purpose
Each Device Handler shows example usages of a specific tile, and is meant to represent the variety of permutations that a tile can be configured.
The various tiles can be used by QA to test tiles on all supported mobile devices, and by developers as a reference implementation.
## Installation
1. Self-publish the Device Handlers in this package.
2. Self-publish the Device Tile Controller SmartApp. The SmartApp can be found [here](https://github.com/SmartThingsCommunity/SmartThingsPublic/blob/master/smartapps/smartthings/tile-ux/device-tile-controller.src/device-tile-controller.groovy).
3. Install the SmartApp from the Marketplace, under "My Apps".
4. Select the simulated devices you want to install and press "Done".
The simulated devices can then be found in the "Things" view of "My Home" in the mobile app.
You may wish to create a new room for these simulated devices for easy access.
## Usage
Each simulated device can be interacted with like other devices.
You can use the mobile app to interact with the tiles to see how they look and behave.
## Troubleshooting
If you get an error when installing the simulated devices using the controller SmartApp, ensure that you have published all the Device Handlers for yourself.
Also check live logging to see if there is a specific tile that is causing installation issues.
## FAQ
*Question: A tile isn't behaving as expected. What should I do?*
QA should create a JIRA ticket for any issues or inconsistencies of tiles across devices.
Developers may file a support ticket, and reference the specific tile and issue observed.
*Question: I'd like to contribute an example tile usage that would be helpful for testing and reference purposes. Can I do that?*
We recommend that you open an issue in the SmartThingsPublic repository describing the example tile and usage.
That way we can discuss with you the proposed change, and then if appropriate you can create a PR associated to the issue.

View File

@@ -22,7 +22,7 @@ metadata {
tiles(scale: 2) {
valueTile("currentColor", "device.color") {
state "color", label: '${currentValue}', defaultState: true
state "default", label: '${currentValue}'
}
controlTile("rgbSelector", "device.color", "color", height: 6, width: 6, inactiveLabel: false) {
@@ -41,13 +41,6 @@ def parse(String description) {
log.debug "Parsing '${description}'"
}
def setColor(value) {
log.debug "setting color: $value"
if (value.hex) { sendEvent(name: "color", value: value.hex) }
if (value.hue) { sendEvent(name: "hue", value: value.hue) }
if (value.saturation) { sendEvent(name: "saturation", value: value.saturation) }
}
def setSaturation(percent) {
log.debug "Executing 'setSaturation'"
sendEvent(name: "saturation", value: percent)

View File

@@ -39,7 +39,7 @@ metadata {
}
valueTile("rangeValue", "device.rangedLevel", height: 2, width: 2) {
state "range", label:'${currentValue}', defaultState: true
state "default", label:'${currentValue}'
}
controlTile("rangeSliderConstrained", "device.rangedLevel", "slider", height: 2, width: 4, range: "(40..60)") {

View File

@@ -41,17 +41,17 @@ metadata {
// standard flat tile with only a label
standardTile("flatLabel", "device.switch", width: 2, height: 2, decoration: "flat") {
state "label", label: 'On Action', action: "switch.on", backgroundColor: "#ffffff", defaultState: true
state "default", label: 'On Action', action: "switch.on", backgroundColor: "#ffffff"
}
// standard flat tile with icon and label
standardTile("flatIconLabel", "device.switch", width: 2, height: 2, decoration: "flat") {
state "iconLabel", label: 'Off Action', action: "switch.off", icon:"st.switches.switch.off", backgroundColor: "#ffffff", defaultState: true
state "default", label: 'Off Action', action: "switch.off", icon:"st.switches.switch.off", backgroundColor: "#ffffff"
}
// standard flat tile with only icon (Refreh text is IN the icon file)
standardTile("flatIcon", "device.switch", width: 2, height: 2, decoration: "flat") {
state "icon", action:"refresh.refresh", icon:"st.secondary.refresh", defaultState: true
state "default", action:"refresh.refresh", icon:"st.secondary.refresh"
}
// standard with defaultState = true
@@ -74,19 +74,19 @@ metadata {
// utility tiles to fill the spaces
standardTile("empty2x2", "null", width: 2, height: 2, decoration: "flat") {
state "emptySmall", label:'', defaultState: true
state "default", label:''
}
standardTile("empty4x2", "null", width: 4, height: 2, decoration: "flat") {
state "emptyBigger", label:'', defaultState: true
state "default", label:''
}
// multi-line text (explicit newlines)
standardTile("multiLine", "device.multiLine", width: 2, height: 2) {
state "multiLine", label: '${currentValue}', defaultState: true
state "default", label: '${currentValue}'
}
standardTile("multiLineWithIcon", "device.multiLine", width: 2, height: 2) {
state "multiLineIcon", label: '${currentValue}', icon: "st.switches.switch.off", defaultState: true
state "default", label: '${currentValue}', icon: "st.switches.switch.off"
}
main("actionRings")

View File

@@ -22,68 +22,68 @@ metadata {
tiles(scale: 2) {
valueTile("text", "device.text", width: 2, height: 2) {
state "val", label:'${currentValue}', defaultState: true
state "default", label:'${currentValue}'
}
valueTile("longText", "device.longText", width: 2, height: 2) {
state "val", label:'${currentValue}', defaultState: true
state "default", label:'${currentValue}'
}
valueTile("integer", "device.integer", width: 2, height: 2) {
state "val", label:'${currentValue}', defaultState: true
state "default", label:'${currentValue}'
}
valueTile("integerFloat", "device.integerFloat", width: 2, height: 2) {
state "val", label:'${currentValue}', defaultState: true
state "default", label:'${currentValue}'
}
valueTile("pi", "device.pi", width: 2, height: 2) {
state "val", label:'${currentValue}', defaultState: true
state "default", label:'${currentValue}'
}
valueTile("floatAsText", "device.floatAsText", width: 2, height: 2) {
state "val", label:'${currentValue}', defaultState: true
state "default", label:'${currentValue}'
}
valueTile("bgColor", "device.integer", width: 2, height: 2) {
state "val", label:'${currentValue}', backgroundColor: "#e86d13", defaultState: true
state "default", label:'${currentValue}', backgroundColor: "#e86d13"
}
valueTile("bgColorRange", "device.integer", width: 2, height: 2) {
state "val", label:'${currentValue}', defaultState: true, backgroundColors: [
state "default", label:'${currentValue}', backgroundColors: [
[value: 10, color: "#ff0000"],
[value: 90, color: "#0000ff"]
]
}
valueTile("bgColorRangeSingleItem", "device.integer", width: 2, height: 2) {
state "val", label:'${currentValue}', defaultState: true, backgroundColors: [
state "default", label:'${currentValue}', backgroundColors: [
[value: 10, color: "#333333"]
]
}
valueTile("bgColorRangeConflict", "device.integer", width: 2, height: 2) {
state "valWithConflict", label:'${currentValue}', defaultState: true, backgroundColors: [
state "default", label:'${currentValue}', backgroundColors: [
[value: 10, color: "#990000"],
[value: 10, color: "#000099"]
]
}
valueTile("noValue", "device.nada", width: 4, height: 2) {
state "noval", label:'${currentValue}', defaultState: true
state "default", label:'${currentValue}'
}
valueTile("multiLine", "device.multiLine", width: 3, height: 2) {
state "val", label: '${currentValue}', defaultState: true
state "default", label: '${currentValue}'
}
valueTile("multiLineWithIcon", "device.multiLine", width: 3, height: 2) {
state "val", label: '${currentValue}', icon: "st.switches.switch.off", defaultState: true
state "default", label: '${currentValue}', icon: "st.switches.switch.off"
}
main("text")
details([
"text", "longText", "integer",
"text", "longText", "integer",
"integerFloat", "pi", "floatAsText",
"bgColor", "bgColorRange", "bgColorRangeSingleItem",
"bgColorRangeConflict", "noValue",

View File

@@ -39,15 +39,15 @@ metadata {
attributeState "turningOff", label:'${name}', backgroundColor:"#ffffff", nextState:"turningOn"
}
tileAttribute("device.level", key: "SECONDARY_CONTROL") {
attributeState "level", icon: 'st.Weather.weather1', action:"randomizeLevel", defaultState: true
attributeState "default", icon: 'st.Weather.weather1', action:"randomizeLevel"
}
tileAttribute("device.level", key: "SLIDER_CONTROL") {
attributeState "level", action:"switch level.setLevel", defaultState: true
attributeState "default", action:"switch level.setLevel"
}
}
multiAttributeTile(name:"valueTile", type:"generic", width:6, height:4) {
tileAttribute("device.level", key: "PRIMARY_CONTROL") {
attributeState "level", label:'${currentValue}', defaultState: true, backgroundColors:[
attributeState "default", label:'${currentValue}', backgroundColors:[
[value: 0, color: "#ff0000"],
[value: 20, color: "#ffff00"],
[value: 40, color: "#00ff00"],
@@ -69,34 +69,34 @@ metadata {
}
multiAttributeTile(name:"lengthyTile", type:"generic", width:6, height:4) {
tileAttribute("device.lengthyText", key: "PRIMARY_CONTROL") {
attributeState "lengthyText", label:'The value of this tile is long and should wrap to two lines', backgroundColor:"#79b821", defaultState: true
attributeState "default", label:'The value of this tile is long and should wrap to two lines', backgroundColor:"#79b821"
}
tileAttribute("device.lengthyText", key: "SECONDARY_CONTROL") {
attributeState "lengthyText", label:'The value of this tile is long and should wrap to two lines', backgroundColor:"#79b821", defaultState: true
attributeState "default", label:'The value of this tile is long and should wrap to two lines', backgroundColor:"#79b821"
}
}
multiAttributeTile(name:"multilineTile", type:"generic", width:6, height:4) {
tileAttribute("device.multilineText", key: "PRIMARY_CONTROL") {
attributeState "multiLineText", label:'Line 1 YES\nLine 2 YES\nLine 3 NO', backgroundColor:"#79b821", defaultState: true
attributeState "default", label:'Line 1 YES\nLine 2 YES\nLine 3 NO', backgroundColor:"#79b821"
}
tileAttribute("device.multilineText", key: "SECONDARY_CONTROL") {
attributeState "multiLineText", label:'Line 1 YES\nLine 2 YES\nLine 3 NO', backgroundColor:"#79b821", defaultState: true
attributeState "default", label:'Line 1 YES\nLine 2 YES\nLine 3 NO', backgroundColor:"#79b821"
}
}
multiAttributeTile(name:"lengthyTileWithIcon", type:"generic", width:6, height:4) {
tileAttribute("device.lengthyText", key: "PRIMARY_CONTROL") {
attributeState "lengthyText", label:'The value of this tile is long and should wrap to two lines', backgroundColor:"#79b821", icon: "st.switches.switch.on", defaultState: true
attributeState "default", label:'The value of this tile is long and should wrap to two lines', backgroundColor:"#79b821", icon: "st.switches.switch.on"
}
tileAttribute("device.lengthyText", key: "SECONDARY_CONTROL") {
attributeState "lengthyText", label:'The value of this tile is long and should wrap to two lines', backgroundColor:"#79b821", icon: "st.switches.switch.on", defaultState: true
attributeState "default", label:'The value of this tile is long and should wrap to two lines', backgroundColor:"#79b821", icon: "st.switches.switch.on"
}
}
multiAttributeTile(name:"multilineTileWithIcon", type:"generic", width:6, height:4) {
tileAttribute("device.multilineText", key: "PRIMARY_CONTROL") {
attributeState "multilineText", label:'Line 1 YES\nLine 2 YES\nLine 3 NO', backgroundColor:"#79b821", icon: "st.switches.switch.on", defaultState: true
attributeState "default", label:'Line 1 YES\nLine 2 YES\nLine 3 NO', backgroundColor:"#79b821", icon: "st.switches.switch.on"
}
tileAttribute("device.multilineText", key: "SECONDARY_CONTROL") {
attributeState "multilineText", label:'Line 1 YES\nLine 2 YES\nLine 3 NO', backgroundColor:"#79b821", icon: "st.switches.switch.on", defaultState: true
attributeState "default", label:'Line 1 YES\nLine 2 YES\nLine 3 NO', backgroundColor:"#79b821", icon: "st.switches.switch.on"
}
}
@@ -110,7 +110,7 @@ def installed() {
sendEvent(name: "multilineText", value: "Line 1 YES\nLine 2 YES\nLine 3 NO")
}
def parse(String description) {
def parse() {
// This is a simulated device. No incoming data to parse.
}

View File

@@ -96,10 +96,10 @@ metadata {
}
standardTile("reset", "device.reset", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "reset", label:"Reset Color", action:"reset", icon:"st.lights.philips.hue-single", defaultState: true
state "default", label:"Reset Color", action:"reset", icon:"st.lights.philips.hue-single"
}
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "refresh", label:"", action:"refresh.refresh", icon:"st.secondary.refresh", defaultState: true
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
}
main(["switch"])
@@ -173,6 +173,7 @@ def setColor(value) {
def reset() {
log.debug "Executing 'reset'"
setAdjustedColor([level:100, hex:"#90C638", saturation:56, hue:23])
//parent.poll()
}
def setAdjustedColor(value) {
@@ -188,6 +189,7 @@ def setAdjustedColor(value) {
def refresh() {
log.debug "Executing 'refresh'"
//parent.manualRefresh()
}
def adjustOutgoingHue(percent) {
@@ -206,3 +208,4 @@ def adjustOutgoingHue(percent) {
log.info "percent: $percent, adjusted: $adjusted"
adjusted
}

View File

@@ -37,10 +37,10 @@ metadata {
attributeState("stopped", label:"Stopped", action:"music Player.play", nextState: "playing")
}
tileAttribute("device.status", key: "PREVIOUS_TRACK") {
attributeState("status", action:"music Player.previousTrack", defaultState: true)
attributeState("default", action:"music Player.previousTrack")
}
tileAttribute("device.status", key: "NEXT_TRACK") {
attributeState("status", action:"music Player.nextTrack", defaultState: true)
attributeState("default", action:"music Player.nextTrack")
}
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
attributeState("level", action:"music Player.setLevel")
@@ -50,7 +50,7 @@ metadata {
attributeState("muted", action:"music Player.unmute", nextState: "unmuted")
}
tileAttribute("device.trackDescription", key: "MARQUEE") {
attributeState("trackDescription", label:"${currentValue}", defaultState: true)
attributeState("default", label:"${currentValue}")
}
}

View File

@@ -32,14 +32,14 @@ metadata {
tiles(scale: 2) {
multiAttributeTile(name:"thermostatFull", type:"thermostat", width:6, height:4) {
tileAttribute("device.temperature", key: "PRIMARY_CONTROL") {
attributeState("temp", label:'${currentValue}', unit:"dF", defaultState: true)
attributeState("default", label:'${currentValue}', unit:"dF")
}
tileAttribute("device.temperature", key: "VALUE_CONTROL") {
attributeState("VALUE_UP", action: "tempUp")
attributeState("VALUE_DOWN", action: "tempDown")
}
tileAttribute("device.humidity", key: "SECONDARY_CONTROL") {
attributeState("humidity", label:'${currentValue}%', unit:"%", defaultState: true)
attributeState("default", label:'${currentValue}%', unit:"%")
}
tileAttribute("device.thermostatOperatingState", key: "OPERATING_STATE") {
attributeState("idle", backgroundColor:"#44b621")
@@ -53,16 +53,15 @@ metadata {
attributeState("auto", label:'${name}')
}
tileAttribute("device.heatingSetpoint", key: "HEATING_SETPOINT") {
attributeState("heatingSetpoint", label:'${currentValue}', unit:"dF", defaultState: true)
attributeState("default", label:'${currentValue}', unit:"dF")
}
tileAttribute("device.coolingSetpoint", key: "COOLING_SETPOINT") {
attributeState("coolingSetpoint", label:'${currentValue}', unit:"dF", defaultState: true)
attributeState("default", label:'${currentValue}', unit:"dF")
}
}
multiAttributeTile(name:"thermostatNoHumidity", type:"thermostat", width:6, height:4) {
tileAttribute("device.temperature", key: "PRIMARY_CONTROL") {
attributeState("coolingSetpoint", label:'${currentValue}', unit:"dF", defaultState: true)
attributeState("temp", label:'${currentValue}', unit:"dF")
attributeState("default", label:'${currentValue}', unit:"dF")
}
tileAttribute("device.temperature", key: "VALUE_CONTROL") {
attributeState("VALUE_UP", action: "tempUp")
@@ -80,16 +79,15 @@ metadata {
attributeState("auto", label:'${name}')
}
tileAttribute("device.heatingSetpoint", key: "HEATING_SETPOINT") {
attributeState("coolingSetpoint", label:'${currentValue}', unit:"dF", defaultState: true)
attributeState("heatingSetpoint", label:'${currentValue}', unit:"dF")
attributeState("default", label:'${currentValue}', unit:"dF")
}
tileAttribute("device.coolingSetpoint", key: "COOLING_SETPOINT") {
attributeState("coolingSetpoint", label:'${currentValue}', unit:"dF", defaultState: true)
attributeState("default", label:'${currentValue}', unit:"dF")
}
}
multiAttributeTile(name:"thermostatBasic", type:"thermostat", width:6, height:4) {
tileAttribute("device.temperature", key: "PRIMARY_CONTROL") {
attributeState("temp", label:'${currentValue}', unit:"dF", defaultState: true,
attributeState("default", label:'${currentValue}', unit:"dF",
backgroundColors:[
[value: 31, color: "#153591"],
[value: 44, color: "#1e9cbb"],
@@ -120,30 +118,30 @@ metadata {
)
}
standardTile("tempDown", "device.temperature", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
state "tempDown", label:'down', action:"tempDown", defaultState: true
state "default", label:'down', action:"tempDown"
}
standardTile("tempUp", "device.temperature", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
state "tempUp", label:'up', action:"tempUp", defaultState: true
state "default", label:'up', action:"tempUp"
}
valueTile("heatingSetpoint", "device.heatingSetpoint", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
state "heat", label:'${currentValue} heat', unit: "F", backgroundColor:"#ffffff"
}
standardTile("heatDown", "device.temperature", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
state "heatDown", label:'down', action:"heatDown", defaultState: true
state "default", label:'down', action:"heatDown"
}
standardTile("heatUp", "device.temperature", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
state "heatUp", label:'up', action:"heatUp", defaultState: true
state "default", label:'up', action:"heatUp"
}
valueTile("coolingSetpoint", "device.coolingSetpoint", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
state "cool", label:'${currentValue} cool', unit:"F", backgroundColor:"#ffffff"
}
standardTile("coolDown", "device.temperature", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
state "coolDown", label:'down', action:"coolDown", defaultState: true
state "default", label:'down', action:"coolDown"
}
standardTile("coolUp", "device.temperature", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
state "coolUp", label:'up', action:"coolUp", defaultState: true
state "default", label:'up', action:"coolUp"
}
standardTile("mode", "device.thermostatMode", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {

View File

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

View File

@@ -1,42 +0,0 @@
# Tyco Door Window Sensor
Works with:
* [Tyco Door Window Sensor](https://support.smartthings.com/hc/en-us/articles/204834100-Tyco-Door-Window-Sensor)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Battery](#battery-specification)
## Capabilities
* **Battery** - defines device uses a battery
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
* **Contact Sensor** - can detect contact (open/close)
* **Refresh** - _refresh()_ command for status updates
* **Temperature Measurement** - can measure the device temperature
* **Health Check** - indicates ability to get device health notifications
## Device Health
Contact sensor with maxReportTime of 5 mins.
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.
Check-in interval = 12 min
## Battery Specification
3V CR2032 battery is required.
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that either the sensor needs to be reseted or the sensor is out of range.
Reset needs to be done by inserting the battery in the sensor and then quickly pressing the adjacent black button 10 times. Pairing should be tried again now.
It may happen that sensor is out of range, then pairing needs to be tried again by placing the sensor closer to the hub.
Instructions related to pairing, resetting and removing the different motion sensors from SmartThings can be found in the following links
for the different models:
* [Tyco Door Window Sensor (MCT-340)](https://support.smartthings.com/hc/en-us/articles/204834100-Tyco-Door-Window-Sensor)

View File

@@ -13,38 +13,36 @@
* for the specific language governing permissions and limitations under the License.
*
*/
import physicalgraph.zigbee.clusters.iaszone.ZoneStatus
metadata {
definition (name: "Tyco Door/Window Sensor", namespace: "smartthings", author: "SmartThings", category: "C2") {
definition (name: "Tyco Door/Window Sensor", namespace: "smartthings", author: "SmartThings") {
capability "Battery"
capability "Configuration"
capability "Contact Sensor"
capability "Refresh"
capability "Temperature Measurement"
capability "Health Check"
command "enrollResponse"
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "Visonic", model: "MCT-340 SMA"
}
simulator {
}
preferences {
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 {
standardTile("contact", "device.contact", width: 2, height: 2) {
state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#79b821")
}
valueTile("temperature", "device.temperature", inactiveLabel: false) {
state "temperature", label:'${currentValue}°',
backgroundColors:[
@@ -60,23 +58,23 @@ metadata {
valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false) {
state "battery", label:'${currentValue}% battery', unit:""
}
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat") {
state "default", action:"refresh.refresh", icon:"st.secondary.refresh"
}
standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat") {
state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure"
}
main (["contact", "temperature"])
details(["contact","temperature","battery","refresh","configure"])
}
}
def parse(String description) {
log.debug "description: $description"
Map map = [:]
if (description?.startsWith('catchall:')) {
map = parseCatchAllMessage(description)
@@ -90,10 +88,10 @@ def parse(String description) {
else if (description?.startsWith('zone status')) {
map = parseIasMessage(description)
}
log.debug "Parse returned $map"
def result = map ? createEvent(map) : null
if (description?.startsWith('enroll request')) {
List cmds = enrollResponse()
log.debug "enroll response: ${cmds}"
@@ -101,7 +99,7 @@ def parse(String description) {
}
return result
}
private Map parseCatchAllMessage(String description) {
Map resultMap = [:]
def cluster = zigbee.parse(description)
@@ -127,20 +125,20 @@ private Map parseCatchAllMessage(String description) {
private boolean shouldProcessMessage(cluster) {
// 0x0B is default response indicating message got through
// 0x07 is bind message
boolean ignoredMessage = cluster.profileId != 0x0104 ||
boolean ignoredMessage = cluster.profileId != 0x0104 ||
cluster.command == 0x0B ||
cluster.command == 0x07 ||
(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)
@@ -149,10 +147,10 @@ private Map parseReportAttributeMessage(String description) {
else if (descMap.cluster == "0001" && descMap.attrId == "0020") {
resultMap = getBatteryResult(Integer.parseInt(descMap.value, 16))
}
return resultMap
}
private Map parseCustomMessage(String description) {
Map resultMap = [:]
if (description?.startsWith('temperature: ')) {
@@ -163,11 +161,42 @@ private Map parseCustomMessage(String description) {
}
private Map parseIasMessage(String description) {
ZoneStatus zs = zigbee.parseZoneStatus(description)
List parsedMsg = description.split(' ')
String msgCode = parsedMsg[2]
Map resultMap = [:]
switch(msgCode) {
case '0x0020': // Closed/No Motion/Dry
resultMap = getContactResult('closed')
break
return zs.isAlarm1Set() ? getContactResult('open') : getContactResult('closed')
case '0x0021': // Open/Motion/Wet
resultMap = getContactResult('open')
break
case '0x0022': // Tamper Alarm
break
case '0x0023': // Battery Alarm
break
case '0x0024': // Supervision Report
resultMap = getContactResult('closed')
break
case '0x0025': // Restore Report
resultMap = getContactResult('open')
break
case '0x0026': // Trouble/Failure
break
case '0x0028': // Test Mode
break
}
return resultMap
}
def getTemperature(value) {
def celsius = Integer.parseInt(value, 16).shortValue() / 100
if(getTemperatureScale() == "C"){
@@ -180,11 +209,11 @@ def getTemperature(value) {
private Map getBatteryResult(rawValue) {
log.debug 'Battery'
def linkText = getLinkText(device)
def result = [
name: 'battery'
]
def volts = rawValue / 10
def descriptionText
if (volts > 3.5) {
@@ -194,8 +223,7 @@ private Map getBatteryResult(rawValue) {
def minVolts = 2.1
def maxVolts = 3.0
def pct = (volts - minVolts) / (maxVolts - minVolts)
def roundedPct = Math.round(pct * 100)
result.value = Math.min(100, roundedPct)
result.value = Math.min(100, (int) pct * 100)
result.descriptionText = "${linkText} battery was ${result.value}%"
}
@@ -214,8 +242,7 @@ private Map getTemperatureResult(value) {
return [
name: 'temperature',
value: value,
descriptionText: descriptionText,
unit: temperatureScale
descriptionText: descriptionText
]
}
@@ -230,51 +257,53 @@ private Map getContactResult(value) {
]
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
return zigbee.readAttribute(0x0402, 0x0000) // Read the Temperature Cluster
}
def refresh()
{
log.debug "Refreshing Temperature and Battery"
def refreshCmds = [
[
"st rattr 0x${device.deviceNetworkId} 1 0x402 0", "delay 200",
"st rattr 0x${device.deviceNetworkId} 1 1 0x20"
]
return refreshCmds + enrollResponse()
}
def configure() {
// Device-Watch allows 2 check-in misses from device
sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
String zigbeeEui = swapEndianHex(device.hub.zigbeeEui)
log.debug "Configuring Reporting, IAS CIE, and Bindings."
def enrollCmds = [
def configCmds = [
"delay 1000",
"zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}", "delay 200",
"send 0x${device.deviceNetworkId} 1 1", "delay 1500",
"zcl global send-me-a-report 1 0x20 0x20 600 3600 {01}", "delay 200",
"send 0x${device.deviceNetworkId} 1 1", "delay 1500",
"zcl global send-me-a-report 0x402 0 0x29 300 3600 {6400}", "delay 200",
"send 0x${device.deviceNetworkId} 1 1", "delay 1500",
//"raw 0x500 {01 23 00 00 00}", "delay 200",
//"send 0x${device.deviceNetworkId} 1 1", "delay 1500",
"zdo bind 0x${device.deviceNetworkId} 1 1 0x402 {${device.zigbeeId}} {}", "delay 500",
"zdo bind 0x${device.deviceNetworkId} 1 1 1 {${device.zigbeeId}} {}",
"delay 500"
]
return enrollCmds + zigbee.batteryConfig() + zigbee.temperatureConfig(30, 300) + refresh() // send refresh cmds as part of config
return configCmds + enrollResponse() + refresh() // send refresh cmds as part of config
}
def enrollResponse() {
log.debug "Sending enroll response"
[
[
"raw 0x500 {01 23 00 00 00}", "delay 200",
"send 0x${device.deviceNetworkId} 1 1"
]
}
private hex(value) {

View File

@@ -1,7 +1,8 @@
/**
* ZigBee Button
* Iris Smart Fob
*
* Copyright 2015 Mitch Pond
* Presence code adapted from SmartThings Arrival Sensor HA device type
*
* 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:
@@ -13,235 +14,181 @@
* for the specific language governing permissions and limitations under the License.
*
*/
metadata {
definition (name: "ZigBee Button", namespace: "smartthings", author: "Mitch Pond") {
capability "Actuator"
capability "Battery"
capability "Button"
definition (name: "ZigBee Button", namespace: "smartthings", author: "Mitch Pond") {
capability "Battery"
capability "Button"
capability "Configuration"
capability "Refresh"
capability "Sensor"
command "enrollResponse"
fingerprint inClusters: "0000, 0001, 0003, 0020, 0402, 0B05", outClusters: "0003, 0006, 0008, 0019", manufacturer: "OSRAM", model: "LIGHTIFY Dimming Switch", deviceJoinName: "OSRAM LIGHTIFY Dimming Switch"
//fingerprint inClusters: "0000, 0001, 0003, 0020, 0500", outClusters: "0003,0019", manufacturer: "CentraLite", model: "3455-L", deviceJoinName: "Iris Care Pendant"
//fingerprint inClusters: "0000, 0001, 0003, 0007, 0020, 0402, 0B05", outClusters: "0003, 0006, 0019", manufacturer: "CentraLite", model: "3460-L", deviceJoinName: "Iris Smart Button"
//fingerprint inClusters: "0000, 0001, 0003, 0007, 0020, 0B05", outClusters: "0003, 0006, 0019", manufacturer: "CentraLite", model:"3450-L", deviceJoinName: "Iris KeyFob"
capability "Presence Sensor"
capability "Sensor"
//fingerprint endpointId: "01", profileId: "0104", inClusters: "0000,0001,0003,0007,0020,0B05", outClusters: "0003,0006,0019", model:"3450-L", manufacturer: "CentraLite"
}
preferences{
input ("holdTime", "number", title: "Minimum time in seconds for a press to count as \"held\"",
defaultValue: 3, displayDuringSetup: false)
input "checkInterval", "enum", title: "Presence timeout (minutes)",
defaultValue:"2", options: ["2", "3", "5"], displayDuringSetup: false
input "logging", "bool", title: "Enable debug logging",
defaultValue: false, displayDuringSetup: false
}
simulator {}
preferences {
section {
input ("holdTime", "number", title: "Minimum time in seconds for a press to count as \"held\"", defaultValue: 1, displayDuringSetup: false)
tiles(scale: 2) {
standardTile("presence", "device.presence", width: 4, height: 4, canChangeBackground: true) {
state "present", label: "Present", labelIcon:"st.presence.tile.present", backgroundColor:"#53a7c0"
state "not present", labelIcon:"st.presence.tile.not-present", backgroundColor:"#ffffff"
}
}
tiles {
standardTile("button", "device.button", width: 2, height: 2) {
state "default", label: "", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#ffffff"
state "button 1 pushed", label: "pushed #1", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#79b821"
standardTile("button", "device.button", decoration: "flat", width: 2, height: 2) {
state "default", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#ffffff"
}
valueTile("battery", "device.battery", decoration: "flat", width: 2, height: 2) {
state "battery", label:'${currentValue}% battery', unit:""
}
valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false) {
state "battery", label:'${currentValue}% battery', unit:""
}
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat") {
state "default", action:"refresh.refresh", icon:"st.secondary.refresh"
}
main (["button"])
details(["button", "battery", "refresh"])
}
main (["presence"])
details(["presence","button","battery"])
}
}
def parse(String description) {
log.debug "description is $description"
def event = zigbee.getEvent(description)
if (event) {
sendEvent(event)
}
else {
if ((description?.startsWith("catchall:")) || (description?.startsWith("read attr -"))) {
def descMap = zigbee.parseDescriptionAsMap(description)
if (descMap.clusterInt == 0x0001 && descMap.attrInt == 0x0020) {
event = getBatteryResult(zigbee.convertHexToInt(descMap.value))
}
else if (descMap.clusterInt == 0x0006 || descMap.clusterInt == 0x0008) {
event = parseNonIasButtonMessage(descMap)
}
}
else if (description?.startsWith('zone status')) {
event = parseIasButtonMessage(description)
}
log.debug "Parse returned $event"
def result = event ? createEvent(event) : []
if (description?.startsWith('enroll request')) {
List cmds = enrollResponse()
result = cmds?.collect { new physicalgraph.device.HubAction(it) }
}
return result
}
}
private Map parseIasButtonMessage(String description) {
int zoneInt = Integer.parseInt((description - "zone status 0x"), 16)
if (zoneInt & 0x02) {
resultMap = getButtonResult('press')
} else {
resultMap = getButtonResult('release')
}
return resultMap
}
private Map getBatteryResult(rawValue) {
log.debug 'Battery'
def volts = rawValue / 10
if (volts > 3.0 || volts == 0 || rawValue == 0xFF) {
return [:]
}
else {
def result = [
name: 'battery'
]
def minVolts = 2.1
def maxVolts = 3.0
def pct = (volts - minVolts) / (maxVolts - minVolts)
result.value = Math.min(100, (int) pct * 100)
def linkText = getLinkText(device)
result.descriptionText = "${linkText} battery was ${result.value}%"
return result
}
}
private Map parseNonIasButtonMessage(Map descMap){
def buttonState = ""
def buttonNumber = 0
if (((device.getDataValue("model") == "3460-L") || (device.getDataValue("model") == "3450-L"))
&&(descMap.clusterInt == 0x0006)) {
if (descMap.command == "01") {
getButtonResult("press")
}
else if (descMap.command == "00") {
getButtonResult("release")
}
}
else if (descMap.clusterInt == 0x0006) {
buttonState = "pushed"
if (descMap.command == "01") {
buttonNumber = 1
}
else if (descMap.command == "00") {
buttonNumber = 2
}
if (buttonNumber !=0) {
def descriptionText = "$device.displayName button $buttonNumber was $buttonState"
return createEvent(name: "button", value: buttonState, data: [buttonNumber: buttonNumber], descriptionText: descriptionText, isStateChange: true)
}
else {
return [:]
}
}
else if (descMap.clusterInt == 0x0008) {
if (descMap.command == "05") {
state.buttonNumber = 1
getButtonResult("press", 1)
}
else if (descMap.command == "01") {
state.buttonNumber = 2
getButtonResult("press", 2)
}
else if (descMap.command == "03") {
getButtonResult("release", state.buttonNumber)
}
}
}
def refresh() {
log.debug "Refreshing Battery"
return zigbee.readAttribute(0x0001, 0x20) +
zigbee.enrollResponse()
}
def configure() {
log.debug "Configuring Reporting, IAS CIE, and Bindings."
def cmds = []
if (device.getDataValue("model") == "3450-L") {
cmds << [
"zdo bind 0x${device.deviceNetworkId} 1 1 6 {${device.zigbeeId}} {}", "delay 300",
"zdo bind 0x${device.deviceNetworkId} 2 1 6 {${device.zigbeeId}} {}", "delay 300",
"zdo bind 0x${device.deviceNetworkId} 3 1 6 {${device.zigbeeId}} {}", "delay 300",
"zdo bind 0x${device.deviceNetworkId} 4 1 6 {${device.zigbeeId}} {}", "delay 300"
]
}
return zigbee.onOffConfig() +
zigbee.levelConfig() +
zigbee.configureReporting(0x0001, 0x20, 0x20, 30, 21600, 0x01) +
zigbee.enrollResponse() +
zigbee.readAttribute(0x0001, 0x20) +
cmds
}
private Map getButtonResult(buttonState, buttonNumber = 1) {
if (buttonState == 'release') {
log.debug "Button was value : $buttonState"
def timeDiff = now() - state.pressTime
log.info "timeDiff: $timeDiff"
def holdPreference = holdTime ?: 1
log.info "holdp1 : $holdPreference"
holdPreference = (holdPreference as int) * 1000
log.info "holdp2 : $holdPreference"
if (timeDiff > 10000) { //timeDiff>10sec check for refresh sending release value causing actions to be executed
return [:]
}
else {
if (timeDiff < holdPreference) {
buttonState = "pushed"
}
else {
buttonState = "held"
}
def descriptionText = "$device.displayName button $buttonNumber was $buttonState"
return createEvent(name: "button", value: buttonState, data: [buttonNumber: buttonNumber], descriptionText: descriptionText, isStateChange: true)
}
}
else if (buttonState == 'press') {
log.debug "Button was value : $buttonState"
state.pressTime = now()
log.info "presstime: ${state.pressTime}"
return [:]
}
}
def installed() {
initialize()
def descMap = zigbee.parseDescriptionAsMap(description)
logIt descMap
state.lastCheckin = now()
logIt "lastCheckin = ${state.lastCheckin}"
handlePresenceEvent(true)
def results = []
if (description?.startsWith('catchall:'))
results = parseCatchAllMessage(descMap)
else if (description?.startsWith('read attr -'))
results = parseReportAttributeMessage(descMap)
else logIt(descMap, "trace")
return results;
}
def updated() {
initialize()
startTimer()
configure()
}
def initialize() {
if ((device.getDataValue("manufacturer") == "OSRAM") && (device.getDataValue("model") == "LIGHTIFY Dimming Switch")) {
sendEvent(name: "numberOfButtons", value: 2)
}
else if ((device.getDataValue("manufacturer") == "CentraLite") &&
((device.getDataValue("model") == "3455-L") || (device.getDataValue("model") == "3460-L"))) {
sendEvent(name: "numberOfButtons", value: 1)
}
else if ((device.getDataValue("manufacturer") == "CentraLite") && (device.getDataValue("model") == "3450-L")) {
sendEvent(name: "numberOfButtons", value: 4)
}
else {
//default. can be changed
sendEvent(name: "numberOfButtons", value: 4)
}
def configure(){
logIt "Configuring Smart Fob..."
[
"zdo bind 0x${device.deviceNetworkId} 1 1 6 {${device.zigbeeId}} {}", "delay 200",
"zdo bind 0x${device.deviceNetworkId} 2 1 6 {${device.zigbeeId}} {}", "delay 200",
"zdo bind 0x${device.deviceNetworkId} 3 1 6 {${device.zigbeeId}} {}", "delay 200",
"zdo bind 0x${device.deviceNetworkId} 4 1 6 {${device.zigbeeId}} {}", "delay 200",
"zdo bind 0x${device.deviceNetworkId} 1 1 1 {${device.zigbeeId}} {}", "delay 200"
] +
zigbee.configureReporting(0x0001,0x0020,0x20,20,20,0x01)
}
def parseCatchAllMessage(descMap) {
if (descMap?.clusterId == "0006" && descMap?.command == "01") //button pressed
handleButtonPress(descMap.sourceEndpoint as int)
else if (descMap?.clusterId == "0006" && descMap?.command == "00") //button released
handleButtonRelease(descMap.sourceEndpoint as int)
else logIt("Parse: Unhandled message: ${descMap}","trace")
}
def parseReportAttributeMessage(descMap) {
if (descMap?.cluster == "0001" && descMap?.attrId == "0020") createBatteryEvent(getBatteryLevel(descMap.value))
else logIt descMap
}
private createBatteryEvent(percent) {
logIt "Battery level at " + percent
return createEvent([name: "battery", value: percent])
}
//this method determines if a press should count as a push or a hold and returns the relevant event type
private handleButtonRelease(button) {
logIt "lastPress state variable: ${state.lastPress}"
def sequenceError = {logIt("Uh oh...missed a message? Dropping this event.", "error"); state.lastPress = null; return []}
if (!state.lastPress) return sequenceError()
else if (state.lastPress.button != button) return sequenceError()
def currentTime = now()
def startOfPress = state.lastPress?.time
def timeDif = currentTime - startOfPress
def holdTimeMillisec = (settings.holdTime?:3).toInteger() * 1000
state.lastPress = null //we're done with this. clear it to make error conditions easier to catch
if (timeDif < 0)
//likely a message sequence issue or dropped packet. Drop this press and wait for another.
return sequenceError()
else if (timeDif < holdTimeMillisec)
return createButtonEvent(button,"pushed")
else
return createButtonEvent(button,"held")
}
private handleButtonPress(button) {
state.lastPress = [button: button, time: now()]
}
private createButtonEvent(button,action) {
logIt "Button ${button} ${action}"
return createEvent([
name: "button",
value: action,
data:[buttonNumber: button],
descriptionText: "${device.displayName} button ${button} was ${action}",
isStateChange: true,
displayed: true])
}
private getBatteryLevel(rawValue) {
def intValue = Integer.parseInt(rawValue,16)
def min = 2.1
def max = 3.0
def vBatt = intValue / 10
return ((vBatt - min) / (max - min) * 100) as int
}
private handlePresenceEvent(present) {
def wasPresent = device.currentState("presence")?.value == "present"
if (!wasPresent && present) {
logIt "Sensor is present"
startTimer()
} else if (!present) {
logIt "Sensor is not present"
stopTimer()
}
def linkText = getLinkText(device)
def eventMap = [
name: "presence",
value: present ? "present" : "not present",
linkText: linkText,
descriptionText: "${linkText} has ${present ? 'arrived' : 'left'}",
]
logIt "Creating presence event: ${eventMap}"
sendEvent(eventMap)
}
private startTimer() {
logIt "Scheduling periodic timer"
schedule("0 * * * * ?", checkPresenceCallback)
}
private stopTimer() {
logIt "Stopping periodic timer"
unschedule()
}
def checkPresenceCallback() {
def timeSinceLastCheckin = (now() - state.lastCheckin) / 1000
def theCheckInterval = (checkInterval ? checkInterval as int : 2) * 60
logIt "Sensor checked in ${timeSinceLastCheckin} seconds ago"
if (timeSinceLastCheckin >= theCheckInterval) {
handlePresenceEvent(false)
}
}
// ****** Utility functions ******
private logIt(str, logLevel = 'debug') {if (settings.logging) log."$logLevel"(str) }

View File

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

View File

@@ -1,36 +0,0 @@
# OSRAM Lightify LED On/Off/Dim
Works with:
* [OSRAM Lightify LED On/Off/Dim](https://shop.smartthings.com/#!/products/osram-led-smart-bulb-on-off-dim)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Battery](#battery-specification)
## Capabilities
* **Actuator** - represents that a Device has commands
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
* **Refresh** - _refresh()_ command for status updates
* **Switch** - can detect state (possible values: on/off)
* **Switch Level** - represents current light level, usually 0-100 in percent
* **Health Check** - indicates ability to get device health notifications
## Device Health
A Category C1 Zigbee dimmer with maxReportTime of 5 mins.
Check-in interval is double the value of maxReportTime.
This gives the device twice the amount of time to respond before it is marked as offline.
Check-in interval = 12 mins
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
Pairing needs to be tried again by placing the device closer to the hub.
Other troubleshooting tips are listed as follows:
* [Troubleshooting:](https://support.smartthings.com/hc/en-us/articles/207191763-OSRAM-LIGHTIFY-LED-Smart-Connected-Light-A19-On-Off-Dim)

View File

@@ -13,13 +13,12 @@
*/
metadata {
definition (name: "ZigBee Dimmer", namespace: "smartthings", author: "SmartThings", category: "C1") {
definition (name: "ZigBee Dimmer", namespace: "smartthings", author: "SmartThings") {
capability "Actuator"
capability "Configuration"
capability "Refresh"
capability "Switch"
capability "Switch Level"
capability "Health Check"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008"
@@ -54,10 +53,7 @@ def parse(String description) {
def event = zigbee.getEvent(description)
if (event) {
if (event.name=="level" && event.value==0) {}
else {
sendEvent(event)
}
sendEvent(event)
}
else {
log.warn "DID NOT PARSE MESSAGE for description : $description"
@@ -76,12 +72,6 @@ def 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.onOffConfig() + zigbee.levelConfig()
@@ -89,8 +79,5 @@ def refresh() {
def configure() {
log.debug "Configuring Reporting and Bindings."
// Device-Watch allows 2 check-in misses from device
sendEvent(name: "checkInterval", value: 60 * 12, 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.onOffRefresh() + zigbee.levelRefresh()
zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.onOffRefresh() + zigbee.levelRefresh()
}

View File

@@ -31,8 +31,7 @@
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD210 PB DB", deviceJoinName: "Yale Push Button Deadbolt Lock"
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD220/240 TSDB", deviceJoinName: "Yale Touch Screen Deadbolt Lock"
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRL210 PB LL", deviceJoinName: "Yale Push Button Lever Lock"
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD226/246 TSDB", deviceJoinName: "Yale Touch Screen Deadbolt Lock"
}
}
tiles(scale: 2) {
multiAttributeTile(name:"toggle", type:"generic", width:6, height:4){

View File

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

View File

@@ -1,42 +0,0 @@
# OSRAM LIGHTIFY LED RGBW Bulb
Works with:
* [OSRAM LIGHTIFY LED RGBW Bulb](https://support.smartthings.com/hc/en-us/articles/207728173-OSRAM-LIGHTIFY-LED-Smart-Connected-Light-A19-RGBW)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Battery](#battery-specification)
## Capabilities
* **Actuator** - It represents that a device has commands.
* **Color Control** - It represents that the color attributes of a device can be controlled (hue, saturation, color value).
* **Color Temperature** - It represents color temperature capability measured in degree Kelvin.
* **Polling** - It represents that a device can be polled.
* **Switch** - can detect state (possible values: on/off)
* **Switch Level** - can detect current light level (0-100 in percent)
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
* **Refresh** - _refresh()_ command for status updates
* **Health Check** - indicates ability to get device health notifications
## Device Health
A Category C6 OSRAM LIGHTIFY LED RGBW Bulb with maxReportTime of 5 mins.
Check-in interval is double the value of maxReportTime.
This gives the device twice the amount of time to respond before it is marked as offline.
Check-in interval = 12 mins
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
Pairing needs to be tried again by placing the device closer to the hub.
It may also happen that you need to reset the device.
Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link:
* [Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/207728173-OSRAM-LIGHTIFY-LED-Smart-Connected-Light-A19-RGBW)

View File

@@ -17,7 +17,7 @@
*/
metadata {
definition (name: "ZigBee RGBW Bulb", namespace: "smartthings", author: "SmartThings", category: "C6") {
definition (name: "ZigBee RGBW Bulb", namespace: "smartthings", author: "SmartThings") {
capability "Actuator"
capability "Color Control"
@@ -27,10 +27,6 @@ metadata {
capability "Refresh"
capability "Switch"
capability "Switch Level"
capability "Health Check"
attribute "colorName", "string"
command "setGenericName"
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY Flex RGBW", deviceJoinName: "OSRAM LIGHTIFY LED FLEXIBLE STRIP RGBW"
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Flex RGBW", deviceJoinName: "OSRAM LIGHTIFY LED FLEXIBLE STRIP RGBW"
@@ -58,15 +54,15 @@ metadata {
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}'
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", "colorName", "refresh"])
details(["switch", "colorTempSliderControl", "colorTemp", "refresh"])
}
}
@@ -82,16 +78,10 @@ private getATTRIBUTE_COLOR_TEMPERATURE() { 0x0007 }
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)
}
def finalResult = zigbee.getEvent(description)
if (finalResult) {
log.debug finalResult
sendEvent(finalResult)
}
else {
def zigbeeMap = zigbee.parseDescriptionAsMap(description)
@@ -99,12 +89,12 @@ def parse(String description) {
if (zigbeeMap?.clusterInt == COLOR_CONTROL_CLUSTER) {
if(zigbeeMap.attrInt == ATTRIBUTE_HUE){ //Hue Attribute
def hueValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 255 * 100)
sendEvent(name: "hue", value: hueValue, descriptionText: "Color has changed")
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, descriptionText: "Color has changed", displayed: false)
sendEvent(name: "saturation", value: saturationValue, displayed:false)
}
}
else {
@@ -120,47 +110,20 @@ def 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.readAttribute(0x0008, 0x00) + zigbee.readAttribute(0x0300, 0x00) + zigbee.readAttribute(0x0300, ATTRIBUTE_COLOR_TEMPERATURE) + zigbee.readAttribute(0x0300, ATTRIBUTE_HUE) + zigbee.readAttribute(0x0300, ATTRIBUTE_SATURATION) + 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)
zigbee.readAttribute(0x0006, 0x00) + zigbee.readAttribute(0x0008, 0x00) + zigbee.readAttribute(0x0300, 0x00) + zigbee.readAttribute(0x0300, ATTRIBUTE_COLOR_TEMPERATURE) + zigbee.readAttribute(0x0300, ATTRIBUTE_HUE) + zigbee.readAttribute(0x0300, ATTRIBUTE_SATURATION) + 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 configure() {
log.debug "Configuring Reporting and Bindings."
// Device-Watch allows 2 check-in misses from device
sendEvent(name: "checkInterval", value: 60 * 12, 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.colorTemperatureConfig() + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE, 0x20, 1, 3600, 0x01) + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION, 0x20, 1, 3600, 0x01) + zigbee.readAttribute(0x0006, 0x00) + zigbee.readAttribute(0x0008, 0x00) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, 0x00) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_COLOR_TEMPERATURE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
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) + zigbee.readAttribute(0x0006, 0x00) + zigbee.readAttribute(0x0008, 0x00) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, 0x00) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_COLOR_TEMPERATURE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
}
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)
}

View File

@@ -20,7 +20,6 @@ metadata {
capability "Switch"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0006", outClusters: "0003, 0006, 0019, 0406", manufacturer: "Leviton", model: "ZSS-10", deviceJoinName: "Leviton Switch"
}
// simulator metadata

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2016 SmartThings
* 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:
@@ -11,133 +11,100 @@
* for the specific language governing permissions and limitations under the License.
*
*/
/*
* Capabilities
* - Battery
* - Configuration
* - Refresh
* - Switch
* - Valve
*/
metadata {
definition (name: "ZigBee Valve", namespace: "smartthings", author: "SmartThings") {
capability "Actuator"
capability "Battery"
capability "Configuration"
capability "Power Source"
capability "Refresh"
capability "Valve"
definition (name: "Zigbee Valve", namespace: "smartthings", author: "SmartThings") {
capability "Battery"
capability "Configuration"
capability "Refresh"
capability "Switch"
capability "Valve"
fingerprint profileId: "0104", inClusters: "0000, 0001, 0003, 0006, 0020, 0B02, FC02", outClusters: "0019", manufacturer: "WAXMAN", model: "leakSMART Water Valve v2.10", deviceJoinName: "leakSMART Valve"
fingerprint profileId: "0104", inClusters: "0000, 0001, 0003, 0004, 0005, 0006, 0008, 000F, 0020, 0B02", outClusters: "0003, 0019", manufacturer: "WAXMAN", model: "House Water Valve - MDL-TBD", deviceJoinName: "Waxman House Water Valve"
}
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0020,0006,0B02", outClusters: "0003"
}
// simulator metadata
simulator {
// status messages
status "on": "on/off: 1"
status "off": "on/off: 0"
// simulator metadata
simulator {
// status messages
status "on": "on/off: 1"
status "off": "on/off: 0"
// reply messages
reply "zcl on-off on": "on/off: 1"
reply "zcl on-off off": "on/off: 0"
}
// reply messages
reply "zcl on-off on": "on/off: 1"
reply "zcl on-off off": "on/off: 0"
}
tiles(scale: 2) {
multiAttributeTile(name:"valve", type: "generic", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.contact", key: "PRIMARY_CONTROL") {
attributeState "open", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#53a7c0", nextState:"closing"
attributeState "closed", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#e86d13", nextState:"opening"
attributeState "opening", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#53a7c0", nextState:"closing"
attributeState "closing", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#e86d13", nextState:"opening"
}
tileAttribute ("powerSource", key: "SECONDARY_CONTROL") {
attributeState "powerSource", label:'Power Source: ${currentValue}'
}
}
valueTile("battery", "device.battery", inactiveLabel:false, decoration:"flat", width:2, height:2) {
state "battery", label:'${currentValue}% battery', unit:""
}
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
}
main(["valve"])
details(["valve", "battery", "refresh"])
}
// UI tile definitions
tiles {
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
state "off", label: 'closed', action: "switch.on", icon: "st.Outdoor.outdoor16", backgroundColor: "#e86d13"
state "on", label: 'open', action: "switch.off", icon: "st.Outdoor.outdoor16", backgroundColor: "#53a7c0"
}
main "switch"
details(["switch"])
}
}
private getCLUSTER_BASIC() { 0x0000 }
private getBASIC_ATTR_POWER_SOURCE() { 0x0007 }
private getCLUSTER_POWER() { 0x0001 }
private getPOWER_ATTR_BATTERY_PERCENTAGE_REMAINING() { 0x0021 }
private getTYPE_U8() { 0x20 }
private getTYPE_ENUM8() { 0x30 }
// 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 == "switch") {
event.name = "contact" //0006 cluster in valve is tied to contact
if(event.value == "on") {
event.value = "open"
}
else if(event.value == "off") {
event.value = "closed"
}
}
sendEvent(event)
}
else {
def descMap = zigbee.parseDescriptionAsMap(description)
if (descMap.clusterInt == CLUSTER_BASIC && descMap.attrInt == BASIC_ATTR_POWER_SOURCE){
def value = descMap.value
if (value == "01" || value == "02") {
sendEvent(name: "powerSource", value: "Mains")
}
else if (value == "03") {
sendEvent(name: "powerSource", value: "Battery")
}
else if (value == "04") {
sendEvent(name: "powerSource", value: "DC")
}
else {
sendEvent(name: "powerSource", value: "Unknown")
}
}
else if (descMap.clusterInt == CLUSTER_POWER && descMap.attrInt == POWER_ATTR_BATTERY_PERCENTAGE_REMAINING) {
event.name = "battery"
event.value = Math.round(Integer.parseInt(descMap.value, 16) / 2)
sendEvent(event)
}
else {
log.warn "DID NOT PARSE MESSAGE for description : $description"
log.debug descMap
}
}
log.info description
if (description?.startsWith("catchall:")) {
def value = name == "switch" ? (description?.endsWith(" 1") ? "on" : "off") : null
def result = createEvent(name: name, value: value)
def msg = zigbee.parse(description)
log.debug "Parse returned ${result?.descriptionText}"
return result
log.trace msg
log.trace "data: $msg.data"
}
else {
def name = description?.startsWith("on/off: ") ? "switch" : null
def value = name == "switch" ? (description?.endsWith(" 1") ? "on" : "off") : null
def result = createEvent(name: name, value: value)
log.debug "Parse returned ${result?.descriptionText}"
return result
}
}
// Commands to device
def on() {
log.debug "on()"
sendEvent(name: "switch", value: "on")
"st cmd 0x${device.deviceNetworkId} 1 6 1 {}"
}
def off() {
log.debug "off()"
sendEvent(name: "switch", value: "off")
"st cmd 0x${device.deviceNetworkId} 1 6 0 {}"
}
def open() {
zigbee.on()
log.debug "on()"
sendEvent(name: "switch", value: "on")
"st cmd 0x${device.deviceNetworkId} 1 6 1 {}"
}
def close() {
zigbee.off()
log.debug "off()"
sendEvent(name: "switch", value: "off")
"st cmd 0x${device.deviceNetworkId} 1 6 0 {}"
}
def refresh() {
log.debug "refresh called"
zigbee.onOffRefresh() +
zigbee.readAttribute(CLUSTER_BASIC, BASIC_ATTR_POWER_SOURCE) +
zigbee.readAttribute(CLUSTER_POWER, POWER_ATTR_BATTERY_PERCENTAGE_REMAINING) +
zigbee.onOffConfig() +
zigbee.configureReporting(CLUSTER_POWER, POWER_ATTR_BATTERY_PERCENTAGE_REMAINING, TYPE_U8, 600, 21600, 1) +
zigbee.configureReporting(CLUSTER_BASIC, BASIC_ATTR_POWER_SOURCE, TYPE_ENUM8, 5, 21600, 1)
log.debug "sending refresh command"
"st rattr 0x${device.deviceNetworkId} 1 6 0"
}
def configure() {
log.debug "Configuring Reporting and Bindings."
zigbee.onOffConfig() +
zigbee.configureReporting(CLUSTER_POWER, POWER_ATTR_BATTERY_PERCENTAGE_REMAINING, TYPE_U8, 600, 21600, 1) +
zigbee.configureReporting(CLUSTER_BASIC, BASIC_ATTR_POWER_SOURCE, TYPE_ENUM8, 5, 21600, 1) +
zigbee.onOffRefresh() +
zigbee.readAttribute(CLUSTER_BASIC, BASIC_ATTR_POWER_SOURCE) +
zigbee.readAttribute(CLUSTER_POWER, POWER_ATTR_BATTERY_PERCENTAGE_REMAINING)
"zdo bind 0x${device.deviceNetworkId} 1 1 6 {${device.zigbeeId}} {}"
}

View File

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

View File

@@ -1,37 +0,0 @@
# OSRAM Lightify Tunable 60 White
Works with:
* [OSRAM Lightify Tunable 60 White](http://www.osram.com/osram_com/tools-and-services/tools/lightify---smart-connected-light/lightify-for-home---what-is-light-to-you/lightify-products/lightify-classic-a60-tunable-white/index.jsp)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Battery](#battery-specification)
## Capabilities
* **Actuator** - represents that a Device has commands
* **Color Temperature** - represents color temperature, measured in degrees Kelvin.
* **Configuration** - _configure()_ command called when device is installed or device preferences updated.
* **Refresh** - _refresh()_ command for status updates
* **Switch** - can detect state (possible values: on/off)
* **Switch Level** - represents current light level, usually 0-100 in percent
* **Health Check** - indicates ability to get device health notifications
## Device Health
A Category C1 OSRAM Lightify Tunable 60 White with maxReportTime of 5 mins.
Check-in interval is double the value of maxReportTime.
This gives the device twice the amount of time to respond before it is marked as offline.
Check-in interval = 12 mins
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
Pairing needs to be tried again by placing the device closer to the hub.
Other troubleshooting tips are listed as follows:
* [Troubleshooting:](https://support.smartthings.com/hc/en-us/articles/204576454-OSRAM-LIGHTIFY-Tunable-White-60-Bulb)

View File

@@ -17,12 +17,11 @@
*/
metadata {
definition (name: "ZigBee White Color Temperature Bulb", namespace: "smartthings", author: "SmartThings", category: "C1") {
definition (name: "ZigBee White Color Temperature Bulb", namespace: "smartthings", author: "SmartThings") {
capability "Actuator"
capability "Color Temperature"
capability "Configuration"
capability "Health Check"
capability "Refresh"
capability "Switch"
capability "Switch Level"
@@ -36,7 +35,6 @@ metadata {
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: "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"
}
// UI tile definitions
@@ -51,6 +49,9 @@ metadata {
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
attributeState "level", action:"switch level.setLevel"
}
tileAttribute ("colorName", key: "SECONDARY_CONTROL") {
attributeState "colorName", label:'${currentValue}'
}
}
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
@@ -60,12 +61,12 @@ metadata {
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}'
valueTile("colorTemp", "device.colorTemperature", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "colorTemperature", label: '${currentValue} K'
}
main(["switch"])
details(["switch", "colorTempSliderControl", "colorName", "refresh"])
details(["switch", "colorTempSliderControl", "colorTemp", "refresh"])
}
}
@@ -74,13 +75,7 @@ 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)
}
sendEvent(event)
}
else {
log.warn "DID NOT PARSE MESSAGE for description : $description"
@@ -100,23 +95,13 @@ 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() + zigbee.levelConfig() + zigbee.colorTemperatureConfig()
}
def configure() {
log.debug "Configuring Reporting and Bindings."
// Device-Watch allows 2 check-in misses from device
sendEvent(name: "checkInterval", value: 60 * 12, 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.colorTemperatureConfig() + zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh()
zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.colorTemperatureConfig() + zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh()
}
def setColorTemperature(value) {

View File

@@ -22,9 +22,8 @@ metadata {
capability "Switch"
capability "Switch Level"
//fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0000,0019"
fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019"
//fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0000,0019", manufacturer: "CREE", model: "Connected A-19 60W Equivalent", deviceJoinName: "Cree Connected Bulb"
fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0000,0019"
fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0000,0019", manufacturer: "CREE", model: "Connected A-19 60W Equivalent", deviceJoinName: "Cree Connected Bulb"
fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Classic A60 W clear", deviceJoinName: "OSRAM LIGHTIFY LED Smart Connected Light"
fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Classic A60 W clear - LIGHTIFY", deviceJoinName: "OSRAM LIGHTIFY LED Smart Connected Light"
fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", manufacturer: "Philips", model: "LWB006", deviceJoinName: "Philips Hue White"

View File

@@ -1,205 +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.
*
*/
metadata {
definition (name: "Z-Wave Dimmer Switch Generic", namespace: "smartthings", author: "SmartThings") {
capability "Switch Level"
capability "Actuator"
capability "Switch"
capability "Polling"
capability "Refresh"
capability "Sensor"
fingerprint inClusters: "0x26", deviceJoinName: "Z-Wave Dimmer"
}
simulator {
status "on": "command: 2003, payload: FF"
status "off": "command: 2003, payload: 00"
status "09%": "command: 2003, payload: 09"
status "10%": "command: 2003, payload: 0A"
status "33%": "command: 2003, payload: 21"
status "66%": "command: 2003, payload: 42"
status "99%": "command: 2003, payload: 63"
// reply messages
reply "2001FF,delay 5000,2602": "command: 2603, payload: FF"
reply "200100,delay 5000,2602": "command: 2603, payload: 00"
reply "200119,delay 5000,2602": "command: 2603, payload: 19"
reply "200132,delay 5000,2602": "command: 2603, payload: 32"
reply "20014B,delay 5000,2602": "command: 2603, payload: 4B"
reply "200163,delay 5000,2602": "command: 2603, payload: 63"
}
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"
}
}
standardTile("refresh", "device.switch", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
}
valueTile("level", "device.level", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "level", label:'${currentValue} %', unit:"%", backgroundColor:"#ffffff"
}
main(["switch"])
details(["switch", "level", "refresh"])
}
}
def parse(String description) {
def result = null
if (description != "updated") {
log.debug "parse() >> zwave.parse($description)"
def cmd = zwave.parse(description, [0x20: 1, 0x26: 1, 0x70: 1])
if (cmd) {
result = zwaveEvent(cmd)
}
}
if (result?.name == 'hail' && hubFirmwareLessThan("000.011.00602")) {
result = [result, response(zwave.basicV1.basicGet())]
log.debug "Was hailed: requesting state update"
} else {
log.debug "Parse returned ${result?.descriptionText}"
}
return result
}
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) {
dimmerEvents(cmd)
}
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) {
dimmerEvents(cmd)
}
def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv1.SwitchMultilevelReport cmd) {
dimmerEvents(cmd)
}
def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv1.SwitchMultilevelSet cmd) {
dimmerEvents(cmd)
}
private dimmerEvents(physicalgraph.zwave.Command cmd) {
def value = (cmd.value ? "on" : "off")
def result = [createEvent(name: "switch", value: value)]
if (cmd.value && cmd.value <= 100) {
result << createEvent(name: "level", value: cmd.value, unit: "%")
}
return result
}
def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) {
log.debug "ConfigurationReport $cmd"
def value = "when off"
if (cmd.configurationValue[0] == 1) {value = "when on"}
if (cmd.configurationValue[0] == 2) {value = "never"}
createEvent([name: "indicatorStatus", value: value])
}
def zwaveEvent(physicalgraph.zwave.commands.hailv1.Hail cmd) {
createEvent([name: "hail", value: "hail", descriptionText: "Switch button was pressed", displayed: false])
}
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
log.debug "manufacturerId: ${cmd.manufacturerId}"
log.debug "manufacturerName: ${cmd.manufacturerName}"
log.debug "productId: ${cmd.productId}"
log.debug "productTypeId: ${cmd.productTypeId}"
def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)
updateDataValue("MSR", msr)
updateDataValue("manufacturer", cmd.manufacturerName)
createEvent([descriptionText: "$device.displayName MSR: $msr", isStateChange: false])
}
def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv1.SwitchMultilevelStopLevelChange cmd) {
[createEvent(name:"switch", value:"on"), response(zwave.switchMultilevelV1.switchMultilevelGet().format())]
}
def zwaveEvent(physicalgraph.zwave.Command cmd) {
// Handles all Z-Wave commands we aren't interested in
[:]
}
def on() {
delayBetween([
zwave.basicV1.basicSet(value: 0xFF).format(),
zwave.switchMultilevelV1.switchMultilevelGet().format()
],5000)
}
def off() {
delayBetween([
zwave.basicV1.basicSet(value: 0x00).format(),
zwave.switchMultilevelV1.switchMultilevelGet().format()
],5000)
}
def setLevel(value) {
log.debug "setLevel >> value: $value"
def valueaux = value as Integer
def level = Math.max(Math.min(valueaux, 99), 0)
if (level > 0) {
sendEvent(name: "switch", value: "on")
} else {
sendEvent(name: "switch", value: "off")
}
sendEvent(name: "level", value: level, unit: "%")
delayBetween ([zwave.basicV1.basicSet(value: level).format(), zwave.switchMultilevelV1.switchMultilevelGet().format()], 5000)
}
def setLevel(value, duration) {
log.debug "setLevel >> value: $value, duration: $duration"
def valueaux = value as Integer
def level = Math.max(Math.min(valueaux, 99), 0)
def dimmingDuration = duration < 128 ? duration : 128 + Math.round(duration / 60)
def getStatusDelay = duration < 128 ? (duration*1000)+2000 : (Math.round(duration / 60)*60*1000)+2000
delayBetween ([zwave.switchMultilevelV2.switchMultilevelSet(value: level, dimmingDuration: dimmingDuration).format(),
zwave.switchMultilevelV1.switchMultilevelGet().format()], getStatusDelay)
}
def poll() {
zwave.switchMultilevelV1.switchMultilevelGet().format()
}
def refresh() {
log.debug "refresh() is called"
def commands = []
commands << zwave.switchMultilevelV1.switchMultilevelGet().format()
if (getDataValue("MSR") == null) {
commands << zwave.manufacturerSpecificV1.manufacturerSpecificGet().format()
}
delayBetween(commands,100)
}
def invertSwitch(invert=true) {
if (invert) {
zwave.configurationV1.configurationSet(configurationValue: [1], parameterNumber: 4, size: 1).format()
}
else {
zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 4, size: 1).format()
}
}

Some files were not shown because too many files have changed in this diff Show More