Philips Hue Lux Device?

Hi Chris,

This is my currently live one. It still doesn’t handle refreshes that well - let me know if you manage to tweak it any further!

/**

  • Zigbee Hue Lux Bulb
  • Copyright 2015 Jason Steele
  • 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.
  • Thanks all the contributors to the GE Link bulb device handler at
  • http://community.smartthings.com/t/updated-ge-link-bulbs-finally-getting-on-status-after-manually-turning-on
  • and special thanks to to @Sticks18 for all his help with this
    */

metadata {
definition (name: “Zigbee Hue Lux Bulb”, namespace: “JasonBSteele”, author: “Jason Steele”) {
capability “Switch Level”
capability “Actuator”
capability “Switch”
capability “Configuration”
capability “Polling”
capability “Refresh”
capability “Sensor”

  fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,1000", outClusters: "0019"

}

// simulator metadata
simulator {
// status messages
status “on”: “on/off: 1”
status “off”: “on/off: 0”

  // reply messages
  reply "zcl on-off on": "on/off: 1"
  reply "zcl on-off off": "on/off: 0"

}

// UI tile definitions
tiles {
standardTile(“switch”, “device.switch”, width: 2, height: 2, canChangeIcon: true) {
state “off”, label: ‘${name}’, action: “switch.on”, icon: “st.switches.light.off”, backgroundColor: “#ffffff
state “on”, label: ‘${name}’, action: “switch.off”, icon: “st.switches.light.on”, backgroundColor: “#79b821
}
standardTile(“refresh”, “device.switch”, inactiveLabel: false, decoration: “flat”) {
state “default”, label:“”, action:“refresh.refresh”, icon:“st.secondary.refresh”
}
controlTile(“levelSliderControl”, “device.level”, “slider”, height: 1, width: 3, inactiveLabel: false) {
state “level”, action:“switch level.setLevel”
}
valueTile(“level”, “device.level”, inactiveLabel: false, decoration: “flat”) {
state “level”, label: ‘Level ${currentValue}%’
}

  main(["switch"])
  details(["switch", "levelSliderControl", "refresh"])

}
}

// Parse incoming device messages to generate events
def parse(String description) {
log.trace “parse(${description})”

def result = null
//Refresh causes catchall: 0104 0006 0B 01 0100 00 5C14 00 00 0000 01 01 0000001001 to be sent if On 
//(and 1000 if Off) and "read attr" for level 
//0000 and 0100 are returned by the On/Off being tapped in the app so we are already raising an event for this
//(however these only get returned when successful so it could be used to only raise the event when bulb is actually powered)
if (description?.startsWith("catchall:")) {
  def x = description[-4..-1]
    switch (x) 
    {
        case "1000":
        	result = createEvent(name: "switch", value: "off")
            break
        case "1001":
        	result = createEvent(name: "switch", value: "on")
            break
        //case "0000":
        //	result = createEvent(name: "switch", value: "off")
        //  break
        //case "0100":
        //	result = createEvent(name: "switch", value: "on")
        //  break
    }
}
else if (description?.startsWith("read attr")) {
  def i = Math.round(convertHexToInt(description[-2..-1]) / 256 * 100 )
    //log.debug "Parse level {$i}" 
  result = createEvent( name: "level", value: i )
    sendEvent( name: "switch.setLevel", value: i) //added to help subscribers

}

else if (description?.startsWith(“on/off:”)) {
//Does the same as sendEvent(name: “switch”, value: “on”) but why?
//Could be more for the benefit of the simulation
//According to Sticks18 this often gets sent when a GE bulb is manually turned on
//This never seems `to happen for the Hue Lux
def value = description?.endsWith(" 1") ? “on” : “off”
result = createEvent(name: “switch”, value: value)
}

//log.debug "parse returned ${result?.descriptionText}"
return result

}

def on() {
// Raise an event to let subscribers know and then tell the device
log.trace “on()”
sendEvent(name: “switch”, value: “on”)
“st cmd 0x${device.deviceNetworkId} ${endpointId} 6 1 {}”
}

def off() {
// Raise an event to let subscribers know and then tell the device
log.trace “off()”
sendEvent(name: “switch”, value: “off”)
“st cmd 0x${device.deviceNetworkId} ${endpointId} 6 0 {}”
}

def refresh() {
//Ask the device to send values for the switch and level
log.trace “refresh()”
[
“st rattr 0x${device.deviceNetworkId} ${endpointId} 6 0”,
“delay 500”,
“st rattr 0x${device.deviceNetworkId} ${endpointId} 8 0”
]
}

def poll(){
log.trace “poll()”
refresh()
}

def setLevel(value) {
log.trace “setLevel($value)”
def cmds =

// If level set to 0 then raise a switch=off event and tell the device
if (value == 0) {
sendEvent(name: “switch”, value: “off”)
cmds << “st cmd 0x${device.deviceNetworkId} ${endpointId} 6 0 {}”
}

// If the level is greater than 0 and the switch is off then raise a switch=on event 

else if (device.latestValue(“switch”) == “off”) {
sendEvent(name: “switch”, value: “on”)
}

// Raise a level=value event and tell the device
sendEvent(name: “level”, value: value)
sendEvent( name: “switch.setLevel”, value: value) //added to help subscribers
def level = new BigInteger(Math.round(value * 255 / 100).toString()).toString(16)
cmds << “st cmd 0x${device.deviceNetworkId} ${endpointId} 8 4 {${level} 0000}”

//log.debug cmds
cmds
}

/*
//Doesn’t seem to be called and doesn’t appear to be necessary
def configure() {
log.trace “configure()”

log.debug “Confuguring Reporting and Bindings.”
def configCmds = [

    //Switch Reporting
    "zcl global send-me-a-report 6 0 0x10 0 3600 {01}", "delay 500",
    "send 0x${device.deviceNetworkId} 1 1", "delay 1000",
    //Level Control Reporting
    "zcl global send-me-a-report 8 0 0x20 5 3600 {0010}", "delay 200",
    "send 0x${device.deviceNetworkId} 1 1", "delay 1500",
    "zdo bind 0x${device.deviceNetworkId} 1 1 6 {${device.zigbeeId}} {}", "delay 1000",
  "zdo bind 0x${device.deviceNetworkId} 1 1 8 {${device.zigbeeId}} {}", "delay 500",

]
return configCmds + refresh() // send refresh cmds as part of config
}
*/

private getEndpointId() {
new BigInteger(device.endpointId, 16).toString()
}

private hex(value, width=2) {
def s = new BigInteger(Math.round(value).toString()).toString(16)
while (s.size() < width) {
s = “0” + s
}
s
}

private Integer convertHexToInt(hex) {
Integer.parseInt(hex,16)
}

2 Likes