HUE Binding: HSBType Color Discrepancy

Tags: #<Tag:0x00007fc3eb168af8> #<Tag:0x00007fc3eb168a30> #<Tag:0x00007fc3eb168918>

Hi Openhabians,

recently i have set up some rules to make my hue bulbs give some information about the house state. For example, when the front door is closed, the porch light will glow green shortly if all doors and windows are shut, red otherwise.
To set the color, I use HSBType, and thats when I saw that for some reason, I can not achieve 100% saturation nor get one color round trip through my rule.
The following experiment will show the behaviour:

GF_Dining_EZEssplatz_Color.sendCommand(new HSBType(new DecimalType(0), new PercentType(100), new PercentType(100)))

Is what I expect to turn the lamp to a fully saturated red with maximum brightness.
The command is well received, the REST API tells me, the Item state is now: 0,100,100.
However, the color of the hue bulb seems washed out.
So I open my All4HUE app and use the color picker. My first find is, the current position of the color picker is not on full saturation. Then I move the color picker to a full red and the bulb actually changes to what i wanted it to be in the first place.
Strangely, the item state updates to 0,100,100 in openhab.
To me, it looks like the maximum saturation value is communicated as something less then 100 percent, and as anything else received would be more than 100 is floored to 100%?

It “works” for blue and green as well… Does anybody experience the same?

@BobMiles

AFAIK Hue bulbs use HSBType automatically.

try:

GF_Dining_EZEssplatz_Color.sendCommand("0,100,100")

or

sendCommand(GF_Dining_EZEssplatz_Color, 0,100,100)

.

EDIT: But you’re right. In HUE APP the saturation is not shown by 100%.

Maybe this is because Philips Hue uses the CIE 1931 color space.

A very good explanation you also can see here.

Maybe it’s not calculated exactly or due to other reasons (e.g. compatibility of non Hue bulbs)?

1 Like

Thanks for your answer!
I tried giving the HSB values as string without the HSBType (“0,100,100”) but the result was the same.
Also HSBType::RED will produce the washed out red with less than 100 percent saturation. I tried it on original Hue Bulbs als well as Innr bulbs.
I think there might be a bug! Is there another way to issue a color command?

Maybe @cweitkamp knows about this? How is the saturation calculated in Hue binding?

Hi all,

Something about the Philips Hue and color:

I just realized there is a second user experiencing the same problem: Hue colors in HSV/HSB differ from the Hue app.

I do not have my development environment handy. Will investigate on it in the next couple of days. Maybe there was a change in the API.

@BobMiles May I ask for your current openHAB version installed? Thanks.

Having the same issue, but mine is an older version. Snapshot #1486 from January 2019.

What you can do in the meantime is to enable DEBUG or TRACE logging for the binding and try to find out what the binding will send towards the Hue API. Basically the saturation in OH HSBType is a percentage from 0-100 which will be multiplied by 2.54 before sending the request. The API accepts saturation values between 0 and 254.

1 Like

Thanks. I’m going to try this tomorow morning.

Thanks for all the info! I’m on 2.4 stable. Rpi3B.
I’ll enable debug tomorrow and will post the information as soon as I have it.
Again, thanks for all your efforts!

You mean the hue bridge REST API? Be careful, this may take a while to update. Depending on the size of your Zigbee network well between 30s to over a minute.

I bet the All4HUE app as well as the Philips app is using x,y,B. Now this is converted by the bulb to some RGB. Note the some, this depends on the RGB definiton, e.g. sRGB, Oracle RGB or whatever the bulb color triangle describes. This RGB is than converted to HSB values. Consequently the HSB is computed from clipped RGB value. Sounds complicated … it is.
The hue binding will only look at the HSB values reported on the bridge. If All4Hue sends x,y,B the HSB values in the REST API may stay unchanged for quite a while until the bulb updated them and they were pulled by the bridge.

To make the issue even more complicated: As described, the bulb does the x,y,B <-> HSB conversion. Philips bulbs are pretty good. RGB(W) controllers (e.g. Dresden electronics) just assume a standard color triangle and I don’t dare to imagine what some cheap RGB(W) devices will do.

To cut a long story short: x,y,B is the representation to use, HSB is not really documented. Even the use of linear RGB or sRGB (i.e. including Gamma correction) seems to depend on the application. So what you are observing is not a bug, it is expected behaviour when using HSB.

That’s why I dropped the hue binding and replaced it with my own javascript implementation which will send x,y,B based on a HSB->sRGB->RGB->x,y,B conversion. At least the hue colors match the screen colors more or less. And the implementation allows me to use RGB+W (separate “bulbs” in e.g. Dresden controller) lightstrip controllers and do color mixing.

Good Morning,

i think the hue binding is communicating using the x,y,B.
Here is my log output for the command (“0,100,100”).

2019-08-24 07:37:00.296 [DEBUG] [home.binding.hue.internal.HttpClient] - Async sending put to address: http://192.168.178.21/api/MYTOKEN/lights/14/state delay: 80 body: {“xy”:[0.64007455,0.3299705],“bri”:254}

Should this not ideally be x = 0 and y = 0 (left lower corner of the color space where red is fully saturated)?

Sure there will be some FLOP truncation, but it is lacking more than 10% saturation I guess…

Anyone volunteering for double checking our calculations from HSB to XY in the HSBType?

1 Like

@cweitkamp @BobMiles @couriersud

I did further investigatons: I’ve checked all results with the Hue API.

There are different color modes of the Hue Brigde: hs=HSB, xy=XY, ct=Color Temperature

I’ve checked all DEFAULT COLORS: RED, YELLOW, GREEN, CYAN, BLUE, MAGENTA

here are my results:

RED:

2019-08-24 08:22:26.527 [ome.event.ItemCommandEvent] - Item 'Innr_Light1_Color' received command 0,100,100
2019-08-24 08:22:26.529 [vent.ItemStateChangedEvent] - Innr_Light1_Color changed from 25,98,100 to 0,100,100

{
	"state": {
		"on": true,
		"bri": 254,
		"hue": 0,
		"sat": 254,
		"effect": "none",
		"xy": [
			0.6961,
			0.3003
		],
		"ct": 500,
		"alert": "select",
		"colormode": "hs",
		"mode": "homeautomation",
		"reachable": true
	}

“hue:” 0/182=0°
.

YELLOW:

2019-08-24 08:25:28.492 [ome.event.ItemCommandEvent] - Item 'Innr_Light1_Color' received command 60,100,100
2019-08-24 08:25:28.495 [vent.ItemStateChangedEvent] - Innr_Light1_Color changed from 0,100,100 to 60,100,100


{
"state": {
	"on": true,
	"bri": 254,
	"hue": 10920,
	"sat": 254,
	"effect": "none",
	"xy": [
		0.472,
		0.499
	],
	"ct": 388,
	"alert": "select",
	"colormode": "hs",
	"mode": "homeautomation",
	"reachable": true
},

“hue:” 10920/182=60°
.

GREEN:

2019-08-24 09:23:40.768 [ome.event.ItemCommandEvent] - Item 'Innr_Light1_Color' received command 120,100,100
2019-08-24 09:23:40.775 [vent.ItemStateChangedEvent] - Innr_Light1_Color changed from 60,100,100 to 120,100,100


{
	"state": {
		"on": true,
		"bri": 254,
		"hue": 21840,
		"sat": 254,
		"effect": "none",
		"xy": [
			0.1141,
			0.8113
		],
		"ct": 500,
		"alert": "select",
		"colormode": "hs",
		"mode": "homeautomation",
		"reachable": true
	}

“hue:” 21840/182=120°
.

CYAN:

2019-08-24 09:29:12.010 [ome.event.ItemCommandEvent] - Item 'Innr_Light1_Color' received command 180,100,100
2019-08-24 09:29:12.021 [vent.ItemStateChangedEvent] - Innr_Light1_Color changed from 300,100,100 to 180,100,100

{
"state": {
	"on": true,
	"bri": 254,
	"hue": 32760,
	"sat": 254,
	"effect": "none",
	"xy": [
		0.1177,
		0.3473
	],
	"ct": 500,
	"alert": "select",
	"colormode": "hs",
	"mode": "homeautomation",
	"reachable": true
}

“hue:” 32760/182=180°
.

BLUE:

2019-08-24 09:41:57.266 [ome.event.ItemCommandEvent] - Item 'Innr_Light1_Color' received command 240,100,100
2019-08-24 09:41:57.271 [vent.ItemStateChangedEvent] - Innr_Light1_Color changed from 180,100,100 to 240,100,100

{
	"state": {
		"on": true,
		"bri": 254,
		"hue": 43680,
		"sat": 254,
		"effect": "none",
		"xy": [
			0.122,
			0.0828
		],
		"ct": 500,
		"alert": "select",
		"colormode": "hs",
		"mode": "homeautomation",
		"reachable": true
	}

“hue:” 43680/182=240°
.

MAGENTA:

2019-08-24 09:46:58.030 [ome.event.ItemCommandEvent] - Item 'Innr_Light1_Color' received command 300,100,100
2019-08-24 09:46:58.032 [vent.ItemStateChangedEvent] - Innr_Light1_Color changed from 180,100,100 to 300,100,100


 {
	"state": {
		"on": true,
		"bri": 254,
		"hue": 54600,
		"sat": 254,
		"effect": "none",
		"xy": [
			0.3948,
			0.1851
		],
		"ct": 266,
		"alert": "select",
		"colormode": "hs",
		"mode": "homeautomation",
		"reachable": true
	}

“hue:” 54600/182=300°
.
.
.
As you can see, everything seems to be OK. Saturation always=254 (!!!)

The xy values I don’t know if they are correct??

But I also had strange effects while testing. Sometimes the color temperature changed from 500 to 388 or 266, but I could not find the reason. Especially (388) when switching to “yellow”.

Sometimes saturation was not 254, it then was 243 or 238.

And sometimes the color mode changed to xy. EDIT: (I now found out) when official Hue APP is used for setting a color!

To get it back to “hs” I had to switch “color temperature” manually e.g. to 100% (=500), then the color mode switched to “ct”. After that, when I’ve changed the color, then it was “hs” again.

Here is a screenshot of HueApp when e.g. RED was set correct by openhab.

And here BLUE:

.
.

EDIT: SUMMARY of above:

Color hue saturation brightness x y ct comment
RED 0 254 254 0.6961 0.3003 500 OK
YELLOW 10920 254 254 0.472 0.499 388 ??
GREEN 21840 254 254 0.1141 0.8113 500 OK
CYAN 32760 254 254 0.1177 0.3473 500 OK
BLUE 43680 254 254 0.122 0.0828 500 OK
MAGENTA 54600 254 254 0.3948 0.1851 266 ??

.
.
Why is color temperature (=ct) changed by switching to yellow or magenta?

Could anyone please calculate if x,y are OK? Thanks a lot! :slight_smile:

1 Like

Shouldn’t the D65 Norm white be: X0,312713 Y0,329016
When I look at the Rgb2Xy it says

Rgb2Xy[][] = { { 0.4124f, 0.3576f, 0.1805f }, { 0.2126f, 0.7152f, 0.0722f },
        { 0.0193f, 0.1192f, 0.9505f } };

Where Rgb2Xy[0][] is full D65 white if I understand correctly?

Edit: Sorry, now I see the conversion matrix. it’s correct in the code.

Basically what is needed is provided by the api for color lights:

				"colorgamuttype": "C",
				"colorgamut": [
					[
						0.6915,
						0.3083
					],
					[
						0.17,
						0.7
					],
					[
						0.1532,
						0.0475
					]
				],

This are the maximum saturation red, green and blue color the light can display. What is missing is the white point (WP). With this information you can build a linear RGB to Yxy matrix needed for WP correction. Basically the following conversion have to done:

  • HSB to sRGB - all colorpickers I have seen use sRGB values and convert them to HSB
  • sRGB to linear RGB
  • linear RGB to Yxy (based on sRGB triangle and WP)
  • Yxy WP correction from sRGB WP to bulb WP
  • convert Y to Brightness
  • send x,y,B to bridge

This approach ensures that the bulb will have a color close to the color picker color. But the sRGB gamut is smaller than the Hue gammuts. This means you will never get fully saturated colors with this approach.
Philips recommends using Wide RGB instead of sRGB. The formulas given by Philips are most likely used by a lot of apps so may be a basis for consistent behaviour.
I am using DCI-P3 in my code since it comes close to the hue gammuts and thus avoids excessive clippings. But for both Wide RGB and DCI-P3 the color picker color may not be close to the illumination color.

1 Like

OK, my bulbs from testing above have:

"colorgamuttype": "other",
			"colorgamut": [
				[
					0.7,
					0.3
				],
				[
					0.11,
					0.82
				],
				[
					0.12,
					0.08
				]
			]

If I compare these (red, green, blue) to my above table, the values are approximately accurate.

Color gamut(x) x gamut(y) y
RED 0.7 0.6961 0.3 0.3003
GREEN 0.11 0.1141 0.82 0.8113
BLUE 0.12 0.122 0.08 0.0828

:+1: Great job guys. Lots of information to work with. To wrap it up: If we want to support (nearly) similar colors than Philips Hue we have to improve our XY calculation. Different bulbs / luminaries have different gammuts. On the one hand we are lucky because the Hue API tells us which one is supported. On the other hand we currently use a fixed one in OHC (HSBType). Thus we need a way to do the new math.

It looks like the formulas given by Philips and our calculation of the gamma corrections are slightly different.

Philips’ formula:

float red = (red > 0.04045f) ? pow((red + 0.055f) / (1.0f + 0.055f), 2.4f) : (red / 12.92f);

Our formula:

return c <= 0.04045f ? c / 19.92f : (float) Math.pow((c + 0.055f) / (1.0f + 0.055f), 2.4f);

Do you see it (ignore the syntax)? :wink: It looks like a small typo introduced by the initial commit while the previous calculation was correct. I will provide a fix for it.

3 Likes

@cweitkamp

You used 19.92f instead of 12.92f :wink:

My fix has been merged yesterday. Can anyone test again?

1 Like

@cweitkamp
I’d rather like to test it, but unfortunately I cannot switch to the newest snapshots, (because AmazonDashButton binding is not running with npcap on Windows 10 with Wifi only connection.) Maybe I’ll find time on the weekend, setting up a test machine with latest snapshot.