Compare commits

..

2 Commits

Author SHA1 Message Date
Vinay Rao
51452bc095 Merge pull request #1391 from SmartThingsCommunity/staging
Rolling up staging for prod deployment
2016-10-25 15:03:50 -07:00
Vinay Rao
c15b1e88e1 Merge pull request #1362 from SmartThingsCommunity/staging
Rolling up staging to production for deploy
2016-10-18 14:03:11 -07:00
37 changed files with 97 additions and 1877 deletions

View File

@@ -1,394 +0,0 @@
/**
* Trend Setter - Colorful Light Group Device
*
* Copyright 2015 Chris Kitch
*
* 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: "Colorful Light Group Device", namespace: "kriskit.trendSetter", author: "Chris Kitch") {
capability "Actuator"
capability "Sensor"
capability "Switch"
capability "Switch Level"
capability "Color Control"
command "adjustLevel"
command "adjustSaturation"
command "adjustHue"
attribute "onPercentage", "number"
attribute "levelSync", "string"
attribute "colorSync", "string"
attribute "saturationSync", "string"
attribute "hueSync", "string"
}
simulator {
// TODO: define status and reply messages here
}
tiles(scale: 2) {
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label: '${name}', action: "switch.off", icon: "st.lights.multi-light-bulb-on", backgroundColor: "#79b821", nextState: "turningOff"
attributeState "off", label: '${name}', action: "switch.on", icon: "st.lights.multi-light-bulb-off", backgroundColor: "#ffffff", nextState: "turningOn"
attributeState "turningOn", label: '${name}', action: "switch.off", icon: "st.lights.multi-light-bulb-on", backgroundColor: "#79b821", nextState: "turningOff"
attributeState "turningOff", label: '${name}', action: "switch.on", icon: "st.lights.multi-light-bulb-off", backgroundColor: "#ffffff", nextState: "turningOn"
attributeState "half", label: '${name}', action: "switch.on", icon: "st.lights.multi-light-bulb-on", backgroundColor: "#a3d164", nextState: "turningOn"
attributeState "mostlyOn", label: 'Onish', action: "switch.on", icon: "st.lights.multi-light-bulb-on", backgroundColor: "#79b821", nextState: "turningOn"
attributeState "mostlyOff", label: 'Offish', action: "switch.off", icon: "st.lights.multi-light-bulb-off", backgroundColor: "#d1e5b5", nextState: "turninOff"
}
tileAttribute ("device.color", key: "COLOR_CONTROL") {
attributeState "color", action: "color control.setColor"
}
tileAttribute ("device.onPercentage", key: "SECONDARY_CONTROL") {
attributeState "onPercentage", label:'${currentValue}% On'
attributeState "100", label:'All On'
attributeState "0", label:'All Off'
}
tileAttribute("device.level", key: "SLIDER_CONTROL") {
attributeState "default", label: '', action: "switch level.setLevel"
}
}
standardTile("levelLabel", "levelLable", height:1, width:1, decoration: "flat", inactiveLabel: true) {
state "default", label:"Level", unit:"", icon: "st.illuminance.illuminance.light"
}
controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 3, inactiveLabel: false) {
state "level", action:"switch level.setLevel"
}
valueTile("levelValue", "device.level", inactiveLabel: true, height:1, width:1, decoration: "flat") {
state "default", label:'${currentValue}%', unit:""
}
valueTile("levelSync", "device.levelSync", height:1, width:1) {
state "default", label:' Sync ', unit:"", action: "adjustLevel", backgroundColor: "#ff9900"
state "ok", label:'', unit:"", backgroundColor: "#00b509"
}
standardTile("saturationLabel", "saturationLabel", height:1, width:1, decoration: "flat", inactiveLabel: true) {
state "default", label:"Sat", unit:"", icon: "st.Kids.kids2"
}
controlTile("saturationSliderControl", "device.saturation", "slider", height: 1, width: 3, inactiveLabel: false) {
state "saturation", action:"color control.setSaturation"
}
valueTile("saturationValue", "device.saturation", inactiveLabel: true, height:1, width:1, decoration: "flat") {
state "default", label:'${currentValue}%', unit:""
}
valueTile("saturationSync", "device.saturationSync", height:1, width:1) {
state "default", label:' Sync ', unit:"", action: "adjustSaturation", backgroundColor: "#ff9900"
state "ok", label:'', unit:"", backgroundColor: "#00b509"
}
standardTile("hueLabel", "hueLabel", height:1, width:1, decoration: "flat", inactiveLabel: true) {
state "default", label:"Hue", unit:"", icon: "st.Kids.kids2"
}
controlTile("hueSliderControl", "device.hue", "slider", height: 1, width: 3, inactiveLabel: false) {
state "hue", action:"color control.setHue"
}
valueTile("hueValue", "device.hue", inactiveLabel: true, height:1, width:1, decoration: "flat") {
state "default", label:'${currentValue}%', unit:""
}
valueTile("hueSync", "device.hueSync", height:1, width:1) {
state "default", label:' Sync ', unit:"", action: "adjustHue", backgroundColor: "#ff9900"
state "ok", label:'', unit:"", backgroundColor: "#00b509"
}
}
main "switch"
details([
"switch",
"levelLabel",
"levelSliderControl",
"levelValue",
"levelSync",
"saturationLabel",
"saturationSliderControl",
"saturationValue",
"saturationSync",
"hueLabel",
"hueSliderControl",
"hueValue",
"hueSync"])
}
def parse(String description) {
}
def groupSync(name, values) {
try {
"sync${name.capitalize()}"(values)
} catch(ex) {
log.error "Error executing 'sync${name.capitalize()}' method: $ex"
}
}
// SWITCH
def on() {
on(true)
}
def on(triggerGroup) {
sendEvent(name: "switch", value: "on")
sendEvent(name: "onPercentage", value: 100, displayed: false)
if (triggerGroup)
parent.performGroupCommand("on")
}
def off() {
off(true)
}
def off(triggerGroup) {
sendEvent(name: "switch", value: "off")
sendEvent(name: "onPercentage", value: 0, displayed: false)
if (triggerGroup)
parent.performGroupCommand("off")
}
def syncSwitch(values) {
log.debug "syncSwitch(): $values"
def onCount = values?.count { it == "on" }
def percentOn = (int)Math.floor((onCount / values?.size()) * 100)
log.debug "Percent On: $percentOn"
if (percentOn == 0 || percentOn == 100) {
if (percentOn == 0)
off(false)
else
on(false)
return
}
def value = null
if (percentOn == 50)
value = "half"
else if (percentOn > 0 && percentOn < 50)
value = "mostlyOff"
else if (percentOn > 50 && percentOn < 100)
value = "mostlyOn"
sendEvent(name: "switch", value: value)
sendEvent(name: "onPercentage", value: percentOn, displayed: false)
}
// LEVEL
def setLevel(val) {
setLevel(val, true)
}
def setLevel(val, triggerGroup) {
log.debug "Setting level to $val"
if (val < 0)
val = 0
if( val > 100)
val = 100
if (triggerGroup) {
if (val == 0)
off()
else
on()
}
sendEvent(name: "level", value: val, isStateChange: true)
sendEvent(name: "switch.setLevel", value: val, isStateChange: true)
if (triggerGroup)
parent.performGroupCommand("setLevel", [val])
}
def syncLevel(values) {
log.debug "syncLevel(): $values"
def valueCount = values?.size()
def valueCountBy = values?.countBy { it }
def matchValue = "bad"
def level = device.currentValue("level")
valueCountBy.each { value, count ->
if (count == valueCount) {
level = value
matchValue = "ok"
return true
}
}
if (matchValue == "bad")
level = getAdjustmentLevel(values)
setLevel(level, false)
sendEvent(name: "levelSync", value: matchValue, displayed: false)
}
def adjustLevel() {
def values = parent.getGroupCurrentValues("level")
if (!values)
return
def level = getAdjustmentLevel(values)
setLevel(level)
}
def getAdjustmentLevel(values) {
if (!values)
return
def valueCountBy = values?.countBy { it }
valueCountBy = valueCountBy?.sort { a, b -> b.value <=> a.value }
def level = device.currentValue("level")
if (valueCountBy.size() > 1) {
if (valueCountBy.size() == values.size()) {
log.debug "Values are all different - making average"
level = Math.round(values.sum() / values.size())
} else {
log.debug "Some values are the same, choosing most popular"
def firstItem = valueCountBy.find { true }
level = firstItem.key
}
}
return level
}
// COLOR
def setColor(value) {
setColor(value, true)
}
def setColor(value, triggerGroup) {
value.level = null
def hex = value.hex
if (!hex && value.hue && value.saturation)
hex = colorUtil.hslToHex(value.hue, value.saturation)
sendEvent(name: "color", value: value.hex, displayed:false)
if (triggerGroup)
parent.performGroupCommand("setColor", [value])
if (value.saturation)
setSaturation(value.saturation, triggerGroup, false)
if (value.hue)
setHue(value.hue, triggerGroup, false)
}
def syncColor(values) {
log.debug "syncColor(): $values"
}
// SATURATION
def setSaturation(value) {
setSaturation(value, true, true)
}
def setSaturation(value, triggerGroup, sendColor) {
on(triggerGroup)
sendEvent(name: "saturation", value: (int)value, displayed:false)
if (triggerGroup)
parent.performGroupCommand("setSaturation", [value])
if (sendColor) {
def hex = colorUtil.hslToHex((int)device.currentValue("hue"), value)
sendEvent(name: "color", value: hex, displayed:false)
}
}
def syncSaturation(values) {
log.debug "syncSaturation(): $values"
def valueCount = values?.size()
def valueCountBy = values?.countBy { it }
def matchValue = "bad"
valueCountBy.each { value, count ->
if (count == valueCount) {
matchValue = "ok"
return true
}
}
sendEvent(name: "saturationSync", value: matchValue, displayed: false)
}
def adjustSaturation() {
def saturation = (int)device.currentValue("saturation")
log.debug "adjustSaturation $saturation"
setSaturation(saturation)
}
// HUE
def setHue(value) {
setHue(value, true, true)
}
def setHue(value, triggerGroup, sendColor) {
on(triggerGroup)
sendEvent(name: "hue", value: (int)value, displayed: false)
if (triggerGroup)
parent.performGroupCommand("setHue", [value])
if (sendColor) {
def hex = colorUtil.hslToHex(value, (int)device.currentValue("saturation"))
sendEvent(name: "color", value: hex, displayed:false)
}
}
def syncHue(values) {
log.debug "syncHue(): $values"
def valueCount = values?.size()
def valueCountBy = values?.countBy { it }
def matchValue = "bad"
valueCountBy.each { value, count ->
if (count == valueCount) {
matchValue = "ok"
return true
}
}
sendEvent(name: "hueSync", value: matchValue, displayed: false)
}
def adjustHue() {
def hue = (int)device.currentValue("hue")
log.debug "adjustHue: $hue"
setHue(hue)
}

View File

@@ -1,229 +0,0 @@
/**
* Trend Setter - Dimmer Group Device
*
* Copyright 2015 Chris Kitch
*
* 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: "Dimmer Group Device", namespace: "kriskit.trendSetter", author: "Chris Kitch") {
capability "Actuator"
capability "Sensor"
capability "Switch"
capability "Switch Level"
command "adjustLevel"
attribute "onPercentage", "number"
attribute "levelSync", "string"
}
simulator {
// TODO: define status and reply messages here
}
tiles(scale: 2) {
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label: '${name}', action: "switch.off", icon: "st.lights.multi-light-bulb-on", backgroundColor: "#79b821", nextState: "turningOff"
attributeState "off", label: '${name}', action: "switch.on", icon: "st.lights.multi-light-bulb-off", backgroundColor: "#ffffff", nextState: "turningOn"
attributeState "turningOn", label: '${name}', action: "switch.off", icon: "st.lights.multi-light-bulb-on", backgroundColor: "#79b821", nextState: "turningOff"
attributeState "turningOff", label: '${name}', action: "switch.on", icon: "st.lights.multi-light-bulb-off", backgroundColor: "#ffffff", nextState: "turningOn"
attributeState "half", label: '${name}', action: "switch.on", icon: "st.lights.multi-light-bulb-on", backgroundColor: "#a3d164", nextState: "turningOn"
attributeState "mostlyOn", label: 'Onish', action: "switch.on", icon: "st.lights.multi-light-bulb-on", backgroundColor: "#79b821", nextState: "turningOn"
attributeState "mostlyOff", label: 'Offish', action: "switch.off", icon: "st.lights.multi-light-bulb-off", backgroundColor: "#d1e5b5", nextState: "turninOff"
}
tileAttribute ("device.onPercentage", key: "SECONDARY_CONTROL") {
attributeState "onPercentage", label:'${currentValue}% On'
attributeState "100", label:'All On'
attributeState "0", label:'All Off'
}
tileAttribute("device.level", key: "SLIDER_CONTROL") {
attributeState "default", label: '', action: "switch level.setLevel"
}
}
standardTile("levelLabel", "levelLable", height:1, width:1, decoration: "flat", inactiveLabel: true) {
state "default", label:"Level", unit:"", icon: "st.illuminance.illuminance.bright"
}
controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 3, inactiveLabel: false) {
state "level", action:"switch level.setLevel"
}
valueTile("levelValue", "device.level", inactiveLabel: true, height:1, width:1, decoration: "flat") {
state "default", label:'${currentValue}%', unit:""
}
valueTile("levelSync", "device.levelSync", height:1, width:1) {
state "default", label:' Sync ', unit:"", action: "adjustLevel", backgroundColor: "#ff9900"
state "ok", label:'', unit:"", backgroundColor: "#00b509"
}
}
main "switch"
details(["switch", "levelLabel", "levelSliderControl", "levelValue", "levelSync"])
}
def parse(String description) {
}
def groupSync(name, values) {
try {
"sync${name.capitalize()}"(values)
} catch(ex) {
log.error "Error executing 'sync${name.capitalize()}' method: $ex"
}
}
// SWITCH
def on() {
on(true)
}
def on(triggerGroup) {
sendEvent(name: "switch", value: "on")
sendEvent(name: "onPercentage", value: 100, displayed: false)
if (triggerGroup)
parent.performGroupCommand("on")
}
def off() {
off(true)
}
def off(triggerGroup) {
sendEvent(name: "switch", value: "off")
sendEvent(name: "onPercentage", value: 0, displayed: false)
if (triggerGroup)
parent.performGroupCommand("off")
}
def syncSwitch(values) {
log.debug "syncSwitch(): $values"
def onCount = values?.count { it == "on" }
def percentOn = (int)Math.floor((onCount / values?.size()) * 100)
log.debug "Percent On: $percentOn"
if (percentOn == 0 || percentOn == 100) {
if (percentOn == 0)
off(false)
else
on(false)
return
}
def value = null
if (percentOn == 50)
value = "half"
else if (percentOn > 0 && percentOn < 50)
value = "mostlyOff"
else if (percentOn > 50 && percentOn < 100)
value = "mostlyOn"
sendEvent(name: "switch", value: value)
sendEvent(name: "onPercentage", value: percentOn, displayed: false)
}
// LEVEL
def setLevel(val){
setLevel(val, true)
}
def setLevel(val, triggerGroup) {
log.debug "Setting level to $val"
if (val < 0)
val = 0
if( val > 100)
val = 100
if (triggerGroup) {
if (val == 0)
off()
else
on()
}
sendEvent(name: "level", value: val, isStateChange: true)
sendEvent(name: "switch.setLevel", value: val, isStateChange: true)
if (triggerGroup)
parent.performGroupCommand("setLevel", [val])
}
def syncLevel(values) {
log.debug "syncLevel(): $values"
def valueCount = values?.size()
def valueCountBy = values?.countBy { it }
def matchValue = "bad"
def level = device.currentValue("level")
valueCountBy.each { value, count ->
if (count == valueCount) {
level = value
matchValue = "ok"
return true
}
}
if (matchValue == "bad")
level = getAdjustmentLevel(values)
setLevel(level, false)
sendEvent(name: "levelSync", value: matchValue, displayed: false)
}
def adjustLevel() {
def values = parent.getGroupCurrentValues("level")
if (!values)
return
def valueCountBy = values?.countBy { it }
valueCountBy = valueCountBy?.sort { a, b -> b.value <=> a.value }
def level = getAdjustmentLevel(values)
setLevel(level)
}
def getAdjustmentLevel(values) {
if (!values)
return
def valueCountBy = values?.countBy { it }
valueCountBy = valueCountBy?.sort { a, b -> b.value <=> a.value }
def level = device.currentValue("level")
if (valueCountBy.size() > 1) {
if (valueCountBy.size() == values.size()) {
log.debug "Values are all different - making average"
level = Math.round(values.sum() / values.size())
} else {
log.debug "Some values are the same, choosing most popular"
def firstItem = valueCountBy.find { true }
level = firstItem.key
}
}
return level
}

View File

@@ -1,162 +0,0 @@
/**
* Power Meter Group Device
*
* Copyright 2015 Chris Kitch
*
* 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: "Power Meter Group Device", namespace: "kriskit.trendsetter", author: "Chris Kitch") {
capability "Power Meter"
capability "Sensor"
capability "Refresh"
attribute "powerUsage", "string"
}
simulator {
// TODO: define status and reply messages here
}
tiles(scale: 2) {
multiAttributeTile(name:"main", type: "lighting", width: 6, height: 4) {
tileAttribute ("device.powerUsage", key: "PRIMARY_CONTROL") {
attributeState "off", label: '${name}', backgroundColor: "#ffffff", icon: "st.Appliances.appliances17"
attributeState "low", label: '${name}', backgroundColor: "#5CB85C", icon: "st.Appliances.appliances17"
attributeState "medium", label: '${name}', backgroundColor: "#ff7b00", icon: "st.Appliances.appliances17"
attributeState "high", label: '${name}', backgroundColor: "#c90000", icon: "st.Appliances.appliances17"
attributeState "veryHigh", label: '${name}', backgroundColor: "#ff0000", icon: "st.Appliances.appliances17"
}
tileAttribute ("device.power", key: "SECONDARY_CONTROL") {
attributeState "default", label: '${currentValue} W'
}
}
standardTile("refresh", "refresh", height:2, width:6, inactiveLabel: false, decoration: "flat") {
state "default", action: "refresh.refresh", icon:"st.secondary.refresh"
}
main("main")
details(["main", "refresh"])
}
}
// parse events into attributes
def parse(String description) {
}
def groupSync(name, values) {
try {
"sync${name.capitalize()}"(values)
} catch(ex) {
log.error "Error executing 'sync${name.capitalize()}' method: $ex"
}
}
def refresh() {
def powerValues = parent.getGroupCurrentValues("power")
syncPower(powerValues)
}
// POWER
def syncPower(values) {
log.debug "syncPower(): $values"
def total = values?.sum()
if (total == 0) {
sendEvent(name: "power", value: 0)
sendEvent(name: "powerUsage", value: "off")
return
}
def aggregate = state.powerAggregate ?: []
state.powerSyncCount = state.powerSyncCount + 1
if (state.powerSyncCount != null && state.powerSyncCount % 5 != 0) {
aggregate.push(total)
state.powerAggregate = aggregate
return
}
def aggregatedAverage = getAverage(aggregate)
log.debug "Aggregated Average Power: $aggregatedAverage"
sendEvent(name: "power", value: aggregatedAverage)
def level = getPowerUsageLevel(aggregatedAverage)
log.debug "Power usage level: $level"
sendEvent(name: "powerUsage", value: level)
state.powerAggregate = []
}
def getPowerUsageLevel(value) {
if (value == 0)
return "off"
def boundaries = getPowerUsageBoundaries()
if (!boundaries)
return "low"
log.debug "Determining power usage level with boundaries: $boundaries for value $value"
if (value > 0 && value <= boundaries.bottom)
return "low"
if (value > boundaries.bottom && value < boundaries.top)
return "medium"
if (value >= boundaries.top && value <= boundaries.max)
return "high"
if (value > boundaries.max) {
state.powerUsageBoundaries = null
return "veryHigh"
}
}
def getPowerUsageBoundaries() {
if (state.powerUsageBoundaries && state.powerSyncCount < 100)
return state.powerUsageBoundaries
def events = device.events([max: 500])
def powerEvents = events?.findAll {
it.name == "power" && it.doubleValue > 0
}
def powerValues = powerEvents*.doubleValue
powerValues.sort()
def eventCount = powerValues?.size()
def eventChunkSize = (int)Math.round(eventCount / 2)
def chunkedEvents = powerValues.collate(eventChunkSize)
if (chunkedEvents.size() < 2)
return null
def boundaries = [
top: getAverage(chunkedEvents[1]),
bottom: getAverage(chunkedEvents[0]),
max: powerValues.max()
]
state.powerSyncCount = 0
state.powerUsageBoundaries = boundaries
log.debug "New boundaries: $boundaries"
return boundaries
}
def getAverage(values) {
return Math.round((values.sum() / values.size()) * 100) / 100
}

View File

@@ -1,116 +0,0 @@
/**
* Trend Setter - Switch Group Device
*
* Copyright 2015 Chris Kitch
*
* 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: "Switch Group Device", namespace: "kriskit.trendSetter", author: "Chris Kitch") {
capability "Actuator"
capability "Sensor"
capability "Switch"
attribute "onPercentage", "number"
}
simulator {
// TODO: define status and reply messages here
}
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"
attributeState "half", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#a3d164", nextState: "turningOn"
attributeState "mostlyOn", label: 'Onish', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#79b821", nextState: "turningOn"
attributeState "mostlyOff", label: 'Offish', action: "switch.off", icon: "st.switches.switch.off", backgroundColor: "#d1e5b5", nextState: "turninOff"
}
tileAttribute ("device.onPercentage", key: "SECONDARY_CONTROL") {
attributeState "onPercentage", label:'${currentValue}% On'
attributeState "100", label:'All On'
attributeState "0", label:'All Off'
}
}
}
main "switch"
details(["switch"])
}
def parse(String description) {
}
def groupSync(name, values) {
try {
"sync${name.capitalize()}"(values)
} catch(ex) {
log.error "Error executing 'sync${name.capitalize()}' method: $ex"
}
}
// SWITCH
def on() {
on(true)
}
def on(triggerGroup) {
sendEvent(name: "switch", value: "on")
sendEvent(name: "onPercentage", value: 100, displayed: false)
if (triggerGroup)
parent.performGroupCommand("on")
}
def off() {
off(true)
}
def off(triggerGroup) {
sendEvent(name: "switch", value: "off")
sendEvent(name: "onPercentage", value: 0, displayed: false)
if (triggerGroup)
parent.performGroupCommand("off")
}
def syncSwitch(values) {
log.debug "syncSwitch(): $values"
def onCount = values?.count { it == "on" }
def percentOn = (int)Math.floor((onCount / values?.size()) * 100)
log.debug "Percent On: $percentOn"
if (percentOn == 0 || percentOn == 100) {
if (percentOn == 0)
off(false)
else
on(false)
return
}
def value = null
if (percentOn == 50)
value = "half"
else if (percentOn > 0 && percentOn < 50)
value = "mostlyOff"
else if (percentOn > 50 && percentOn < 100)
value = "mostlyOn"
sendEvent(name: "switch", value: value)
sendEvent(name: "onPercentage", value: percentOn, displayed: false)
}

View File

@@ -59,15 +59,6 @@ metadata {
}
}
def installed() {
log.debug "${device} installed"
}
def updated() {
log.debug "${device} updated"
configureHealthCheck()
}
// Parse incoming device messages to generate events
def parse(String description) {
log.debug "description is $description"
@@ -105,14 +96,6 @@ def refresh() {
zigbee.onOffRefresh() + zigbee.levelRefresh()
}
def configureHealthCheck() {
log.debug "configureHealthCheck"
unschedule("healthPoll")
runEvery5Minutes("healthPoll")
// Device-Watch allows 2 check-in misses from device
sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
}
def healthPoll() {
log.debug "healthPoll()"
def cmds = zigbee.onOffRefresh() + zigbee.levelRefresh()
@@ -120,5 +103,9 @@ def healthPoll() {
}
def configure() {
refresh()
unschedule()
runEvery5Minutes("healthPoll")
// Device-Watch allows 2 check-in misses from device
sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
zigbee.onOffRefresh() + zigbee.levelRefresh()
}

View File

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

View File

@@ -1,45 +0,0 @@
# Z-wave Dimmer Switch
Works with:
* [GE Z-Wave In-Wall Smart Dimmer (GE 12724)](http://products.z-wavealliance.org/products/1197)
* [GE Z-Wave In-Wall Smart Dimmer (Toggle) (GE 12729)](http://products.z-wavealliance.org/products/1201)
* [GE Z-Wave Plug-in Smart Dimmer (GE 12718)](http://products.z-wavealliance.org/products/1191)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Troubleshooting](#Troubleshooting)
## Capabilities
* **Switch Level** - it's defined to accept two parameters, the level and the rate of dimming
* **Actuator** - represents that a Device has commands
* **Indicator** - gives you the ability to set the indicator LED light on a Z-Wave switch
* **Switch** - can detect state (possible values: on/off)
* **Polling** - represents that poll() can be implemented for the device
* **Refresh** - _refresh()_ command for status updates
* **Sensor** - detects sensor events
* **Health Check** - indicates ability to get device health notifications
## Device Health
Z-Wave Smart Dimmers (In-Wall, In-Wall(Toggle), Plug-In) are polled by the hub.
As of hubCore version 0.14.38 the hub sends up reports every 15 minutes regardless of whether the state changed.
Check-in interval = 32 mins.
Not to mention after going OFFLINE when the device is plugged back in, it might take a considerable amount of time for
the device to appear as ONLINE again. This is because if this listening device does not respond to two poll requests in a row,
it is not polled for 5 minutes by the hub. This can delay up the process of being marked ONLINE by quite some time.
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
Pairing needs to be tried again by placing the device closer to the hub.
Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link:
* [General Z-Wave Dimmer/Switch Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/200955890-Troubleshooting-GE-in-wall-switch-or-dimmer-won-t-respond-to-commands-or-automations-Z-Wave-)
* [GE Z-Wave In-Wall Smart Dimmer (GE 12724) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/200902600-GE-In-Wall-Paddle-Dimmer-Switch-GE-12724-Z-Wave-)
* [GE Z-Wave In-Wall Smart Dimmer (Toggle) (GE 12729) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/207568463-GE-In-Wall-Smart-Toggle-Dimmer-GE-12729-Z-Wave-)
* [GE Z-Wave Plug-in Smart Dimmer (GE 12718) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/202088474-GE-Plug-In-Smart-Dimmer-GE-12718-Z-Wave-)

View File

@@ -20,7 +20,6 @@ metadata {
capability "Polling"
capability "Refresh"
capability "Sensor"
capability "Health Check"
fingerprint mfr:"0063", prod:"4457", deviceJoinName: "Z-Wave Wall Dimmer"
fingerprint mfr:"0063", prod:"4944", deviceJoinName: "Z-Wave Wall Dimmer"
@@ -83,8 +82,6 @@ metadata {
}
def updated(){
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
switch (ledIndicator) {
case "on":
indicatorWhenOn()
@@ -218,13 +215,6 @@ def poll() {
zwave.switchMultilevelV1.switchMultilevelGet().format()
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
refresh()
}
def refresh() {
log.debug "refresh() is called"
def commands = []

View File

@@ -11,9 +11,9 @@ metadata {
capability "Color Temperature"
capability "Switch"
capability "Switch Level" // brightness
capability "Polling"
capability "Refresh"
capability "Sensor"
capability "Health Check"
}
simulator {
@@ -23,6 +23,7 @@ metadata {
tiles(scale: 2) {
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "unreachable", label: "?", action:"refresh.refresh", icon:"http://hosted.lifx.co/smartthings/v1/196xUnreachable.png", backgroundColor:"#666666"
attributeState "on", label:'${name}', action:"switch.off", icon:"http://hosted.lifx.co/smartthings/v1/196xOn.png", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"http://hosted.lifx.co/smartthings/v1/196xOff.png", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'Turning on', action:"switch.off", icon:"http://hosted.lifx.co/smartthings/v1/196xOn.png", backgroundColor:"#79b821", nextState:"turningOff"
@@ -63,8 +64,12 @@ metadata {
}
}
void installed() {
sendEvent(name: "DeviceWatch-Enroll", value: "{\"protocol\": \"cloud\", \"scheme\":\"untracked\", \"hubHardwareId\": \"${device?.hub?.hardwareID}\"}")
// parse events into attributes
def parse(String description) {
if (description == 'updated') {
return // don't poll when config settings is being updated as it may time out
}
poll()
}
// handle commands
@@ -187,17 +192,14 @@ def off() {
return []
}
def refresh() {
log.debug "Executing 'refresh'"
def poll() {
log.debug "Executing 'poll' for ${device} ${this} ${device.deviceNetworkId}"
def resp = parent.apiGET("/lights/${selector()}")
if (resp.status == 404) {
state.online = false
sendEvent(name: "DeviceWatch-DeviceStatusUpdate", value: "offline", displayed: false)
log.warn "$device is Offline"
sendEvent(name: "switch", value: "unreachable")
return []
} else if (resp.status != 200) {
log.error("Unexpected result in refresh(): [${resp.status}] ${resp.data}")
log.error("Unexpected result in poll(): [${resp.status}] ${resp.data}")
return []
}
def data = resp.data[0]
@@ -206,20 +208,19 @@ def refresh() {
sendEvent(name: "label", value: data.label)
sendEvent(name: "level", value: Math.round((data.brightness ?: 1) * 100))
sendEvent(name: "switch.setLevel", value: Math.round((data.brightness ?: 1) * 100))
sendEvent(name: "switch", value: data.power)
sendEvent(name: "switch", value: data.connected ? data.power : "unreachable")
sendEvent(name: "color", value: colorUtil.hslToHex((data.color.hue / 3.6) as int, (data.color.saturation * 100) as int))
sendEvent(name: "hue", value: data.color.hue / 3.6)
sendEvent(name: "saturation", value: data.color.saturation * 100)
sendEvent(name: "colorTemperature", value: data.color.kelvin)
sendEvent(name: "model", value: data.product.name)
sendEvent(name: "model", value: "${data.product.company} ${data.product.name}")
if (data.connected) {
sendEvent(name: "DeviceWatch-DeviceStatus", value: "online", displayed: false)
log.debug "$device is Online"
} else {
sendEvent(name: "DeviceWatch-DeviceStatus", value: "offline", displayed: false)
log.warn "$device is Offline"
return []
}
def refresh() {
log.debug "Executing 'refresh'"
poll()
}
def selector() {

View File

@@ -10,9 +10,9 @@ metadata {
capability "Color Temperature"
capability "Switch"
capability "Switch Level" // brightness
capability "Polling"
capability "Refresh"
capability "Sensor"
capability "Health Check"
}
simulator {
@@ -22,12 +22,13 @@ metadata {
tiles(scale: 2) {
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "unreachable", label: "?", action:"refresh.refresh", icon:"http://hosted.lifx.co/smartthings/v1/196xUnreachable.png", backgroundColor:"#666666"
attributeState "on", label:'${name}', action:"switch.off", icon:"http://hosted.lifx.co/smartthings/v1/196xOn.png", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"http://hosted.lifx.co/smartthings/v1/196xOff.png", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'Turning on', action:"switch.off", icon:"http://hosted.lifx.co/smartthings/v1/196xOn.png", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'Turning off', action:"switch.on", icon:"http://hosted.lifx.co/smartthings/v1/196xOff.png", backgroundColor:"#ffffff", nextState:"turningOn"
}
}
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
attributeState "level", action:"switch level.setLevel"
}
@@ -52,10 +53,15 @@ metadata {
main "switch"
details(["switch", "colorTempSliderControl", "colorTemp", "refresh"])
}
}
void installed() {
sendEvent(name: "DeviceWatch-Enroll", value: "{\"protocol\": \"cloud\", \"scheme\":\"untracked\", \"hubHardwareId\": \"${device?.hub?.hardwareID}\"}")
// parse events into attributes
def parse(String description) {
if (description == 'updated') {
return // don't poll when config settings is being updated as it may time out
}
poll()
}
// handle commands
@@ -116,17 +122,14 @@ def off() {
return []
}
def refresh() {
log.debug "Executing 'refresh'"
def poll() {
log.debug "Executing 'poll' for ${device} ${this} ${device.deviceNetworkId}"
def resp = parent.apiGET("/lights/${selector()}")
if (resp.status == 404) {
state.online = false
sendEvent(name: "DeviceWatch-DeviceStatusUpdate", value: "offline", displayed: false)
log.warn "$device is Offline"
sendEvent(name: "switch", value: "unreachable")
return []
} else if (resp.status != 200) {
log.error("Unexpected result in refresh(): [${resp.status}] ${resp.data}")
log.error("Unexpected result in poll(): [${resp.status}] ${resp.data}")
return []
}
def data = resp.data[0]
@@ -134,17 +137,16 @@ def refresh() {
sendEvent(name: "label", value: data.label)
sendEvent(name: "level", value: Math.round((data.brightness ?: 1) * 100))
sendEvent(name: "switch.setLevel", value: Math.round((data.brightness ?: 1) * 100))
sendEvent(name: "switch", value: data.power)
sendEvent(name: "switch", value: data.connected ? data.power : "unreachable")
sendEvent(name: "colorTemperature", value: data.color.kelvin)
sendEvent(name: "model", value: data.product.name)
if (data.connected) {
sendEvent(name: "DeviceWatch-DeviceStatus", value: "online", displayed: false)
log.debug "$device is Online"
} else {
sendEvent(name: "DeviceWatch-DeviceStatus", value: "offline", displayed: false)
log.warn "$device is Offline"
return []
}
def refresh() {
log.debug "Executing 'refresh'"
poll()
}
def selector() {

View File

@@ -74,15 +74,6 @@ metadata {
}
}
def installed() {
log.debug "${device} installed"
}
def updated() {
log.debug "${device} updated"
configureHealthCheck()
}
// Parse incoming device messages to generate events
def parse(String description) {
log.debug "description is $description"
@@ -149,14 +140,10 @@ def refresh() {
zigbee.onOffRefresh() + zigbee.electricMeasurementPowerRefresh()
}
def configureHealthCheck() {
def configure() {
// Device-Watch allows 3 check-in misses from device (plus 1 min lag time)
// enrolls with default periodic reporting until newer 5 min interval is confirmed
sendEvent(name: "checkInterval", value: 3 * 10 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
}
def configure() {
// OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity
refresh() + zigbee.onOffConfig(0, 300) + powerConfig()

View File

@@ -84,15 +84,6 @@ metadata {
}
}
def installed() {
log.debug "${device} installed"
}
def updated() {
log.debug "${device} updated"
configureHealthCheck()
}
def parse(String description) {
log.debug "description: $description"
@@ -312,13 +303,11 @@ def refresh() {
return refreshCmds + enrollResponse()
}
def configureHealthCheck() {
def configure() {
// Device-Watch allows 3 check-in misses from device (plus 1 min lag time)
// enrolls with default periodic reporting until newer 5 min interval is confirmed
sendEvent(name: "checkInterval", value: 3 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
}
def configure() {
// temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity
// battery minReport 30 seconds, maxReportTime 6 hrs by default
return refresh() + zigbee.batteryConfig() + zigbee.temperatureConfig(30, 300) // send refresh cmds as part of config

View File

@@ -88,15 +88,6 @@ metadata {
}
}
def installed() {
log.debug "${device} installed"
}
def updated() {
log.debug "${device} updated"
configureHealthCheck()
}
def parse(String description) {
log.debug "description: $description"
@@ -327,13 +318,11 @@ def refresh() {
return refreshCmds + enrollResponse()
}
def configureHealthCheck() {
def configure() {
// Device-Watch allows 3 check-in misses from device (plus 1 min lag time)
// enrolls with default periodic reporting until newer 5 min interval is confirmed
sendEvent(name: "checkInterval", value: 3 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
}
def configure() {
// temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity
// battery minReport 30 seconds, maxReportTime 6 hrs by default
return refresh() + zigbee.batteryConfig() + zigbee.temperatureConfig(30, 300) // send refresh cmds as part of config

View File

@@ -115,34 +115,6 @@ metadata {
}
}
def installed() {
log.debug "${device} installed"
}
def updated() {
log.debug "updated called"
log.info "garage value : $garageSensor"
if (garageSensor == "Yes") {
def descriptionText = "Updating device to garage sensor"
if (device.latestValue("status") == "open") {
sendEvent(name: 'status', value: 'garage-open', descriptionText: descriptionText, translatable: true)
}
else if (device.latestValue("status") == "closed") {
sendEvent(name: 'status', value: 'garage-closed', descriptionText: descriptionText, translatable: true)
}
}
else {
def descriptionText = "Updating device to open/close sensor"
if (device.latestValue("status") == "garage-open") {
sendEvent(name: 'status', value: 'open', descriptionText: descriptionText, translatable: true)
}
else if (device.latestValue("status") == "garage-closed") {
sendEvent(name: 'status', value: 'closed', descriptionText: descriptionText, translatable: true)
}
}
configureHealthCheck()
}
def parse(String description) {
Map map = [:]
if (description?.startsWith('catchall:')) {
@@ -274,6 +246,29 @@ private Map parseIasMessage(String description) {
return resultMap
}
def updated() {
log.debug "updated called"
log.info "garage value : $garageSensor"
if (garageSensor == "Yes") {
def descriptionText = "Updating device to garage sensor"
if (device.latestValue("status") == "open") {
sendEvent(name: 'status', value: 'garage-open', descriptionText: descriptionText, translatable: true)
}
else if (device.latestValue("status") == "closed") {
sendEvent(name: 'status', value: 'garage-closed', descriptionText: descriptionText, translatable: true)
}
}
else {
def descriptionText = "Updating device to open/close sensor"
if (device.latestValue("status") == "garage-open") {
sendEvent(name: 'status', value: 'open', descriptionText: descriptionText, translatable: true)
}
else if (device.latestValue("status") == "garage-closed") {
sendEvent(name: 'status', value: 'closed', descriptionText: descriptionText, translatable: true)
}
}
}
def getTemperature(value) {
def celsius = Integer.parseInt(value, 16).shortValue() / 100
if(getTemperatureScale() == "C"){
@@ -416,13 +411,11 @@ def refresh() {
return refreshCmds + enrollResponse()
}
def configureHealthCheck(){
def configure() {
// Device-Watch allows 3 check-in misses from device (plus 1 min lag time)
// enrolls with default periodic reporting until newer 5 min interval is confirmed
sendEvent(name: "checkInterval", value: 3 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
}
def configure() {
log.debug "Configuring Reporting"
// temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity

View File

@@ -75,15 +75,6 @@ metadata {
}
}
def installed() {
log.debug "${device} installed"
}
def updated() {
log.debug "${device} updated"
configureHealthCheck()
}
def parse(String description) {
log.debug "description: $description"
@@ -274,12 +265,11 @@ def refresh() {
return refreshCmds + enrollResponse()
}
def configureHealthCheck() {
def configure() {
// Device-Watch allows 3 check-in misses from device (plus 1 min lag time)
// enrolls with default periodic reporting until newer 5 min interval is confirmed
sendEvent(name: "checkInterval", value: 3 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
}
def configure() {
log.debug "Configuring Reporting, IAS CIE, and Bindings."
// temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity

View File

@@ -69,15 +69,6 @@ metadata {
}
}
def installed() {
log.debug "${device} installed"
}
def updated() {
log.debug "${device} updated"
configureHealthCheck()
}
def parse(String description) {
log.debug "description: $description"
@@ -277,13 +268,11 @@ def refresh()
zigbee.readAttribute(0x0001, 0x0020)
}
def configureHealthCheck() {
def configure() {
// Device-Watch allows 3 check-in misses from device (plus 1 min lag time)
// enrolls with default periodic reporting until newer 5 min interval is confirmed
sendEvent(name: "checkInterval", value: 3 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
}
def configure() {
log.debug "Configuring Reporting and Bindings."
def humidityConfigCmds = [
"zdo bind 0x${device.deviceNetworkId} 1 1 0xFC45 {${device.zigbeeId}} {}", "delay 500",

View File

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

View File

@@ -1,41 +0,0 @@
# GE Plug-In/In-Wall Smart Dimmer (ZigBee)
Works with:
* [GE In-Wall Smart Dimmer (ZigBee)](https://shop.smartthings.com/#!/products/ge-in-wall-smart-dimmer-switch)
* [GE Plug-In Smart Dimmer (ZigBee)](https://www.smartthings.com/works-with-smartthings/ge/ge-plug-in-smart-dimmer-zigbee)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Troubleshooting](#Troubleshooting)
## 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
* **Power Meter** - ability to check the power meter(energy consumption) of device
* **Sensor** - represents the device sensor capability
* **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 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.
Enrolls with default periodic reporting until newer 5 min interval is confirmed
It then enrolls the device with updated checkInterval i.e. 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:
* [GE Z-Wave In-Wall Smart Dimmer (GE 45857) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/204988564-GE-In-Wall-Smart-Dimmer-45857GE-ZigBee-)
* [GE Zigbee Plug-in Smart Dimmer (GE 45852) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/205239280-GE-Plug-In-Smart-Dimmer-45852GE-ZigBee-)

View File

@@ -21,7 +21,6 @@ metadata {
capability "Sensor"
capability "Switch"
capability "Switch Level"
capability "Health Check"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B04"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702"
@@ -71,20 +70,8 @@ def parse(String description) {
}
}
else {
def cluster = zigbee.parse(description)
if (cluster && cluster.clusterId == 0x0006 && cluster.command == 0x07) {
if (cluster.data[0] == 0x00){
log.debug "ON/OFF REPORTING CONFIG RESPONSE: " + cluster
sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
}
else {
log.warn "ON/OFF REPORTING CONFIG FAILED- error code:${cluster.data[0]}"
}
}
else {
log.warn "DID NOT PARSE MESSAGE for description : $description"
log.debug zigbee.parseDescriptionAsMap(description)
}
log.warn "DID NOT PARSE MESSAGE for description : $description"
log.debug zigbee.parseDescriptionAsMap(description)
}
}
@@ -100,22 +87,11 @@ 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.simpleMeteringPowerRefresh() + zigbee.electricMeasurementPowerRefresh() + zigbee.onOffConfig(0, 300) + zigbee.levelConfig() + zigbee.simpleMeteringPowerConfig() + zigbee.electricMeasurementPowerConfig()
zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.simpleMeteringPowerRefresh() + zigbee.electricMeasurementPowerRefresh() + zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.simpleMeteringPowerConfig() + zigbee.electricMeasurementPowerConfig()
}
def configure() {
log.debug "Configuring Reporting and Bindings."
// Device-Watch allows 3 check-in misses from device (plus 1 min lag time)
// enrolls with default periodic reporting until newer 5 min interval is confirmed
sendEvent(name: "checkInterval", value: 3 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
refresh()
}

View File

@@ -48,15 +48,6 @@ metadata {
}
}
def installed() {
log.debug "${device} installed"
}
def updated() {
log.debug "${device} updated"
configureHealthCheck()
}
// Parse incoming device messages to generate events
def parse(String description) {
log.debug "description is $description"
@@ -109,13 +100,12 @@ def refresh() {
zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.onOffConfig(0, 300) + zigbee.levelConfig()
}
def configureHealthCheck() {
def configure() {
log.debug "Configuring Reporting and Bindings."
// Device-Watch allows 3 check-in misses from device (plus 1 min lag time)
// enrolls with default periodic reporting until newer 5 min interval is confirmed
sendEvent(name: "checkInterval", value: 3 * 10 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
}
def configure() {
// OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity
zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.onOffConfig(0, 300) + zigbee.levelConfig()
}

View File

@@ -70,16 +70,6 @@ metadata {
}
}
def installed() {
log.debug "${device} installed"
}
def updated() {
log.debug "${device} updated"
configureHealthCheck()
}
//Globals
private getATTRIBUTE_HUE() { 0x0000 }
private getATTRIBUTE_SATURATION() { 0x0001 }
@@ -148,17 +138,16 @@ def ping() {
}
def refresh() {
// OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity
zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_COLOR_TEMPERATURE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION) + zigbee.onOffConfig(0, 300) + zigbee.levelConfig() + zigbee.colorTemperatureConfig() + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE, 0x20, 1, 3600, 0x01) + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION, 0x20, 1, 3600, 0x01)
}
def configureHealthCheck() {
def configure() {
log.debug "Configuring Reporting and Bindings."
// Device-Watch allows 3 check-in misses from device (plus 1 min lag time)
// enrolls with default periodic reporting until newer 5 min interval is confirmed
sendEvent(name: "checkInterval", value: 3 * 10 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
}
def configure() {
// OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity
refresh()
}

View File

@@ -21,7 +21,6 @@ metadata {
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"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0006", outClusters: "000A", manufacturer: "HAI", model: "65A21-1", deviceJoinName: "Leviton Wireless Load Control Module-30amp"
}
// simulator metadata

View File

@@ -69,15 +69,6 @@ metadata {
}
}
def installed() {
log.debug "${device} installed"
}
def updated() {
log.debug "${device} updated"
configureHealthCheck()
}
// Parse incoming device messages to generate events
def parse(String description) {
log.debug "description is $description"
@@ -130,17 +121,16 @@ def ping() {
}
def refresh() {
// OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity
zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh() + zigbee.onOffConfig(0, 300) + zigbee.levelConfig() + zigbee.colorTemperatureConfig()
}
def configureHealthCheck() {
def configure() {
log.debug "Configuring Reporting and Bindings."
// Device-Watch allows 3 check-in misses from device (plus 1 min lag time)
// enrolls with default periodic reporting until newer 5 min interval is confirmed
sendEvent(name: "checkInterval", value: 3 * 10 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
}
def configure() {
// OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity
refresh()
}

View File

@@ -11,9 +11,6 @@
* for the specific language governing permissions and limitations under the License.
*
*/
import groovy.transform.Field
@Field Boolean hasConfiguredHealthCheck = false
metadata {
definition (name: "ZLL Dimmer Bulb", namespace: "smartthings", author: "SmartThings") {
@@ -24,7 +21,6 @@ metadata {
capability "Refresh"
capability "Switch"
capability "Switch Level"
capability "Health Check"
//fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0000,0019"
fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019"
@@ -100,38 +96,7 @@ def poll() {
refresh()
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
return zigbee.levelRefresh()
}
def healthPoll() {
log.debug "healthPoll()"
def cmds = refresh()
cmds.each{ sendHubCommand(new physicalgraph.device.HubAction(it))}
}
def configureHealthCheck() {
Integer hcIntervalMinutes = 12
if (!hasConfiguredHealthCheck) {
log.debug "Configuring Health Check, Reporting"
unschedule("healthPoll")
runEvery5Minutes("healthPoll")
// Device-Watch allows 2 check-in misses from device
sendEvent(name: "checkInterval", value: hcIntervalMinutes * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
hasConfiguredHealthCheck = true
}
}
def configure() {
log.debug "configure()"
log.debug "Configuring Reporting and Bindings."
zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.onOffRefresh() + zigbee.levelRefresh()
configureHealthCheck()
}
def updated() {
log.debug "updated()"
configureHealthCheck()
}

View File

@@ -11,9 +11,6 @@
* for the specific language governing permissions and limitations under the License.
*
*/
import groovy.transform.Field
@Field Boolean hasConfiguredHealthCheck = false
metadata {
definition (name: "ZLL White Color Temperature Bulb", namespace: "smartthings", author: "SmartThings") {
@@ -25,7 +22,6 @@ metadata {
capability "Refresh"
capability "Switch"
capability "Switch Level"
capability "Health Check"
attribute "colorName", "string"
command "setGenericName"
@@ -100,41 +96,9 @@ def poll() {
zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh()
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
return zigbee.levelRefresh()
}
def healthPoll() {
log.debug "healthPoll()"
def cmds = zigbee.onOffRefresh() + zigbee.levelRefresh()
cmds.each{ sendHubCommand(new physicalgraph.device.HubAction(it))}
}
def configureHealthCheck() {
Integer hcIntervalMinutes = 12
if (!hasConfiguredHealthCheck) {
log.debug "Configuring Health Check, Reporting"
unschedule("healthPoll")
runEvery5Minutes("healthPoll")
// Device-Watch allows 2 check-in misses from device
sendEvent(name: "checkInterval", value: hcIntervalMinutes * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
hasConfiguredHealthCheck = true
}
}
def configure() {
log.debug "configure()"
configureHealthCheck()
log.debug "Configuring Reporting and Bindings."
zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.colorTemperatureConfig() + zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh()
}
def updated() {
log.debug "updated()"
configureHealthCheck()
}
def setColorTemperature(value) {

View File

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

View File

@@ -1,39 +0,0 @@
# Z-wave Dimmer
Works with:
* [Leviton Plug-in Lamp Dimmer Module (DZPD3-1LW)](http://www.leviton.com/OA_HTML/ProductDetail.jsp?partnumber=DZPD3-1LW)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Troubleshooting](#troubleshooting)
## Capabilities
* **Switch Level** - it's defined to accept two parameters, the level and the rate of dimming
* **Actuator** - represents that a Device has commands
* **Health Check** - indicates ability to get device health notifications
* **Switch** - can detect state (possible values: on/off)
* **Polling** - represents that poll() can be implemented for the device
* **Refresh** - _refresh()_ command for status updates
* **Sensor** - detects sensor events
## Device Health
A Category C5 Leviton Plug-in Lamp Dimmer Module (DZPA1-1LW) (Z-Wave) polled by the hub.
As of hubCore version 0.14.38 the hub sends up reports every 15 minutes regardless of whether the state changed.
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*15 + 2)mins = 32 mins.
Not to mention after going OFFLINE when the device is plugged back in, it might take a considerable amount of time for
the device to appear as ONLINE again. This is because if this listening device does not respond to two poll requests in a row,
it is not polled for 5 minutes by the hub. This can delay up the process of being marked ONLINE by quite some time.
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
Pairing needs to be tried again by placing the device closer to the hub.
Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link:
* [Leviton Plug-in Lamp Dimmer Module (DZPD3-1LW) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/206171053-How-to-connect-Leviton-Z-Wave-devices)

View File

@@ -15,14 +15,12 @@ metadata {
definition (name: "Z-Wave Dimmer Switch Generic", namespace: "smartthings", author: "SmartThings") {
capability "Switch Level"
capability "Actuator"
capability "Health Check"
capability "Switch"
capability "Polling"
capability "Refresh"
capability "Sensor"
fingerprint inClusters: "0x26", deviceJoinName: "Z-Wave Dimmer"
fingerprint mfr:"001D", prod:"1902", deviceJoinName: "Z-Wave Dimmer"
}
simulator {
@@ -70,11 +68,6 @@ metadata {
}
}
def updated(){
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
}
def parse(String description) {
def result = null
if (description != "updated") {
@@ -192,13 +185,6 @@ def poll() {
zwave.switchMultilevelV1.switchMultilevelGet().format()
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
refresh()
}
def refresh() {
log.debug "refresh() is called"
def commands = []

View File

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

View File

@@ -1,39 +0,0 @@
# Z-wave Switch
Works with:
* [Leviton Appliance Module (DZPA1-1LW)](https://support.smartthings.com/hc/en-us/articles/205881176-Leviton-Appliance-Module-DZPA1-1LW-)
* [GE Plug-In Outdoor Smart Switch (GE 12720) (Z-Wave)](https://support.smartthings.com/hc/en-us/articles/200903080-GE-Plug-In-Outdoor-Smart-Switch-GE-12720-Z-Wave-)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
## Capabilities
* **Actuator** - represents that a Device has commands
* **Health Check** - indicates ability to get device health notifications
* **Switch** - can detect state (possible values: on/off)
* **Polling** - represents that poll() can be implemented for the device
* **Refresh** - _refresh()_ command for status updates
* **Sensor** - detects sensor events
## Device Health
A Category C5 Leviton Appliance Module (DZPA1-1LW) and GE Plug-In Outdoor Smart Switch (GE 12720) (Z-Wave) polled by the hub.
As of hubCore version 0.14.38 the hub sends up reports every 15 minutes regardless of whether the state changed.
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*15 + 2)mins = 32 mins.
Not to mention after going OFFLINE when the device is plugged back in, it might take a considerable amount of time for
the device to appear as ONLINE again. This is because if this listening device does not respond to two poll requests in a row,
it is not polled for 5 minutes by the hub. This can delay up the process of being marked ONLINE by quite some time.
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
Pairing needs to be tried again by placing the device closer to the hub.
Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link:
* [Leviton Appliance Module (DZPA1-1LW) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/205881176-Leviton-Appliance-Module-DZPA1-1LW-)
* [GE Plug-In Outdoor Smart Switch (GE 12720) (Z-Wave) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/200903080-GE-Plug-In-Outdoor-Smart-Switch-GE-12720-Z-Wave-)

View File

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

View File

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

View File

@@ -1,49 +0,0 @@
# Z-Wave Switch
Works with:
* [GE Z-Wave Plug-In Smart Switch (12719)](http://products.z-wavealliance.org/products/1193)
* [GE Z-Wave In-Wall Smart Outlet (12721)](http://products.z-wavealliance.org/products/1195)
* [GE Z-Wave In-Wall Smart Switch (12722)](http://products.z-wavealliance.org/products/1196)
* [GE Z-Wave In-Wall Smart Toggle Switch (12727)](http://products.z-wavealliance.org/products/1200)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Troubleshooting](#Troubleshooting)
## Capabilities
* **Actuator** - represents that a Device has commands
* **Indicator** - gives you the ability to set the indicator LED light on a Z-Wave switch
* **Switch** - can detect state (possible values: on/off)
* **Polling** - represents that poll() can be implemented for the device
* **Refresh** - _refresh()_ command for status updates
* **Sensor** - detects sensor events
* **Health Check** - indicates ability to get device health notifications
## Device Health
Z-Wave Switches (Plug-In, In-Wall(Toggle Switch, Switch, Outlet)) are polled by the hub.
As of hubCore version 0.14.38 the hub sends up reports every 15 minutes regardless of whether the state changed.
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*15 + 2)mins = 32 mins.
Not to mention after going OFFLINE when the device is plugged back in, it might take a considerable amount of time for
the device to appear as ONLINE again. This is because if this listening device does not respond to two poll requests in a row,
it is not polled for 5 minutes by the hub. This can delay up the process of being marked ONLINE by quite some time.
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
Pairing needs to be tried again by placing the device closer to the hub.
Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link:
* [General Z-Wave Dimmer/Switch Troubleshooting](https://support.smartthings.com/hc/en-us/articles/200955890-Troubleshooting-GE-in-wall-switch-or-dimmer-won-t-respond-to-commands-or-automations-Z-Wave-)
* [GE Z-Wave Plug-In Smart Switch (12719) Troubleshooting](https://support.smartthings.com/hc/en-us/articles/200903070-GE-Plug-In-Smart-Switch-GE-12719-Z-Wave)
* [GE Z-Wave In-Wall Smart Outlet (12721) Troubleshooting](https://support.smartthings.com/hc/en-us/articles/200903020-GE-In-Wall-Smart-Outlet-GE-12721-Z-Wave)
* [GE Z-Wave In-Wall Smart Switch (12722) Troubleshooting](https://support.smartthings.com/hc/en-us/articles/200902540-GE-In-Wall-Smart-Switch-GE-12722-Z-Wave)
* [GE Z-Wave In-Wall Smart Toggle Switch (12727) Troubleshooting](https://support.smartthings.com/hc/en-us/articles/207568933-GE-In-Wall-Smart-Toggle-Switch-GE-12727-Z-Wave)

View File

@@ -19,7 +19,6 @@ metadata {
capability "Polling"
capability "Refresh"
capability "Sensor"
capability "Health Check"
fingerprint mfr:"0063", prod:"4952", deviceJoinName: "Z-Wave Wall Switch"
fingerprint mfr:"0063", prod:"5257", deviceJoinName: "Z-Wave Wall Switch"
@@ -65,8 +64,6 @@ metadata {
}
def updated(){
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
switch (ledIndicator) {
case "on":
indicatorWhenOn()
@@ -159,13 +156,6 @@ def poll() {
])
}
/**
* PING is used by Device-Watch in attempt to reach the Device
**/
def ping() {
refresh()
}
def refresh() {
delayBetween([
zwave.switchBinaryV1.switchBinaryGet().format(),

View File

@@ -1,317 +0,0 @@
/**
* Trend Setter - Group
*
* Copyright 2015 Chris Kitch
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*
*/
definition(
name: "Group",
namespace: "kriskit.trendSetter",
author: "Chris Kitch",
description: "A child SmartApp for Trend Setter for handling a group of devices.",
category: "My Apps",
iconUrl: "https://cdn.rawgit.com/Kriskit/SmartThingsPublic/master/smartapps/kriskit/trendsetter/icon.png",
iconX2Url: "https://cdn.rawgit.com/Kriskit/SmartThingsPublic/master/smartapps/kriskit/trendsetter/icon@2x.png",
iconX3Url: "https://cdn.rawgit.com/Kriskit/SmartThingsPublic/master/smartapps/kriskit/trendsetter/icon@3x.png",
parent: "kriskit.trendsetter:Trend Setter")
def version() {
return "1.0"
}
def typeDefinitions() {
return [
[
type: "switch",
singular: "Switch",
plural: "Switches",
deviceType: "Switch Group Device",
attributes: [
[name: "switch"]
]
],
[
type: "switchLevel",
singular: "Dimmer",
plural: "Dimmers",
deviceType: "Dimmer Group Device",
inherits: "switch",
attributes: [
[name: "level"]
]
],
[
type: "colorControl",
singular: "Colorful Light",
plural: "Colorful Lights",
deviceType: "Colorful Light Group Device",
inherits: "switchLevel",
attributes: [
[name: "hue"],
[name: "saturation"],
[name: "color"]
]
],
[
type: "powerMeter",
singular: "Power Meter",
plural: "Power Meters",
deviceType: "Power Meter Group Device",
attributes: [
[name: "power"]
]
]
]
}
// Setup
preferences {
page(name: "configure")
}
def configure() {
atomicState.typeDefinitions = null
def controller = getControllerDevice();
dynamicPage(name: "configure", uninstall: controller != null, install: true) {
if (!controller) {
section {
input "deviceType", "enum", title: "Device Type", required: true, submitOnChange: true, options: getDeviceTypeOptions()
paragraph "This cannot be changed once the group is created.", color: "#ffcc00"
}
}
if (deviceType) {
def definition = getTypeDefinition(deviceType)
section(title: controller == null ? "Grouping" : null) {
label title: "Group Name", required: true
input "devices", "capability.${deviceType}", title: "${definition.plural}", multiple: true, required: true, submitOnChange: controller != null
if (selectedDevicesContainsController()) {
paragraph "WARNING: You have selected the controller ${definition.singular.toLowerCase()} for this group. This will likely cause unexpected behaviour.\n\nPlease uncheck the '${controller.displayName}' from the selected ${definition.plural.toLowerCase()}.",
image: "https://cdn2.iconfinder.com/data/icons/freecns-cumulus/32/519791-101_Warning-512.png"
}
}
if (controller == null) {
section(title: "Controller") {
input "deviceName", "text", title: "${definition.singular} Name", required: true, description: "For the controlling virtual ${definition.singular.toLowerCase()} to be created"
}
}
if (definition.advanced) {
section(title: "Advanced", hidden: true, hideable: true) {
}
}
}
}
}
def installed() {
log.debug "Installed with settings: ${settings}"
installControllerDevice()
initialize()
}
def uninstalled() {
log.debug "Uninstalled"
}
def installControllerDevice() {
def definition = getTypeDefinition()
log.debug "Installing switch group controller device..."
addChildDevice("kriskit.trendSetter", definition.deviceType, UUID.randomUUID().toString(), null, ["name": deviceName, "label": deviceName, completedSetup: true])
}
def updated() {
log.debug "Updated with settings: ${settings}"
unsubscribe()
initialize()
}
def initialize() {
def definition = getTypeDefinition()
addSubscriptions(definition)
def namesToCheck = definition.attributes?.collect { it.name }
updateControllerState(namesToCheck)
}
def addSubscriptions(definition) {
def controller = getControllerDevice()
definition.attributes?.each {
log.debug "Subscribing to ${it.name}..."
subscribe(devices, it.name, onDeviceAttributeChange)
}
}
// Subscription Handlers
def onDeviceAttributeChange(evt) {
def namesToCheck = atomicState.namesToCheck ?: []
log.debug "Device state change: ${evt.device.displayName} -> ${evt.name} = ${evt.value}"
if (!namesToCheck.any { it == evt.name })
namesToCheck.push(evt.name)
atomicState.namesToCheck = namesToCheck
runIn(1, "updateControllerState")
}
def updateControllerState() {
def namesToCheck = atomicState.namesToCheck
updateControllerState(namesToCheck)
atomicState.namesToCheck = null
}
def updateControllerState(namesToCheck) {
if (!namesToCheck)
return
def controller = getControllerDevice()
namesToCheck?.each { name ->
def values = devices?.currentValue(name)
values?.removeAll([null])
log.debug "Updating Controller State: $name -> $values"
controller.groupSync(name, values)
}
}
def performGroupCommand(command, arguments = null) {
runCommand(devices, command, arguments ?: [])
}
def runCommand(target, command, args) {
log.debug "Running command '${command}' with arguments ${args} on ${target}..."
$performCommand(target, command, args)
}
def getGroupCurrentValues(name) {
return devices?.currentValue(name)
}
// Utilities
def getTypeDefinitions() {
if (atomicState.version != version()) {
atomicState.typeDefinitions = null
atomicState.version = version()
}
if (atomicState.typeDefinitions)
return atomicState.typeDefinitions
log.debug "Building type definitions..."
def result = []
def definitions = typeDefinitions()
definitions?.each { definition ->
if (definition.inherits)
definition = mergeAttributes(definition, definitions.find { it.type == definition.inherits })
result.push(definition)
}
atomicState.typeDefinitions = result
return result
}
def mergeAttributes(definition, inheritedDefinition) {
inheritedDefinition.attributes?.each { attr ->
if (!definition.attributes?.any { it.name == attr.name })
definition.attributes.push(attr)
}
if (inheritedDefinition.inherits) {
def definitions = typeDefinitions()
definition = mergeAttributes(definition, definitions.find { it.type == inheritedDefinition.inherits })
}
return definition
}
def getControllerDevice() {
return getChildDevices()?.find { true }
}
def getTypeDefinition() {
return getTypeDefinition(deviceType)
}
def getTypeDefinition(type) {
return getTypeDefinitions().find {
it.type == type
}
}
def getDeviceTypeOptions() {
return getTypeDefinitions().collect {
["${it.type}": it.singular]
}
}
def selectedDevicesContainsController() {
def controller = getControllerDevice()
return devices?.any {
it?.deviceNetworkId == controller?.deviceNetworkId
}
}
private $performCommand(target, command, args) {
switch(args?.size()) {
default:
target?."$command"()
break
case 1:
target?."$command"(args[0])
break
case 2:
target?."$command"(args[0], args[1])
break
case 3:
target?."$command"(args[0], args[1], args[2])
break
case 4:
target?."$command"(args[0], args[1], args[2], args[3])
break
case 5:
target?."$command"(args[0], args[1], args[2], args[3], args[4], args[5])
break
case 6:
target?."$command"(args[0], args[1], args[2], args[3], args[4], args[5], args[6])
break
case 7:
target?."$command"(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7])
break
case 8:
target?."$command"(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8])
break
case 9:
target?."$command"(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9])
break
}
}

View File

@@ -1,58 +0,0 @@
/**
* Trend Setter
*
* Copyright 2015 Chris Kitch
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*
*/
definition(
name: "Trend Setter",
namespace: "kriskit.trendSetter",
author: "Chris Kitch",
description: "Uses virtual child devices to group other devices together and perform commands and aggregate data from the group.",
category: "My Apps",
iconUrl: "https://cdn.rawgit.com/Kriskit/SmartThingsPublic/master/smartapps/kriskit/trendsetter/icon.png",
iconX2Url: "https://cdn.rawgit.com/Kriskit/SmartThingsPublic/master/smartapps/kriskit/trendsetter/icon@2x.png",
iconX3Url: "https://cdn.rawgit.com/Kriskit/SmartThingsPublic/master/smartapps/kriskit/trendsetter/icon@3x.png",
singleInstance: true)
preferences {
page(name: "mainPage")
}
def mainPage() {
dynamicPage(name: "mainPage", title: "Your Groups", install: true, uninstall: true, submitOnChange: true) {
section {
app(name: "groups", appName: "Group", namespace: "kriskit.trendSetter", title: "Create Group...", multiple: true)
}
}
}
def installed() {
log.debug "Installed with settings: ${settings}"
initialize()
}
def updated() {
log.debug "Updated with settings: ${settings}"
unsubscribe()
initialize()
}
def initialize() {
// TODO: subscribe to attributes, devices, locations, etc.
}
def childUninstalled() {
}

View File

@@ -242,6 +242,8 @@ def installed() {
} else {
initialize()
}
// Check for new devices and remove old ones every 3 hours
runEvery3Hours('updateDevices')
}
// called after settings are changed
@@ -269,19 +271,9 @@ private removeChildDevices(devices) {
def initialize() {
log.debug "initialize"
updateDevices()
// Check for new devices and remove old ones every 3 hours
runEvery5Minutes('updateDevices')
setupDeviceWatch()
}
// Misc
private setupDeviceWatch() {
def hub = location.hubs[0]
// Make sure that all child devices are enrolled in device watch
getChildDevices().each {
it.sendEvent(name: "DeviceWatch-Enroll", value: "{\"protocol\": \"LAN\", \"scheme\":\"untracked\", \"hubHardwareId\": \"${hub?.hub?.hardwareID}\"}")
}
}
Map apiRequestHeaders() {
return ["Authorization": "Bearer ${state.lifxAccessToken}",
@@ -384,7 +376,7 @@ def updateDevices() {
def data = [
label: device.label,
level: Math.round((device.brightness ?: 1) * 100),
switch: device.power,
switch: device.connected ? device.power : "unreachable",
colorTemperature: device.color.kelvin
]
if (device.product.capabilities.has_color) {
@@ -395,42 +387,18 @@ def updateDevices() {
} else {
childDevice = addChildDevice(app.namespace, "LIFX White Bulb", device.id, null, data)
}
childDevice?.completedSetup = true
} else {
if (device.product.capabilities.has_color) {
sendEvent(name: "color", value: colorUtil.hslToHex((device.color.hue / 3.6) as int, (device.color.saturation * 100) as int))
sendEvent(name: "hue", value: device.color.hue / 3.6)
sendEvent(name: "saturation", value: device.color.saturation * 100)
}
childDevice.sendEvent(name: "label", value: device.label)
childDevice.sendEvent(name: "level", value: Math.round((device.brightness ?: 1) * 100))
childDevice.sendEvent(name: "switch.setLevel", value: Math.round((device.brightness ?: 1) * 100))
childDevice.sendEvent(name: "switch", value: device.power)
childDevice.sendEvent(name: "colorTemperature", value: device.color.kelvin)
childDevice.sendEvent(name: "model", value: device.product.name)
}
if (state.devices[device.id] == null) {
// State missing, add it and set it to opposite status as current status to provoke event below
state.devices[device.id] = [online : !device.connected]
}
if (!state.devices[device.id]?.online && device.connected) {
// Device came online after being offline
childDevice?.sendEvent(name: "DeviceWatch-DeviceStatus", value: "online", displayed: false)
log.debug "$device is back Online"
} else if (state.devices[device.id]?.online && !device.connected) {
// Device went offline after being online
childDevice?.sendEvent(name: "DeviceWatch-DeviceStatus", value: "offline", displayed: false)
log.debug "$device went Offline"
}
state.devices[device.id] = [online: device.connected]
}
getChildDevices().findAll { !selectors.contains("${it.deviceNetworkId}") }.each {
log.info("Deleting ${it.deviceNetworkId}")
state.devices[it.deviceNetworkId] = null
deleteChildDevice(it.deviceNetworkId)
}
runIn(1, 'refreshDevices') // Asynchronously refresh devices so we don't block
}
def refreshDevices() {
log.info("Refreshing all devices...")
getChildDevices().each { device ->
device.refresh()
}
}