Color is returned as a String when using latestValue? How to pull back out as map?

tl;dr: How do I pull saved color data from a device and maintain it as a map and not a big string?

Long version: From what I can tell, based on testing here, when you tell Alexa to set something to a color it is passed to a device handler through the “setColor” routine in the map but only Hue and Saturation are passed with no other values. So based on that I want to recreate all the color data to properly store it in my device. I do it through a bunch of pretty standard functions and assign it like this:

// came from the ST cloud which only contains hue and saturation.  So build our color data and pass it.
        def myRGB = hslToRGB(color.hue, color.saturation, 0.5)
        def myHEX = rgbToHex(myRGB)
        def colorData = [:]
        colorData = [red: myRGB.red,
                     hex: myHEX,
                     saturation: color.saturation,
                     blue: myRGB.blue,
                     hue: color.hue,
                     green: myRGB.green,
                     alpha: 1]
        sendEvent(name: "color", value: colorData)
        adjustColor(colorData)

So with some debug lines added in I can see the progression when I say “Alexa set the cabinet lights to red”

raw color map passed in: [hue:0, saturation:100]
myRGB: [red:255, green:0, blue:0]
myHEX: #ff0000
LightLevel: 86
FullColorMap: [red:255, hex:#ff0000, saturation:100, blue:0, hue:0, green:0, alpha:1]
AdjustedColorSentToLight: #db0000

Everything works exactly as it should, I get the hue and saturation values for red, convert those to red, green, blue, and hex, build my map, save it to the device, then pass it to my adjustedColor routine which modifies the HEX based on dimmer setting and sends it to the physical light.

The problem is when I try to pull the color map back out. If I adjust the dimmer I use the last known color by pulling it with this:

def lastColor = device.latestValue(“color”)
adjustColor(lastColor)

Then in the adjustColor routine it takes the color map and does a color.red to pull red etc. Problem is when I pull the data using latestValue or currentValue it errors out with a “groovy.lang.MissingPropertyException: No such property: red for class: java.lang.String”.

For example clicking the color chooser sends the color map like in the debug output above and color.red works perfectly fine. lastestValue gives this:

{red=255, hex=#ff0000, saturation=100, blue=0, hue=0, green=0, alpha=1}

So as you can see passed directly from the color picker or if I build the color map using data from Hue/Sat then it works great and each item in the map has a colon after it then the value. If I pull from lastValue it seems to bring it in as a big string with quotes and equal signs so the map is broken.

How do I pull the saved color data in a device back out and maintain it being a map so I can do things like lastColorValue.red and get the red value?

The use of Attribute color in “#RRGGBB” is deprecated and should not be used in new code!

The new definition is a STRING representation of the map [hue, saturation] per:

http://docs.smartthings.com/en/latest/capabilities-reference.html#color-control
image

1 Like

If this is true then why does their own color picker control spit out the full map with all the values? When a user selects a color with that control should I re build the map as just hue and saturation then save that to the device instead of the full block of information that it gives?

Guess what I’m getting stuck on is how do I pull the information back out of the string? It is easy with a map, do I have to use substring statements? I see the set commands but no get commands.

Side note: The color picker includes the full RGB values which I used to figure out lightness (which is what I set my dimmer to). For a Alexa command just “Red” and its Hue/Sat is good enough because I can then adjust it using the dimmer value after the fact.

I’ve given up on trying to get the color map working. setHue and setSaturation don’t like the values I’m passing in even though I have tried converting them to every number type possible. For example Hue = 32 and Sat = 100 won’t take giving a conversion error about big decimal. So I tried to round to a integer, float, etc with no luck. I’m simply going to take the hue and saturation, convert to RGB, then convert to Hex and store Hex unless someone can tell me a better way.

It would be nice if the documentation for this had examples of storing and retrieving these values and not just the set syntax which doesn’t seem to work properly.

Also in case anyone cares. setColor is called by both the standard ST color picker control and also from the ST cloud when a color is passed to the DTH:

def setColor(Map color) {
log.debug “raw color map passed in: ${color}”
if (color.hex){
// came from the color picker. Since the color selector takes into account lightness we have to reconvert
// the color values and adjust the level slider to better represent where it should be at based on the color picked
def colorHSL = rgbToHSL(color)
sendEvent(name: “level”, value: (colorHSL.l * 100))
adjustColor(color.hex)
} else if (color.hue && color.saturation) {
// came from the ST cloud which only contains hue and saturation. So convert to hex and pass it.
def colorRGB = hslToRGB(color.hue, color.saturation, 0.5)
def colorHEX = rgbToHex(colorRGB)
adjustColor(colorHEX)
}
}

Then in the adjustColor routine it saves the hex to the device (sendEvent), applies the dimmer control value to the hex, and sends it to the physical device. Works as expected.

It’s not unusual for SmartThings to not follow their own standards / Documentation. Or the Docs could be out of sync again. @Jim? @unixbeast?

There are Java libraries with “JSON string to Object Map” conversion Methods, but I don’t know if any library is already available in the sandbox or if a particular one is recommended. Hopefully someone will chime in… Again I’m leaning on @Jim here because I agree with you that an example in the Docs would be quite helpful.

Yes…you could use substring methods, but hopefully it doesn’t come down to that.

1 Like

Maybe looking at an example would help? Here’s the implementation of setColor() from the LIFX device handler: https://github.com/SmartThingsCommunity/SmartThingsPublic/blob/64f671ceb841c0503edb834908b58e98054de123/devicetypes/smartthings/lifx-color-bulb.src/lifx-color-bulb.groovy#L110

Thank-you @Jim, a little more helpful. It is ironic however that the example you link to is using code to set the hex value of the device on multiple different lines when the documentation says its depreciated which kinda validates @tgauchat comments. :wink: But I get it since the bulb uses hex for its command.

Which begs another question…why depreciate hex if the color bulbs on the market accept it? Like the one you linked to…if I’m reading the DTH right (questionable…) then on a setColor it takes the hue, saturation, and color temperature information and saves it to the device but then says if the hex value is in the color map send it. The Cree, Fibaro (which my DTH is based on), generic RGBW, etc all seem to try and use hex first and if it cant they try hue/sat. If hex is depreciated why it is primary in commands? Or is it only depreciated because other vendors (Amazon/Google) have Hue/Sat as primary and it doesn’t matter what the bulb manufactures are doing?

1 Like

It is considered polite for APIs to accommodate the use of deprecated (nb: not “depreciated”) parameters… At least for a transition period.

I can’t think of any good reason for the spec change, though… Except to eliminate risky ambiguous redundancy.


SmartThings is going to have a huge ongoing challenge regarding Capability definitions. Without a meticulously followed rigorous deprecation protocol, Capabilities are effectively immutable, and that can stifle innovation.

2 Likes