DVCSMP-1597 Philips HUE: Bloom and Strip lights need temperature control removed

-Added new device type for Hue lights that have color control but no temperature control (Bloom/Strip)
-Add missing event to setLevel
This commit is contained in:
Lars Finander
2016-03-28 09:32:19 -07:00
parent 6ac174c2f3
commit 0c5840087b
4 changed files with 278 additions and 15 deletions

View File

@@ -0,0 +1,227 @@
/**
* Hue Bloom
*
* Philips Hue Type "Color Light"
*
* Author: SmartThings
*/
// for the UI
metadata {
// Automatically generated. Make future change here.
definition (name: "Hue Bloom", namespace: "smartthings", author: "SmartThings") {
capability "Switch Level"
capability "Actuator"
capability "Color Control"
capability "Switch"
capability "Refresh"
capability "Sensor"
command "setAdjustedColor"
command "reset"
command "refresh"
}
simulator {
// TODO: define status and reply messages here
}
tiles (scale: 2){
multiAttributeTile(name:"rich-control", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#C6C7CC", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#C6C7CC", nextState:"turningOn"
}
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
attributeState "level", action:"switch level.setLevel", range:"(0..100)"
}
tileAttribute ("device.level", key: "SECONDARY_CONTROL") {
attributeState "level", label: 'Level ${currentValue}%'
}
tileAttribute ("device.color", key: "COLOR_CONTROL") {
attributeState "color", action:"setAdjustedColor"
}
}
standardTile("reset", "device.reset", height: 2, width: 2, inactiveLabel: false, decoration: "flat") {
state "default", label:"Reset Color", action:"reset", icon:"st.lights.philips.hue-single"
}
standardTile("refresh", "device.refresh", height: 2, width: 2, inactiveLabel: false, decoration: "flat") {
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
}
main(["rich-control"])
details(["rich-control", "colorTempSliderControl", "colorTemp", "reset", "refresh"])
}
}
// parse events into attributes
def parse(description) {
log.debug "parse() - $description"
def results = []
def map = description
if (description instanceof String) {
log.debug "Hue Bulb stringToMap - ${map}"
map = stringToMap(description)
}
if (map?.name && map?.value) {
results << createEvent(name: "${map?.name}", value: "${map?.value}")
}
results
}
// handle commands
void on() {
log.trace parent.on(this)
sendEvent(name: "switch", value: "on")
}
void off() {
log.trace parent.off(this)
sendEvent(name: "switch", value: "off")
}
void nextLevel() {
def level = device.latestValue("level") as Integer ?: 0
if (level <= 100) {
level = Math.min(25 * (Math.round(level / 25) + 1), 100) as Integer
}
else {
level = 25
}
setLevel(level)
}
void setLevel(percent) {
log.debug "Executing 'setLevel'"
if (verifyPercent(percent)) {
parent.setLevel(this, percent)
sendEvent(name: "level", value: percent, descriptionText: "Level has changed to ${percent}%")
sendEvent(name: "switch", value: "on")
}
}
void setSaturation(percent) {
log.debug "Executing 'setSaturation'"
if (verifyPercent(percent)) {
parent.setSaturation(this, percent)
sendEvent(name: "saturation", value: percent, displayed: false)
}
}
void setHue(percent) {
log.debug "Executing 'setHue'"
if (verifyPercent(percent)) {
parent.setHue(this, percent)
sendEvent(name: "hue", value: percent, displayed: false)
}
}
void setColor(value) {
log.debug "setColor: ${value}, $this"
def events = []
def validValues = [:]
if (verifyPercent(value.hue)) {
events << createEvent(name: "hue", value: value.hue, displayed: false)
validValues.hue = value.hue
}
if (verifyPercent(value.saturation)) {
events << createEvent(name: "saturation", value: value.saturation, displayed: false)
validValues.saturation = value.saturation
}
if (value.hex != null) {
if (value.hex ==~ /^\#([A-Fa-f0-9]){6}$/) {
events << createEvent(name: "color", value: value.hex)
validValues.hex = value.hex
} else {
log.warn "$value.hex is not a valid color"
}
}
if (verifyPercent(value.level)) {
events << createEvent(name: "level", value: value.level, descriptionText: "Level has changed to ${value.level}%")
validValues.level = value.level
}
if (value.switch == "off" || (value.level != null && value.level <= 0)) {
events << createEvent(name: "switch", value: "off")
validValues.switch = "off"
} else {
events << createEvent(name: "switch", value: "on")
validValues.switch = "on"
}
if (!events.isEmpty()) {
parent.setColor(this, validValues)
}
events.each {
sendEvent(it)
}
}
void reset() {
log.debug "Executing 'reset'"
def value = [level:100, saturation:56, hue:23]
setAdjustedColor(value)
parent.poll()
}
void setAdjustedColor(value) {
if (value) {
log.trace "setAdjustedColor: ${value}"
def adjusted = value + [:]
adjusted.hue = adjustOutgoingHue(value.hue)
// Needed because color picker always sends 100
adjusted.level = null
setColor(adjusted)
} else {
log.warn "Invalid color input"
}
}
void setColorTemperature(value) {
if (value) {
log.trace "setColorTemperature: ${value}k"
parent.setColorTemperature(this, value)
sendEvent(name: "colorTemperature", value: value)
sendEvent(name: "switch", value: "on")
} else {
log.warn "Invalid color temperature"
}
}
void refresh() {
log.debug "Executing 'refresh'"
parent.manualRefresh()
}
def adjustOutgoingHue(percent) {
def adjusted = percent
if (percent > 31) {
if (percent < 63.0) {
adjusted = percent + (7 * (percent -30 ) / 32)
}
else if (percent < 73.0) {
adjusted = 69 + (5 * (percent - 62) / 10)
}
else {
adjusted = percent + (2 * (100 - percent) / 28)
}
}
log.info "percent: $percent, adjusted: $adjusted"
adjusted
}
def verifyPercent(percent) {
if (percent == null)
return false
else if (percent >= 0 && percent <= 100) {
return true
} else {
log.warn "$percent is not 0-100"
return false
}
}

View File

@@ -1,6 +1,8 @@
/**
* Hue Bulb
*
* Philips Hue Type "Extended Color Light"
*
* Author: SmartThings
*/
@@ -69,11 +71,13 @@ metadata {
def parse(description) {
log.debug "parse() - $description"
def results = []
def map = description
if (description instanceof String) {
log.debug "Hue Bulb stringToMap - ${map}"
map = stringToMap(description)
}
if (map?.name && map?.value) {
results << createEvent(name: "${map?.name}", value: "${map?.value}")
}
@@ -229,4 +233,4 @@ def verifyPercent(percent) {
log.warn "$percent is not 0-100"
return false
}
}
}

View File

@@ -1,6 +1,8 @@
/**
* Hue Lux Bulb
*
* Philips Hue Type "Dimmable Light"
*
* Author: SmartThings
*/
// for the UI
@@ -68,12 +70,12 @@ def parse(description) {
// handle commands
void on() {
parent.on(this)
log.trace parent.on(this)
sendEvent(name: "switch", value: "on")
}
void off() {
parent.off(this)
log.trace parent.off(this)
sendEvent(name: "switch", value: "off")
}
@@ -82,6 +84,7 @@ void setLevel(percent) {
if (percent != null && percent >= 0 && percent <= 100) {
parent.setLevel(this, percent)
sendEvent(name: "level", value: percent)
sendEvent(name: "switch", value: "on")
} else {
log.warn "$percent is not 0-100"
}

View File

@@ -289,7 +289,7 @@ def bulbListHandler(hub, data = "") {
def object = new groovy.json.JsonSlurper().parseText(data)
object.each { k,v ->
if (v instanceof Map)
bulbs[k] = [id: k, name: v.name, type: v.type, hub:hub]
bulbs[k] = [id: k, name: v.name, type: v.type, modelid: v.modelid, hub:hub]
}
}
def bridge = null
@@ -300,6 +300,40 @@ def bulbListHandler(hub, data = "") {
return msg
}
private upgradeDeviceType(device, newHueType) {
def deviceType = getDeviceType(newHueType)
// Automatically change users Hue bulbs to correct device types
if (deviceType && !(device?.typeName?.equalsIgnoreCase(deviceType))) {
log.debug "Update device type: \"$device.label\" ${device?.typeName}->$deviceType"
device.setDeviceType(deviceType)
}
}
private getDeviceType(hueType) {
// Determine ST device type based on Hue classification of light
if (hueType?.equalsIgnoreCase("Dimmable light"))
return "Hue Lux Bulb"
else if (hueType?.equalsIgnoreCase("Extended Color Light"))
return "Hue Bulb"
else if (hueType?.equalsIgnoreCase("Color Light"))
return "Hue Bloom"
else
return null
}
private addChildBulb(dni, hueType, name, hub, update=false, device = null) {
def deviceType = getDeviceType(hueType)
if (deviceType) {
return addChildDevice("smartthings", deviceType, dni, hub, ["label": name])
}
else {
log.warn "Device type $hueType not supported"
return null
}
}
def addBulbs() {
def bulbs = getHueBulbs()
selectedBulbs?.each { dni ->
@@ -309,11 +343,7 @@ def addBulbs() {
if (bulbs instanceof java.util.Map) {
newHueBulb = bulbs.find { (app.id + "/" + it.value.id) == dni }
if (newHueBulb != null) {
if (newHueBulb?.value?.type?.equalsIgnoreCase("Dimmable light") ) {
d = addChildDevice("smartthings", "Hue Lux Bulb", dni, newHueBulb?.value.hub, ["label":newHueBulb?.value.name])
} else {
d = addChildDevice("smartthings", "Hue Bulb", dni, newHueBulb?.value.hub, ["label":newHueBulb?.value.name])
}
d = addChildBulb(dni, newHueBulb?.value?.type, newHueBulb?.value?.name, newHueBulb?.value?.hub)
log.debug "created ${d.displayName} with id $dni"
d.refresh()
} else {
@@ -322,16 +352,15 @@ def addBulbs() {
} else {
//backwards compatable
newHueBulb = bulbs.find { (app.id + "/" + it.id) == dni }
d = addChildDevice("smartthings", "Hue Bulb", dni, newHueBulb?.hub, ["label":newHueBulb?.name])
d = addChildBulb(dni, "Extended Color Light", newHueBulb?.value?.name, newHueBulb?.value?.hub)
d.refresh()
}
} else {
log.debug "found ${d.displayName} with id $dni already exists, type: '$d.typeName'"
if (bulbs instanceof java.util.Map) {
// Update device type if incorrect
def newHueBulb = bulbs.find { (app.id + "/" + it.value.id) == dni }
if (newHueBulb?.value?.type?.equalsIgnoreCase("Dimmable light") && d.typeName == "Hue Bulb") {
d.setDeviceType("Hue Lux Bulb")
}
upgradeDeviceType(d, newHueBulb?.value?.type)
}
}
}
@@ -473,7 +502,7 @@ def locationHandler(evt) {
def bulbs = getHueBulbs()
log.debug "Adding bulbs to state!"
body.each { k,v ->
bulbs[k] = [id: k, name: v.name, type: v.type, hub:parsedEvent.hub]
bulbs[k] = [id: k, name: v.name, type: v.type, modelid: v.modelid, hub:parsedEvent.hub]
}
}
}
@@ -836,7 +865,7 @@ def convertBulbListToMap() {
if (state.bulbs instanceof java.util.List) {
def map = [:]
state.bulbs.unique {it.id}.each { bulb ->
map << ["${bulb.id}":["id":bulb.id, "name":bulb.name, "hub":bulb.hub]]
map << ["${bulb.id}":["id":bulb.id, "name":bulb.name, "type": bulb.type, "modelid": bulb.modelid, "hub":bulb.hub]]
}
state.bulbs = map
}