This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm that you accept these cookies being set.

Phlips Hue - RGB Color Feedback - Zigbee
#1
Hello everyone,
I am trying to read the color status of a Philips RGB lamp with the Zigbee gateway.
Looking at the link: https://kb.logicmachine.net/libraries/zigbee/

I have been able to get the On/Off status, color temperature, but I am not able to read the RGB status.I don't understand that about xy and then being able to convert it to 3 bytes to use it on KNX screens.
Can anybody help me?
Thank you so much in advance,
Reply
#2
Try using xy_to_rgb from user.hue v2.lua: https://forum.logicmachine.net/showthrea...50#pid6250
Reply
#3
Code:
RGB = event.getvalue()

-- Norm of RGB values
R = bit.rshift(bit.band(RGB, 0xFF0000), 16)
G = bit.rshift(bit.band(RGB, 0x00FF00), 8)
B = bit.band(RGB, 0x0000FF)

Red =    R / 255
Green = G / 255
Blue = B / 255

-- Gamma correction
if Red > 0.04045 then
  Red = ((Red + 0.055) / (1 + 0.055))^2.4
else
  Red = Red / 12.92
end

if Green > 0.04045 then
  Green = ((Green + 0.055) / (1 + 0.055))^2.4
else
  Green = Green / 12.92
end

if Blue > 0.04045 then
  Blue = ((Blue + 0.055) / (1 + 0.055))^2.4
else
  Blue = Red / 12.92
end

-- Coversion RGB > XY
X = Red * 0.649926 + Green * 0.103455 + Blue * 0.197109
Y = Red * 0.234327 + Green * 0.743075 + Blue * 0.022598
Z = Green * 0.053077 + Blue * 1.035763

x = X / (X+Y+Z)
y = Y / (X+Y+Z)

-- Coversion XY > CCT
n = (x - 0.3320) / (0.1858 - y)
cct = math.floor((-449 * ((x - 0.332) / (y - 0.1858))^3) + (3525 * ((x - 0.332) / (y - 0.1858))^2) - (6823.3 * ((x - 0.332) / (y - 0.1858))) + (5520.33))

log(cct)
Reply
#4
(21.03.2024, 09:13)admin Wrote: Try using xy_to_rgb from user.hue v2.lua: https://forum.logicmachine.net/showthrea...50#pid6250

I'm trying to use xy_to_rgb from user.hue v2.lua. But I can't be doing it right. I have copied the function into common functions. Then I have in the event script:

Code:
xy = zb.cmdsync('getxy', addr)
rgb = xy_to_rgb(xy['x'],xy['y'])
log(rgb)

But I get the excact same rgb value wether I have red or blue light. (255,0,0) or (0,0,255) gives the same rgb value. But the lamp is red or blue correctly. For colours without blue the result makes sense I think, but it seems like blue and red is mixed up somehow.

Value of variable rgb is 16711680 for both (255,0,0) and (0,0,255)...

I can see that the x and y values differ (45913,19614) for red and (8880,2613) for blue - so the result shouldn't be equal...

Any hints? Smile
Reply
#5
Well, looking more into this I now understand that the xy coordinates should be less than 1 - and that's the main problem. Don't know where these numbers come from, or what I can do with them... Help!
Reply
#6
Use this conversion function:
Code:
function xytorgb(x, y, level)
  local function revgamma(v)
    if v <= 0.0031308 then
      return v * 12.92
    else
      return (1 + 0.055) * math.pow(v, (1 / 2.4)) - 0.055
    end
  end

  local function clampconvert(v, max)
    v = math.max(0, v * 255 / max)
    v = math.min(255, v)
    return math.round(v)
  end

  local x = x / 0xFFFE
  local y = y / 0xFFFE
  local z = 1 - x - y

  local Y = math.min(254, level) / 254
  local X = (Y / y) * x
  local Z = (Y / y) * z

  local r = revgamma(3.2404542 * X - 1.5371385 * Y - 0.4985314 * Z)
  local g = revgamma(-0.9692660 * X + 1.8760108 * Y + 0.0415560 * Z)
  local b = revgamma(0.0556434 * X - 0.2040259 * Y + 1.0572252 * Z)

  local max = math.max(r, g, b)

  r = clampconvert(r, max)
  g = clampconvert(g, max)
  b = clampconvert(b, max)

  return r * 0x10000 + g * 0x100 + b
end

x = 45913
y = 19614
level = 254

rgb = xytorgb(x, y, level)
log(rgb)

You also need to pass the light level (0..254) for the conversion to work.
Reply
#7
Thank you so much! This works nicely! 

Can I ask why getxy() returns not xy? Smile

But I think I have uncovered a bug in the Mosaic RGBW dimmer (6 byte DALI) widget. It seems it expects 0-255 values, but according to this:

https://support.knx.org/hc/en-us/article...2631105682

(and my Gira devices...) the 6 byte DPT 251.600 should have 0-100 as value for the different colours. Unlike 232.600 which is 0-255... Yay for consistency from KNX...

Unless I'm mistaken (which I very much could be...) it would be awesome if this could be fixed in the next FW release Smile
Reply
#8
The actual range is 0..255 which is treated as 0..100%. Notice the resolution is ~0.4% (100/255).
Reply
#9
Might be... But Gira sends (and expects) 0-100. But that might be their bug, I don't have anything else to compare with.

(But why is the DPT 232.600 showing expected value to be 0-255, while DPT 251.600 shows 0-100 in the specifications?)

Seems atleast a MDT Dali controller does the same: https://community.openhab.org/t/rgbw-col...600/150055
Reply
#10
I still think I'm right about the 6 bit DALI RGBW DPT...

But anyways, your xytorgb() works very good. I have not been comparing input and output, because that doesn't really matter, but I just noticed that for different green colours, I usually get the same feedback anyways...


rgb(0 149 48) gives me x=11049, y=44152
rgb(0 255 0) gives me x=11299, y=48940

But running both these coordinates through xytorgb() gives me 0,255,0 as feedback... 

As I wrote, I understand that it's impossible to match input and feedback 100%, but I feel this should have been better..?

What do you think?
Reply
#11
MDT is brand labeling this from IPAS and they have new firmware which is fixing this bug. Check if MDT already released latest version.
Same works correct on SE (also IPAS branded) version.
------------------------------
Ctrl+F5
Reply
#12
Try this updated conversion function:
Code:
function xytorgb(x, y, level)
  local function revgamma(v)
    if v <= 0.0031308 then
      return v * 12.92
    else
      return (1 + 0.055) * math.pow(v, (1 / 2.4)) - 0.055
    end
  end

  local function round(v)
    if v <= 0 then
      return 0
    else
      return math.round(v * level)
    end
  end

  x = x / 0xFFFE
  y = y / 0xFFFE

  local z = 1.0 - x - y

  local Y = level
  local X = (Y / y) * x
  local Z = (Y / y) * z

  local r = X * 1.656492 - Y * 0.354851 - Z * 0.255038
  local g = -X * 0.707196 + Y * 1.655397 + Z * 0.036152
  local b = X * 0.051713 - Y * 0.121364 + Z * 1.01153

  if r > b and r > g and r > 1 then
    g = g / r
    b = b / r
    r = 1
  elseif g > b and g > r and g > 1 then
    r = r / g
    b = b / g
    g = 1
  elseif b > r and b > g and b > 1 then
    r = r / b
    g = g / b
    b = 1
  end

  r = round(revgamma(r))
  g = round(revgamma(g))
  b = round(revgamma(b))

  return r * 0x10000 + g * 0x100 + b
end
Reply
#13
This one is perfect, thank you so much!

I didn't notice that I had getlevel before setrgb, so things didn't really make sense. But eventually I saw my mistake and now it's 100%!

Thank you! Smile
Reply


Forum Jump: