Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[hue] OH binding should use same color Gamut as Hue App #16482

Closed
andrewfg opened this issue Mar 4, 2024 · 11 comments · Fixed by #16436
Closed

[hue] OH binding should use same color Gamut as Hue App #16482

andrewfg opened this issue Mar 4, 2024 · 11 comments · Fixed by #16436
Assignees
Labels
enhancement An enhancement or new feature for an existing add-on

Comments

@andrewfg
Copy link
Contributor

andrewfg commented Mar 4, 2024

To be honest, I am not sure if this is a bug or a feature. And/or if it requires any action in the binding. Therefore I am simply recording this issue as a place holder for the time being..

The issue is as follows..

  1. Older Hue color lamps support Gamut B (which is a relatively limited color space -- red triangle on image below).
  2. Towards OH the Hue API v2 reports that such lamps support Gamut B.
  3. Currently, therefore, the OH binding constrains outgoing commanded xy colors to those within Gamut B.
  4. And currently, therefore, the OH binding constrains incoming xy evented xy colors to those within Gamut B.
  5. HOWEVER the color wheel selectors in the Hue App use Gamut C (which is a much wider color space -- blue triangle on image below)
  6. AND THEREFORE when the Hue App is used to send a Gamut C color to a Gamut B lamp, the Hue API v2 reports an xy color event corresponding the Gamut C xy coordinate from the App -- even though the lamp is actually not able to display that color.
  7. Yet (because of 4. above) the OH binding constrains that incoming xy evented xy color to be within Gamut B again.
  8. This means that OH IS aligned with the colors that are actually physically possible for the lamp, but OH is NOT aligned with the colors seen in the Hue App.

Note: this is particularly noticeable when the App sends a deep green color.

image

@andrewfg andrewfg added the enhancement An enhancement or new feature for an existing add-on label Mar 4, 2024
@andrewfg
Copy link
Contributor Author

andrewfg commented Mar 4, 2024

@jlaur any thoughts?

@andrewfg andrewfg self-assigned this Mar 4, 2024
@andrewfg
Copy link
Contributor Author

andrewfg commented Mar 7, 2024

Just a further feedback: It seems that the Hue App is smarter than I originally thought. When you use the app to set a color that is outside the gamut of the lamp, it initially shows the color that you selected. However after about 30 seconds, it 'pops' to show the actual color which the lamp has been able to achieve. See video below .. watch it until the end!

Screen_Recording_20240307_174720_Hue.mp4

@jlaur
Copy link
Contributor

jlaur commented Mar 7, 2024

@andrewfg - I don't have detailed knowledge about color gamut etc. But from the explanation you have given, my immediate feedback would be that we should probably accept Gamut C input and send that to the bridge. Can you try that, and see how that will work now that we have #15984 in place? I would expect the channel state to be "auto-corrected" to be within the allowed gamut.

@andrewfg
Copy link
Contributor Author

andrewfg commented Mar 7, 2024

@jlaur thanks for the feedback. This issue is not directly connected to core #4124 and addons #16436 .. but it is somehow all part of the bigger picture. I am going to do some Wiresharking on the Hue App to see what it is sending to bridge, and if it sends Gamut C to the bridge, then I would suggest we do the same. (But otherwise not..)

Current behavior is as follows..

  • Hue App: user moves the color to an "impossible" color => app display shows that color => 30 seconds later app shows actual color
  • OH binding: user moves the color to an "impossible" color => OH corrects on the fly to a possible color => OH displays actual color
C914E27B-D0AE-45D4-94CE-1DCE4FC81E22.MP4

@jlaur
Copy link
Contributor

jlaur commented Mar 7, 2024

  • OH binding: user moves the color to an "impossible" color => OH corrects on the fly to a possible color => OH displays actual color

Just to be sure, doesn't this mean that when trying to select a color within the Gamut C colorspace for a lamp supporting Gamut C, this will be "corrected" to Gamut B?

@andrewfg
Copy link
Contributor Author

andrewfg commented Mar 7, 2024

doesn't this mean that when trying to select a color within the Gamut C colorspace for a lamp supporting Gamut C, this will be "corrected" to Gamut B?

Each lamp declares its own gamut triangle; it doesn’t actually say A or B or C, but rather it gives the actual XY coordinates of its particular gamut triangle in the color space. Currently the binding receives user color commands (from HSBType) and first converts those to ‘raw’ XY, and then secondly adjusts the ‘raw’ XY to a ‘clean’ XY that lies within the particular lamp’s self declared gamut triangle. The hypothesis is that if we would NOT apply the second cleaning adjustment, then the Hue bridge (or the lamp itself) would do the cleaning adjustment for itself; and report the subsequent ‘clean’ XY back to the OH binding via the state change event message; whereupon the returned clean XY is converted back to HSB for the OH UI. I think it would certainly be neater if the Hue bridge or lamp would do its own cleaning (avoiding double cleaning, and possible conflicts). But we just need to check in real life if the Hue bridge or lamp will not be upset if it is given a non clean XY coordinate..

@andrewfg
Copy link
Contributor Author

andrewfg commented Mar 8, 2024

@jlaur I tested a version of the binding that does not apply any gamut cleaning, and just sends the raw XY values directly. The response is not what I expected before making the test, but having done the test, I am not at all surprised by the result!

  • When the binding applies gamut cleaning, the bridge sends one single event update echoing the gamut cleaned XY value.
  • When the binding sends the raw XY value, the bridge sends two event updates, one immediately echoing the raw XY value, and then another a few seconds later with the gamut cleaned XY value. (This delay suggests that the gamut cleaning may be being done in the lamp rather than the bridge).

I am not sure if this an improvement or not -- in the binding release version the OH UI immediately updates to the gamut corrected XY, whereas in the test version the OH UI updates after 4 seconds. => WDYT?

2024-03-08 16:33:03.544 [TRACE] [org.openhab.core.util.ColorUtil     ] - HSB:[0.000000,100.000000,100.000000] - RGB:[1.000000,0.000000,0.000000] - XYZ:[0.664511,0.283881,0.000088] - xyz:[0.700606,0.299301,0.283881] - xyY:[0.698738,0.297432,0.283881] (xyForced:true)
2024-03-08 16:33:03.545 [TRACE] [.hue.internal.connection.Clip2Bridge] - PUT https://192.168.1.108/clip/v2/resource/light/bcad47a0-3f1f-498c-a8aa-3cf389965219 HTTP/2 >> {"type":"light","id":"bcad47a0-3f1f-498c-a8aa-3cf389965219","on":{"on":true},"dimming":{"brightness":100.0},"color":{"xy":{"x":0.698737790618585,"y":0.2974323567351564}}}
2024-03-08 16:33:03.635 [TRACE] [.hue.internal.connection.Clip2Bridge] - HTTP/2 200 (Content-Type: application/json) << {"data":[{"rid":"bcad47a0-3f1f-498c-a8aa-3cf389965219","rtype":"light"}],"errors":[]}
2024-03-08 16:33:03.653 [TRACE] [.hue.internal.connection.Clip2Bridge] - onEventData() data:[{"creationtime":"2024-03-08T16:33:03Z","data":[{"color":{"xy":{"x":0.6987,"y":0.2974}},"color_temperature":{"mirek":null,"mirek_valid":false},"id":"bcad47a0-3f1f-498c-a8aa-3cf389965219","id_v1":"/lights/3","owner":{"rid":"7bf2175d-0bb8-48dc-a7b4-775d3af3dfc9","rtype":"device"},"service_id":0,"type":"light"}],"id":"3926bcfc-4717-4293-b71d-998ef227ba4b","type":"update"}]
2024-03-08 16:33:03.655 [TRACE] [org.openhab.core.util.ColorUtil     ] - xyY:[0.698700,0.297400,0.297400] - xyz:[0.698700,0.297400,0.003900] - XYZ:[0.698700,0.297400,0.003900] - RGB:[1.000000,0.000000,0.064449] - HSB:[356.133000,100.000000,100.000000] (xyForced:false)
2024-03-08 16:33:07.932 [TRACE] [.hue.internal.connection.Clip2Bridge] - onEventData() data:[{"creationtime":"2024-03-08T16:33:07Z","data":[{"color":{"xy":{"x":0.675,"y":0.322}},"color_temperature":{"mirek":null,"mirek_valid":false},"id":"bcad47a0-3f1f-498c-a8aa-3cf389965219","id_v1":"/lights/3","owner":{"rid":"7bf2175d-0bb8-48dc-a7b4-775d3af3dfc9","rtype":"device"},"service_id":0,"type":"light"}],"id":"66956ede-c554-436f-aaf9-18b2d556db00","type":"update"}]
2024-03-08 16:33:07.935 [TRACE] [org.openhab.core.util.ColorUtil     ] - xyY:[0.675000,0.322000,0.321584] - xyz:[0.674584,0.321584,0.003832] - XYZ:[0.674584,0.321584,0.003832] - RGB:[1.000000,0.261368,0.000000] - HSB:[15.682000,100.000000,100.000000] (xyForced:true)

EDIT: the code tested is here

@jlaur
Copy link
Contributor

jlaur commented Mar 9, 2024

I am not sure if this an improvement or not -- in the binding release version the OH UI immediately updates to the gamut corrected XY, whereas in the test version the OH UI updates after 4 seconds. => WDYT?

The advantage of leaving this calculation/feedback entirely to the bridge/lamp is that the logic on OH side would be simpler (there wouldn't be any) and we will be less prone to errors if a lamp would report wrong gamut, or none at all. We would remove all assumptions. For example, if a lamp reports gamut B, but actually supports gamut C, we would not be able to utilize the full color space. So I think the device support would be better by sending the raw XY - like I understand the Hue app also does.

On the other hand, the advantage of applying our own correction before sending the command is almost immediate feedback on final target value, as opposed to having to wait a few seconds for that.

IMHO the advantage of better device compatibility and eliminated risk of miscalculations on our side outweights the benefit of this slightly faster update.

@andrewfg
Copy link
Contributor Author

andrewfg commented Mar 9, 2024

@jlaur I agree with you.

However just one minor clarification comment..

less prone to errors if a lamp would report .. none at all

According to the Philips specifications, in order to NOT do gamut correction (in the case where the lamp specifies none) then one must actually apply the so called 'Default Gamut' correction (see below). In other words, according to Philips, even if 'no' gamut correction shall be applied, we must still apply the default correction. I think the purpose of this is to ensure that XY values cannot exceed 1.0 (??)

But if one overlays the 'Default Gamut' on the CIE chart, one can see that it does actually still clip the far right (red) corner of the chart. So in order to really really eliminate gamut clipping within OH (i.e. to actually not correct any raw XYs) we need in fact to apply a 'Revised Default Gamut' as shown below. (I know this sounds convoluted, but please bear with me..)

=> So today I shall make another change to achieve the above, and test it ASAP.

// Philips 'Default Gamut'
public static final Gamut DEFAULT_GAMUT = new Gamut(new double[] { 0.9961, 0.0001 }, new double[] { 0, 0.9961 }, new double[] { 0, 0.0001 });

// Proposed 'Revised Default Gamut'
public static final Gamut DEFAULT_GAMUT = new Gamut(new double[] { 0.820, 0.185 }, new double[] { 0, 0.9961 }, new double[] { 0, 0.0001 });

@andrewfg
Copy link
Contributor Author

andrewfg commented Mar 9, 2024

^
Tested. Seems to work fine!

2024-03-09 13:54:24.293 [TRACE] [org.openhab.core.util.ColorUtil     ] - HSB:[0.000000,100.000000,100.000000] - RGB:[1.000000,0.000000,0.000000] - XYZ:[0.664511,0.283881,0.000088] - xyz:[0.700606,0.299301,0.283881] - xyY:[0.700606,0.299301,0.283881] (xyForced:false)
2024-03-09 13:54:24.294 [TRACE] [.hue.internal.connection.Clip2Bridge] - PUT https://192.168.1.108/clip/v2/resource/light/bcad47a0-3f1f-498c-a8aa-3cf389965219 HTTP/2 >> {"type":"light","id":"bcad47a0-3f1f-498c-a8aa-3cf389965219","on":{"on":true},"dimming":{"brightness":100.0},"color":{"xy":{"x":0.7006062331309042,"y":0.2993009868421053}}}
2024-03-09 13:54:24.383 [TRACE] [.hue.internal.connection.Clip2Bridge] - HTTP/2 200 (Content-Type: application/json) << {"data":[{"rid":"bcad47a0-3f1f-498c-a8aa-3cf389965219","rtype":"light"}],"errors":[]}
2024-03-09 13:54:24.402 [TRACE] [.hue.internal.connection.Clip2Bridge] - onEventData() data:[{"creationtime":"2024-03-09T13:54:24Z","data":[{"color":{"xy":{"x":0.7006,"y":0.2993}},"color_temperature":{"mirek":null,"mirek_valid":false},"id":"bcad47a0-3f1f-498c-a8aa-3cf389965219","id_v1":"/lights/3","owner":{"rid":"7bf2175d-0bb8-48dc-a7b4-775d3af3dfc9","rtype":"device"},"service_id":0,"type":"light"}],"id":"a8392f99-1aa2-47eb-81cc-222940245389","type":"update"}]
2024-03-09 13:54:24.405 [TRACE] [org.openhab.core.util.ColorUtil     ] - xyY:[0.700600,0.299300,0.299300] - xyz:[0.700600,0.299300,0.000100] - XYZ:[0.700600,0.299300,0.000100] - RGB:[1.000000,0.000030,0.000086] - HSB:[359.996000,99.997000,100.000000] (xyForced:false)
2024-03-09 13:54:31.674 [TRACE] [.hue.internal.connection.Clip2Bridge] - onEventData() data:[{"creationtime":"2024-03-09T13:54:31Z","data":[{"color":{"xy":{"x":0.675,"y":0.322}},"color_temperature":{"mirek":null,"mirek_valid":false},"id":"bcad47a0-3f1f-498c-a8aa-3cf389965219","id_v1":"/lights/3","owner":{"rid":"7bf2175d-0bb8-48dc-a7b4-775d3af3dfc9","rtype":"device"},"service_id":0,"type":"light"}],"id":"60de6316-5807-4c38-98b0-673b4ae5d51c","type":"update"}]
2024-03-09 13:54:31.678 [TRACE] [org.openhab.core.util.ColorUtil     ] - xyY:[0.675000,0.322000,0.322000] - xyz:[0.675000,0.322000,0.003000] - XYZ:[0.675000,0.322000,0.003000] - RGB:[1.000000,0.264058,0.000000] - HSB:[15.843000,100.000000,100.000000] (xyForced:false)

2024-03-09 13:55:23.768 [TRACE] [org.openhab.core.util.ColorUtil     ] - HSB:[120.000000,100.000000,100.000000] - RGB:[0.000000,1.000000,0.000000] - XYZ:[0.154324,0.668433,0.072310] - xyz:[0.172416,0.746797,0.668433] - xyY:[0.172416,0.746797,0.668433] (xyForced:false)
2024-03-09 13:55:23.769 [TRACE] [.hue.internal.connection.Clip2Bridge] - PUT https://192.168.1.108/clip/v2/resource/light/bcad47a0-3f1f-498c-a8aa-3cf389965219 HTTP/2 >> {"type":"light","id":"bcad47a0-3f1f-498c-a8aa-3cf389965219","on":{"on":true},"dimming":{"brightness":100.0},"color":{"xy":{"x":0.1724161431490603,"y":0.7467966085220437}}}
2024-03-09 13:55:23.855 [TRACE] [.hue.internal.connection.Clip2Bridge] - HTTP/2 200 (Content-Type: application/json) << {"data":[{"rid":"bcad47a0-3f1f-498c-a8aa-3cf389965219","rtype":"light"}],"errors":[]}
2024-03-09 13:55:23.873 [TRACE] [.hue.internal.connection.Clip2Bridge] - onEventData() data:[{"creationtime":"2024-03-09T13:55:23Z","data":[{"color":{"xy":{"x":0.1724,"y":0.7468}},"color_temperature":{"mirek":null,"mirek_valid":false},"id":"bcad47a0-3f1f-498c-a8aa-3cf389965219","id_v1":"/lights/3","owner":{"rid":"7bf2175d-0bb8-48dc-a7b4-775d3af3dfc9","rtype":"device"},"service_id":0,"type":"light"}],"id":"78237e46-000e-4620-9006-59a696d9ec44","type":"update"}]
2024-03-09 13:55:23.877 [TRACE] [org.openhab.core.util.ColorUtil     ] - xyY:[0.172400,0.746800,0.746800] - xyz:[0.172400,0.746800,0.080800] - XYZ:[0.172400,0.746800,0.080800] - RGB:[0.000000,1.000000,0.000496] - HSB:[120.030000,100.000000,100.000000] (xyForced:false)
2024-03-09 13:55:42.695 [TRACE] [.hue.internal.connection.Clip2Bridge] - onEventData() data:[{"creationtime":"2024-03-09T13:55:42Z","data":[{"color":{"xy":{"x":0.409,"y":0.518}},"color_temperature":{"mirek":null,"mirek_valid":false},"id":"bcad47a0-3f1f-498c-a8aa-3cf389965219","id_v1":"/lights/3","owner":{"rid":"7bf2175d-0bb8-48dc-a7b4-775d3af3dfc9","rtype":"device"},"service_id":0,"type":"light"}],"id":"4e6c6d18-7a32-40ca-a2b9-72578e467389","type":"update"}]
2024-03-09 13:55:42.700 [TRACE] [org.openhab.core.util.ColorUtil     ] - xyY:[0.409000,0.518000,0.518000] - xyz:[0.409000,0.518000,0.073000] - XYZ:[0.409000,0.518000,0.073000] - RGB:[0.718695,0.780250,0.196830] - HSB:[66.329900,74.773000,78.025000] (xyForced:false)

2024-03-09 13:56:19.405 [TRACE] [org.openhab.core.util.ColorUtil     ] - HSB:[240.000000,100.000000,100.000000] - RGB:[0.000000,0.000000,1.000000] - XYZ:[0.162028,0.047685,0.986039] - xyz:[0.135503,0.039879,0.047685] - xyY:[0.135503,0.039879,0.047685] (xyForced:false)
2024-03-09 13:56:19.406 [TRACE] [.hue.internal.connection.Clip2Bridge] - PUT https://192.168.1.108/clip/v2/resource/light/bcad47a0-3f1f-498c-a8aa-3cf389965219 HTTP/2 >> {"type":"light","id":"bcad47a0-3f1f-498c-a8aa-3cf389965219","on":{"on":true},"dimming":{"brightness":100.0},"color":{"xy":{"x":0.13550301400290363,"y":0.03987867049354716}}}
2024-03-09 13:56:19.481 [TRACE] [.hue.internal.connection.Clip2Bridge] - HTTP/2 200 (Content-Type: application/json) << {"data":[{"rid":"bcad47a0-3f1f-498c-a8aa-3cf389965219","rtype":"light"}],"errors":[]}
2024-03-09 13:56:19.502 [TRACE] [.hue.internal.connection.Clip2Bridge] - onEventData() data:[{"creationtime":"2024-03-09T13:56:19Z","data":[{"color":{"xy":{"x":0.1355,"y":0.0399}},"color_temperature":{"mirek":null,"mirek_valid":false},"id":"bcad47a0-3f1f-498c-a8aa-3cf389965219","id_v1":"/lights/3","owner":{"rid":"7bf2175d-0bb8-48dc-a7b4-775d3af3dfc9","rtype":"device"},"service_id":0,"type":"light"}],"id":"7b3c3f03-b54f-4b72-9933-c7583660fa8f","type":"update"}]
2024-03-09 13:56:19.505 [TRACE] [org.openhab.core.util.ColorUtil     ] - xyY:[0.135500,0.039900,0.039900] - xyz:[0.135500,0.039900,0.824600] - XYZ:[0.135500,0.039900,0.824600] - RGB:[0.000000,0.000574,0.924263] - HSB:[239.963000,100.000000,92.426000] (xyForced:false)
2024-03-09 13:56:29.994 [TRACE] [.hue.internal.connection.Clip2Bridge] - onEventData() data:[{"creationtime":"2024-03-09T13:56:29Z","data":[{"color":{"xy":{"x":0.167,"y":0.04}},"color_temperature":{"mirek":null,"mirek_valid":false},"id":"bcad47a0-3f1f-498c-a8aa-3cf389965219","id_v1":"/lights/3","owner":{"rid":"7bf2175d-0bb8-48dc-a7b4-775d3af3dfc9","rtype":"device"},"service_id":0,"type":"light"}],"id":"6e226b8d-bc18-4ad8-a380-de008101b180","type":"update"}]
2024-03-09 13:56:29.999 [TRACE] [org.openhab.core.util.ColorUtil     ] - xyY:[0.167000,0.040000,0.040000] - xyz:[0.167000,0.040000,0.793000] - XYZ:[0.167000,0.040000,0.793000] - RGB:[0.319770,0.000000,0.920771] - HSB:[260.838000,100.000000,92.077000] (xyForced:false)

@andrewfg
Copy link
Contributor Author

@jlaur I combined the code for this topic into my existing #16436 and changed its description to cover both topics.

@andrewfg andrewfg changed the title [hue] [rfc] OH binding should use same color Gamut as Hue App [hue] OH binding should use same color Gamut as Hue App Mar 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement An enhancement or new feature for an existing add-on
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants