Compare commits

..

1 Commits

Author SHA1 Message Date
João Borges
8a175bdac0 MSA-1574: descricao 2016-11-08 04:52:55 -06:00
16 changed files with 133 additions and 124 deletions

View File

@@ -87,7 +87,7 @@ metadata {
def parse(String description) { def parse(String description) {
def resultMap = zigbee.getEvent(description) def resultMap = zigbee.getEvent(description)
if (resultMap) { if (resultMap) {
if (resultMap.name != "level" || resultMap.value != 0) { // Ignore level reports of 0 sent when bulb turns off if ((resultMap.name == "level" && state.trigger == "setLevel") || resultMap.name != "level") { //doing this to account for weird level reporting bug with GE Link Bulbs
sendEvent(resultMap) sendEvent(resultMap)
} }
} }
@@ -188,10 +188,12 @@ def updated() {
} }
def on() { def on() {
state.trigger = "on/off"
zigbee.on() zigbee.on()
} }
def off() { def off() {
state.trigger = "on/off"
zigbee.off() zigbee.off()
} }
@@ -204,6 +206,7 @@ def refresh() {
} }
def setLevel(value) { def setLevel(value) {
state.trigger = "setLevel"
def cmd def cmd
def delayForRefresh = 500 def delayForRefresh = 500
if (dimRate && (state?.rate != null)) { if (dimRate && (state?.rate != null)) {

View File

@@ -69,17 +69,15 @@ metadata {
def parse(String description) { def parse(String description) {
log.debug "description is $description" log.debug "description is $description"
def event = [:]
def finalResult = isKnownDescription(description) def finalResult = isKnownDescription(description)
if (finalResult != "false") { if (finalResult != "false") {
log.info finalResult log.info finalResult
if (finalResult.type == "update") { if (finalResult.type == "update") {
log.info "$device updates: ${finalResult.value}" log.info "$device updates: ${finalResult.value}"
event = null
} }
else if (finalResult.type == "power") { else if (finalResult.type == "power") {
def powerValue = (finalResult.value as Integer)/10 def powerValue = (finalResult.value as Integer)/10
event = createEvent(name: "power", value: powerValue) sendEvent(name: "power", value: powerValue)
/* /*
Dividing by 10 as the Divisor is 10000 and unit is kW for the device. AttrId: 0302 and 0300. Simplifying to 10 Dividing by 10 as the Divisor is 10000 and unit is kW for the device. AttrId: 0302 and 0300. Simplifying to 10
@@ -89,14 +87,13 @@ def parse(String description) {
*/ */
} }
else { else {
event = createEvent(name: finalResult.type, value: finalResult.value) sendEvent(name: finalResult.type, value: finalResult.value)
} }
} }
else { else {
log.warn "DID NOT PARSE MESSAGE for description : $description" log.warn "DID NOT PARSE MESSAGE for description : $description"
log.debug parseDescriptionAsMap(description) log.debug parseDescriptionAsMap(description)
} }
return event
} }
// Commands to device // Commands to device

View File

@@ -79,7 +79,6 @@ def parse(String description) {
log.debug "description is $description" log.debug "description is $description"
def finalResult = zigbee.getKnownDescription(description) def finalResult = zigbee.getKnownDescription(description)
def event = [:]
//TODO: Remove this after getKnownDescription can parse it automatically //TODO: Remove this after getKnownDescription can parse it automatically
if (!finalResult && description!="updated") if (!finalResult && description!="updated")
@@ -89,11 +88,10 @@ def parse(String description) {
log.info "final result = $finalResult" log.info "final result = $finalResult"
if (finalResult.type == "update") { if (finalResult.type == "update") {
log.info "$device updates: ${finalResult.value}" log.info "$device updates: ${finalResult.value}"
event = null
} }
else if (finalResult.type == "power") { else if (finalResult.type == "power") {
def powerValue = (finalResult.value as Integer)/10 def powerValue = (finalResult.value as Integer)/10
event = createEvent(name: "power", value: powerValue, descriptionText: '{{ device.displayName }} power is {{ value }} Watts', translatable: true) sendEvent(name: "power", value: powerValue, descriptionText: '{{ device.displayName }} power is {{ value }} Watts', translatable: true )
/* /*
Dividing by 10 as the Divisor is 10000 and unit is kW for the device. AttrId: 0302 and 0300. Simplifying to 10 Dividing by 10 as the Divisor is 10000 and unit is kW for the device. AttrId: 0302 and 0300. Simplifying to 10
power level is an integer. The exact power level with correct units needs to be handled in the device type power level is an integer. The exact power level with correct units needs to be handled in the device type
@@ -102,7 +100,7 @@ def parse(String description) {
} }
else { else {
def descriptionText = finalResult.value == "on" ? '{{ device.displayName }} is On' : '{{ device.displayName }} is Off' def descriptionText = finalResult.value == "on" ? '{{ device.displayName }} is On' : '{{ device.displayName }} is Off'
event = createEvent(name: finalResult.type, value: finalResult.value, descriptionText: descriptionText, translatable: true) sendEvent(name: finalResult.type, value: finalResult.value, descriptionText: descriptionText, translatable: true)
} }
} }
else { else {
@@ -111,11 +109,10 @@ def parse(String description) {
if (cluster && cluster.clusterId == 0x0006 && cluster.command == 0x07){ if (cluster && cluster.clusterId == 0x0006 && cluster.command == 0x07){
if (cluster.data[0] == 0x00) { if (cluster.data[0] == 0x00) {
log.debug "ON/OFF REPORTING CONFIG RESPONSE: " + cluster log.debug "ON/OFF REPORTING CONFIG RESPONSE: " + cluster
event = createEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
} }
else { else {
log.warn "ON/OFF REPORTING CONFIG FAILED- error code:${cluster.data[0]}" log.warn "ON/OFF REPORTING CONFIG FAILED- error code:${cluster.data[0]}"
event = null
} }
} }
else { else {
@@ -123,7 +120,6 @@ def parse(String description) {
log.debug "${cluster}" log.debug "${cluster}"
} }
} }
return event
} }
def off() { def off() {

View File

@@ -86,7 +86,7 @@ metadata {
def parse(String description) { def parse(String description) {
log.debug "parse($description)" log.debug "parse($description)"
def results = [:] def results = null
if (!isSupportedDescription(description) || zigbee.isZoneType19(description)) { if (!isSupportedDescription(description) || zigbee.isZoneType19(description)) {
// Ignore this in favor of orientation-based state // Ignore this in favor of orientation-based state

View File

@@ -102,7 +102,7 @@ def parse(String description) {
} }
log.debug "Parse returned $map" log.debug "Parse returned $map"
def result = map ? createEvent(map) : [:] def result = map ? createEvent(map) : null
if (description?.startsWith('enroll request')) { if (description?.startsWith('enroll request')) {
List cmds = enrollResponse() List cmds = enrollResponse()

View File

@@ -106,7 +106,7 @@ def parse(String description) {
} }
log.debug "Parse returned $map" log.debug "Parse returned $map"
def result = map ? createEvent(map) : [:] def result = map ? createEvent(map) : null
if (description?.startsWith('enroll request')) { if (description?.startsWith('enroll request')) {
List cmds = enrollResponse() List cmds = enrollResponse()

View File

@@ -94,7 +94,7 @@ def parse(String description) {
} }
log.debug "Parse returned $map" log.debug "Parse returned $map"
def result = map ? createEvent(map) : [:] def result = map ? createEvent(map) : null
if (description?.startsWith('enroll request')) { if (description?.startsWith('enroll request')) {
List cmds = enrollResponse() List cmds = enrollResponse()

View File

@@ -44,7 +44,7 @@ metadata {
} }
def parse(String description) { def parse(String description) {
def results = [:] def results
if (isZoneType19(description) || !isSupportedDescription(description)) { if (isZoneType19(description) || !isSupportedDescription(description)) {
results = parseBasicMessage(description) results = parseBasicMessage(description)
} }
@@ -57,25 +57,21 @@ def parse(String description) {
private Map parseBasicMessage(description) { private Map parseBasicMessage(description) {
def name = parseName(description) def name = parseName(description)
if (name != null) { def value = parseValue(description)
def value = parseValue(description) def linkText = getLinkText(device)
def linkText = getLinkText(device) def descriptionText = parseDescriptionText(linkText, value, description)
def descriptionText = parseDescriptionText(linkText, value, description) def handlerName = value
def handlerName = value def isStateChange = isStateChange(device, name, value)
def isStateChange = isStateChange(device, name, value)
def results = [ def results = [
name : name, name: name,
value : value, value: value,
linkText : linkText, linkText: linkText,
descriptionText: descriptionText, descriptionText: descriptionText,
handlerName : handlerName, handlerName: handlerName,
isStateChange : isStateChange, isStateChange: isStateChange,
displayed : displayed(description, isStateChange) displayed: displayed(description, isStateChange)
] ]
} else {
results = [:]
}
log.debug "Parse returned $results.descriptionText" log.debug "Parse returned $results.descriptionText"
return results return results
} }

View File

@@ -127,7 +127,7 @@ def parse(String description) {
map = parseIasMessage(description) map = parseIasMessage(description)
} }
def result = map ? createEvent(map) : [:] def result = map ? createEvent(map) : null
if (description?.startsWith('enroll request')) { if (description?.startsWith('enroll request')) {
List cmds = enrollResponse() List cmds = enrollResponse()

View File

@@ -93,7 +93,7 @@ def parse(String description) {
} }
log.debug "Parse returned $map" log.debug "Parse returned $map"
def result = map ? createEvent(map) : [:] def result = map ? createEvent(map) : null
if (description?.startsWith('enroll request')) { if (description?.startsWith('enroll request')) {
List cmds = enrollResponse() List cmds = enrollResponse()

View File

@@ -84,7 +84,7 @@ def parse(String description) {
} }
log.debug "Parse returned $map" log.debug "Parse returned $map"
return map ? createEvent(map) : [:] return map ? createEvent(map) : null
} }
private Map parseCatchAllMessage(String description) { private Map parseCatchAllMessage(String description) {

View File

@@ -84,20 +84,18 @@ def refresh() {
def configure() { def configure() {
log.debug "in configure()" log.debug "in configure()"
return configureHealthCheck() configureHealthCheck()
} }
def configureHealthCheck() { def configureHealthCheck() {
Integer hcIntervalMinutes = 12 Integer hcIntervalMinutes = 12
refresh()
sendEvent(name: "checkInterval", value: hcIntervalMinutes * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) sendEvent(name: "checkInterval", value: hcIntervalMinutes * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
return refresh()
} }
def updated() { def updated() {
log.debug "in updated()" log.debug "in updated()"
// updated() doesn't have it's return value processed as hub commands, so we have to send them explicitly configureHealthCheck()
def cmds = configureHealthCheck()
cmds.each{ sendHubCommand(new physicalgraph.device.HubAction(it)) }
} }
def ping() { def ping() {

View File

@@ -21,14 +21,10 @@ metadata {
capability "Sensor" capability "Sensor"
fingerprint inClusters: "0x25", deviceJoinName: "Z-Wave Switch" fingerprint inClusters: "0x25", deviceJoinName: "Z-Wave Switch"
fingerprint deviceId: "0x1001", inClusters: "0x5E,0x20,0x25,0x27,0x72,0x86,0x70,0x85", deviceJoinName: "Z-Wave Switch" // to prevent typing as relay
fingerprint deviceId: "0x1003", inClusters: "0x5E,0x25,0x2B,0x2C,0x27,0x75,0x73,0x70,0x86,0x72", deviceJoinName: "Z-Wave Switch"
fingerprint mfr:"001D", prod:"1A02", model:"0334", deviceJoinName: "Leviton Appliance Module" fingerprint mfr:"001D", prod:"1A02", model:"0334", deviceJoinName: "Leviton Appliance Module"
fingerprint mfr:"001D", prod:"3601", model:"0001", deviceJoinName: "Leviton Appliance Module" fingerprint mfr:"0063", prod:"4F50", model:"3031", deviceJoinName: "GE Plug-in Outdoor Switch"
fingerprint mfr:"001D", prod:"1D04", model:"0334", deviceJoinName: "Leviton Outlet" fingerprint mfr:"001D", prod:"1D04", model:"0334", deviceJoinName: "Leviton Outlet"
fingerprint mfr:"001D", prod:"1C02", model:"0334", deviceJoinName: "Leviton Switch" fingerprint mfr:"001D", prod:"1C02", model:"0334", deviceJoinName: "Leviton Switch"
fingerprint mfr:"001D", prod:"3401", model:"0001", deviceJoinName: "Leviton Switch"
fingerprint mfr:"0063", prod:"4F50", model:"3031", deviceJoinName: "GE Plug-in Outdoor Switch"
} }
// simulator metadata // simulator metadata

View File

@@ -1,10 +1,9 @@
/** /**
* Color Coordinator * Color Coordinator
* Version 1.1.0 - 11/9/16 * Version 1.0.0 - 7/4/15
* By Michael Struck * By Michael Struck
* *
* 1.0.0 - Initial release * 1.0.0 - Initial release
* 1.1.0 - Fixed issue where master can be part of slaves. This causes a loop that impacts SmartThings.
* *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
@@ -32,35 +31,27 @@ preferences {
} }
def mainPage() { def mainPage() {
dynamicPage(name: "mainPage", title: "", install: true, uninstall: false) { dynamicPage(name: "mainPage", title: "", install: true, uninstall: true) {
def masterInList = slaves.id.find{it==master.id} section("Master Light") {
if (masterInList) {
section ("**WARNING**"){
paragraph "You have included the Master Light in the Slave Group. This will cause a loop in execution. Please remove this device from the Slave Group.", image: "https://raw.githubusercontent.com/MichaelStruck/SmartThingsPublic/master/img/caution.png"
}
}
section("Master Light") {
input "master", "capability.colorControl", title: "Colored Light" input "master", "capability.colorControl", title: "Colored Light"
} }
section("Lights that follow the master settings") { section("Lights that follow the master settings") {
input "slaves", "capability.colorControl", title: "Colored Lights", multiple: true, required: false, submitOnChange: true input "slaves", "capability.colorControl", title: "Colored Lights", multiple: true, required: false
} }
section([mobileOnly:true], "Options") { section([mobileOnly:true], "Options") {
input "randomYes", "bool",title: "When Master Turned On, Randomize Color", defaultValue: false label(title: "Assign a name", required: false)
href "pageAbout", title: "About ${textAppName()}", description: "Tap to get application version, license and instructions" href "pageAbout", title: "About ${textAppName()}", description: "Tap to get application version, license and instructions"
} }
} }
} }
page(name: "pageAbout", title: "About ${textAppName()}", uninstall: true) { page(name: "pageAbout", title: "About ${textAppName()}") {
section { section {
paragraph "${textVersion()}\n${textCopyright()}\n\n${textLicense()}\n" paragraph "${textVersion()}\n${textCopyright()}\n\n${textLicense()}\n"
} }
section("Instructions") { section("Instructions") {
paragraph textHelp() paragraph textHelp()
} }
section("Tap button below to remove application"){
}
} }
def installed() { def installed() {
@@ -81,55 +72,27 @@ def init() {
} }
//----------------------------------- //-----------------------------------
def onOffHandler(evt){ def onOffHandler(evt){
if (!slaves.id.find{it==master.id}){ if (master.currentValue("switch") == "on"){
if (master.currentValue("switch") == "on"){ slaves?.on()
if (randomYes) getRandomColorMaster() }
else slaves?.on() else {
} slaves?.off()
else { }
slaves?.off()
}
}
} }
def colorHandler(evt) { def colorHandler(evt) {
if (!slaves.id.find{it==master.id} && master.currentValue("switch") == "on"){ def dimLevel = master.currentValue("level")
log.debug "Changing Slave units H,S,L" def hueLevel = master.currentValue("hue")
def dimLevel = master.currentValue("level") def saturationLevel = master.currentValue("saturation")
def hueLevel = master.currentValue("hue")
def saturationLevel = master.currentValue("saturation")
def newValue = [hue: hueLevel, saturation: saturationLevel, level: dimLevel as Integer]
slaves?.setColor(newValue)
try {
log.debug "Changing Slave color temp"
def tempLevel = master.currentValue("colorTemperature")
slaves?.setColorTemperature(tempLevel)
}
catch (e){
log.debug "Color temp for master --"
}
}
}
def getRandomColorMaster(){
def hueLevel = Math.floor(Math.random() *1000)
def saturationLevel = Math.floor(Math.random() * 100)
def dimLevel = master.currentValue("level")
def newValue = [hue: hueLevel, saturation: saturationLevel, level: dimLevel as Integer] def newValue = [hue: hueLevel, saturation: saturationLevel, level: dimLevel as Integer]
log.debug hueLevel slaves?.setColor(newValue)
log.debug saturationLevel
master.setColor(newValue)
slaves?.setColor(newValue)
} }
def tempHandler(evt){ def tempHandler(evt){
if (!slaves.id.find{it==master.id} && master.currentValue("switch") == "on"){ if (evt.value != "--") {
if (evt.value != "--") { def tempLevel = master.currentValue("colorTemperature")
log.debug "Changing Slave color temp based on Master change" slaves?.setColorTemperature(tempLevel)
def tempLevel = master.currentValue("colorTemperature") }
slaves?.setColorTemperature(tempLevel)
}
}
} }
//Version/Copyright/Information/Help //Version/Copyright/Information/Help
@@ -139,11 +102,11 @@ private def textAppName() {
} }
private def textVersion() { private def textVersion() {
def text = "Version 1.1.0 (11/09/2016)" def text = "Version 1.0.0 (07/04/2015)"
} }
private def textCopyright() { private def textCopyright() {
def text = "Copyright © 2016 Michael Struck" def text = "Copyright © 2015 Michael Struck"
} }
private def textLicense() { private def textLicense() {
@@ -165,5 +128,5 @@ private def textHelp() {
def text = def text =
"This application will allow you to control the settings of multiple colored lights with one control. " + "This application will allow you to control the settings of multiple colored lights with one control. " +
"Simply choose a master control light, and then choose the lights that will follow the settings of the master, "+ "Simply choose a master control light, and then choose the lights that will follow the settings of the master, "+
"including on/off conditions, hue, saturation, level and color temperature. Also includes a random color feature." "including on/off conditions, hue, saturation, level and color temperature."
} }

View File

@@ -0,0 +1,50 @@
/**
* name
*
* Copyright 2016 João Borges
*
* 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: "name",
namespace: "namespace",
author: "João Borges",
description: "description",
category: "SmartThings Labs",
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
iconX3Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png")
preferences {
section("Title") {
// TODO: put inputs here
}
}
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.
}
// TODO: implement event handlers

View File

@@ -381,28 +381,38 @@ def updateDevices() {
selectors.add("${device.id}") selectors.add("${device.id}")
if (!childDevice) { if (!childDevice) {
// log.info("Adding device ${device.id}: ${device.product}") // log.info("Adding device ${device.id}: ${device.product}")
def data = [
label: device.label,
level: Math.round((device.brightness ?: 1) * 100),
switch: device.power,
colorTemperature: device.color.kelvin
]
if (device.product.capabilities.has_color) { if (device.product.capabilities.has_color) {
childDevice = addChildDevice(app.namespace, "LIFX Color Bulb", device.id, null, ["label": device.label, "completedSetup": true]) data["color"] = colorUtil.hslToHex((device.color.hue / 3.6) as int, (device.color.saturation * 100) as int)
data["hue"] = device.color.hue / 3.6
data["saturation"] = device.color.saturation * 100
childDevice = addChildDevice(app.namespace, "LIFX Color Bulb", device.id, null, data)
} else { } else {
childDevice = addChildDevice(app.namespace, "LIFX White Bulb", device.id, null, ["label": device.label, "completedSetup": true]) 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 (device.product.capabilities.has_color) {
childDevice.sendEvent(name: "color", value: colorUtil.hslToHex((device.color.hue / 3.6) as int, (device.color.saturation * 100) as int))
childDevice.sendEvent(name: "hue", value: device.color.hue / 3.6)
childDevice.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) { if (state.devices[device.id] == null) {
// State missing, add it and set it to opposite status as current status to provoke event below // State missing, add it and set it to opposite status as current status to provoke event below
state.devices[device.id] = [online: !device.connected] state.devices[device.id] = [online : !device.connected]
} }
if (!state.devices[device.id]?.online && device.connected) { if (!state.devices[device.id]?.online && device.connected) {