Getting Philips Hue Values

I have tried several ways of getting Philips Hue level, hue and saturation values - and none appear to work.

All of the below do not work (in the simulator at least):

def currentLevel = targetDevice.currentState("level").integerValue
// java.lang.NullPointerException: Cannot get property 'integerValue' on null object

def currentLevel = targetDevice.latestState("level").integerValue
// java.lang.NullPointerException: Cannot get property 'integerValue' on null object

def currentLevel = targetDevice.currentState("level").value
// java.lang.NullPointerException: Cannot get property 'value' on null object

def currentLevel = targetDevice.currentValue("level")
// null

def currentLevel = targetDevice.latestValue("level")
// null

I have also tried polling / refreshing before checking the values - they remain as above.

targetDevice.poll()
targetDevice.refresh() 

Here’s the device type code for the hue bulbs. Helpful?

/**
 *  Hue Bulb
 *
 *  Author: SmartThings
 */
// for the UI
metadata {
	// Automatically generated. Make future change here.
	definition (name: "Hue Bulb", namespace: "smartthings", author: "SmartThings") {
		capability "Switch Level"
		capability "Actuator"
		capability "Color Control"
		capability "Switch"
		capability "Polling"
		capability "Refresh"
		capability "Sensor"

		command "setAdjustedColor"
	}

	simulator {
		// TODO: define status and reply messages here
	}

	standardTile("switch", "device.switch", width: 1, height: 1, canChangeIcon: true) {
		state "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
		state "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
		state "turningOn", label:'${name}', icon:"st.switches.switch.on", backgroundColor:"#79b821"
		state "turningOff", label:'${name}', icon:"st.switches.switch.off", backgroundColor:"#ffffff"
	}
	standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
		state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
	}
	standardTile("nextLevel", "device.level", inactiveLabel: false, decoration: "flat") {
		state "default", label:'Level', action:"nextLevel", icon:"st.illuminance.illuminance.light"
	}
	controlTile("rgbSelector", "device.color", "color", height: 3, width: 3, inactiveLabel: false) {
		state "color", action:"setAdjustedColor"
	}
	controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 2, inactiveLabel: false) {
		state "level", action:"switch level.setLevel"
	}
	valueTile("level", "device.level", inactiveLabel: false, decoration: "flat") {
		state "level", label: 'Level ${currentValue}%'
	}
	controlTile("saturationSliderControl", "device.saturation", "slider", height: 1, width: 2, inactiveLabel: false) {
		state "saturation", action:"color control.setSaturation"
	}
	valueTile("saturation", "device.saturation", inactiveLabel: false, decoration: "flat") {
		state "saturation", label: 'Sat ${currentValue}    '
	}
	controlTile("hueSliderControl", "device.hue", "slider", height: 1, width: 2, inactiveLabel: false) {
		state "hue", action:"color control.setHue"
	}
	valueTile("hue", "device.hue", inactiveLabel: false, decoration: "flat") {
		state "hue", label: 'Hue ${currentValue}   '
	}

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

}

// 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
def on() {
	parent.on(this)
	sendEvent(name: "switch", value: "on")
}

def off() {
	parent.off(this)
	sendEvent(name: "switch", value: "off")
}

def poll() {
	parent.poll(this)
}

def 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)
}

def setLevel(percent) {
	log.debug "Executing 'setLevel'"
	parent.setLevel(this, percent)
	sendEvent(name: "level", value: percent)
}

def setSaturation(percent) {
	log.debug "Executing 'setSaturation'"
	parent.setSaturation(this, percent)
	sendEvent(name: "saturation", value: percent)
}

def setHue(percent) {
	log.debug "Executing 'setHue'"
	parent.setHue(this, percent)
	sendEvent(name: "hue", value: percent)
}

def setColor(value) {
	log.debug "setColor: ${value}"
	parent.setColor(this, value)
	sendEvent(name: "hue", value: value.hue)
	sendEvent(name: "saturation", value: value.saturation)
	if (value.level) {
		sendEvent(name: "level", value: value.level)
	}
	if (value.switch) {
		sendEvent(name: "switch", value: value.switch)
	}
}

def setAdjustedColor(value) {
	log.debug "setAdjustedColor: ${value}"
	def adjusted = value + [:]
	adjusted.hue = adjustOutgoingHue(value.hue)
	adjusted.level = null // needed because color picker always sends 100
	setColor(adjusted)
}

def save() {
	log.debug "Executing 'save'"
}

def refresh() {
	log.debug "Executing 'refresh'"
	parent.poll(this)
}

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
}

Cheers for the code - but I still can not work out how to retrieve the current values.

With the code above - my concern is that the driver doesn’t make those values available.

Is that correct?

Your last two attempts like the two below is the correct syntax and those should work.

targetDevice.latestValue("level")
targetDevice.currentValue("level")

Have you tried pulling any other attributes from the device like?

targetDevice.currentValue("switch")

If you’re not seeing values for any attributes could you share more of your code?

1 Like

The only value I ever get back is “switch”, I don’t see “level”, “hue” or “saturation” (they are always null).

I’m happy to share more of the code - would you prefer here @rappleg or via support?

Please share code here, if you can as support isn’t as equipped to deal with code-specific topics. Thanks!

It seems that for some reason this is now working, I had tested extensively before and haven’t really made any changes.

The code below captures the state of all switches defined under settings.switches

Call it as below to store the state of all switches in a application level variable.

state.originalStates = captureStates()

And the functions:

def captureStates() {
	def states = [:]
	for (theDevice in settings.switches) {
		def deviceState = captureState(theDevice)
		def deviceID = theDevice.id
		states[deviceID] = deviceState
	}
	return states
}

def captureState(theDevice) {
	def deviceAttributes = theDevice.supportedAttributes
	def deviceAttrValue = [:]
	for ( attr in theDevice.supportedAttributes ) {
		def attrName = "${attr}"
		def attrValue = theDevice.currentValue(attrName)
		deviceAttrValue[attrName] = attrValue
	}
	return deviceAttrValue
}

I would love any feedback about how I could made this more efficient.

Can setColor() take a CT instead of HSL? I know the Philips API supports this but I never found if ST does as well.

Thanks!

CT?.. Color, Tint? Or am I guessing wrong?

This would just require an extension (i.e. A new Command signature) to Capability Color (which is technically a very tough thing to do because every Device Type that claims a Capability must implement all of its Attributes and Commands, so all existing Device Types would need to have conversion methods…).

The workable alternative is to add a new Capability with just this Command signature (and Attributes to read the current set values), and Device Types can decide whether or not to claim and implement it.

Please make the New Capability request in the Category on the Forum!

I believe u can send a hex color and level instead of hue and saturation.
setcolor([hex: #00FF00, level: 50])

Is this supported by all Capability Color Device Types or only Hue… Or is Hue the only such Device?

Documentation update needed?

ie… All Command method “signatures” should be listed in the Capability Taxonomy…, @Jim

I don’t have any hues. He can test to see if it works.

As for the signatures, I suggest that we add the items below. What do you think Pup?

Hex,
HSL,
HST,
ColorName,
RGB,
RGBW,
Temperature,

My guess CT is color and temp?

Good list, but I prefer colorTemperature to avoid ambiguous Attribute or parameter names even if they are in context.

But adding Attributes, Commands, or Command Signatures to an existing Capability is theoretically risky.

(and I discuss choice of Units for Color Temperature)…

I also consider Hex and RGB to be redundant, if they have the same resolution (0 to 255), since the units are equivalent, just a different number representation. #FFFFFFF = 255,255,255.

I am exploring the idea that each capability have its own dedicated documentation page/section, with all attributes and possible values, commands and their signatures.

And code examples, of course.

I think what we currently have is… lacking.

3 Likes

@Kristopher,

Did you try Hex and Level?

Certified zigbee Light link device (ZLL). Standard clusters.

CT in lighting installations means “color temperature.” Cool white to warm white.

The hue API provides three options for setting color:

hue and saturation
xy in the CIE color space
ct the Mired Color temperature

If you would like to use RGB color in your app, you will need to translate to one of these color settings options. Our SDKs provide utility methods to do this or alternatively you can build your own. For more information on this refer to ‘Color gets more complicated’ in ‘Core Concepts’.

1 Like

Thanks for exploring that idea, @Jim!

Some Capabilities will have quite complex definitions, with lots of Attributes, etc.

I’d appreciate any feedback or personal discusson you have time for on my Draft Guidelines… I raise a few important questions there that suggest feature requests for the Platform, but without new features, we may need some redundant and overlapping Capabilities and this means extra documentation to explain why each overlap occurs, and the recommended Capability choices for example Device Types and their SmartApps.