[Tradfri] Support for new RGB bulbs #4251 #4271
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
/** | ||
* Copyright (c) 2014-2017 by the respective copyright holders. | ||
* All rights reserved. This program and the accompanying materials | ||
* are made available under the terms of the Eclipse Public License v1.0 | ||
* which accompanies this distribution, and is available at | ||
* http://www.eclipse.org/legal/epl-v10.html | ||
*/ | ||
package org.eclipse.smarthome.binding.tradfri.internal; | ||
|
||
import static org.junit.Assert.*; | ||
|
||
import org.eclipse.smarthome.core.library.types.HSBType; | ||
import org.eclipse.smarthome.core.library.types.PercentType; | ||
import org.junit.Test; | ||
|
||
/** | ||
* Tests for {@link TradfriColor}. | ||
* | ||
* @author Holger Reichert - Initial contribution | ||
*/ | ||
public class TradfriColorTest { | ||
|
||
@Test | ||
public void testFromCieKnownGood1() { | ||
TradfriColor color = TradfriColor.fromCie(29577, 12294, 254); | ||
assertNotNull(color); | ||
assertEquals(255, (int) color.rgbR); | ||
assertEquals(21, (int) color.rgbG); | ||
assertEquals(207, (int) color.rgbB); | ||
assertEquals(29577, (int) color.xyX); | ||
assertEquals(12294, (int) color.xyY); | ||
assertEquals(254, (int) color.brightness); | ||
} | ||
|
||
@Test | ||
public void testFromCieKnownGood2() { | ||
TradfriColor color = TradfriColor.fromCie(19983, 37417, 84); | ||
assertNotNull(color); | ||
assertEquals(110, (int) color.rgbR); | ||
assertEquals(174, (int) color.rgbG); | ||
assertEquals(58, (int) color.rgbB); | ||
assertEquals(19983, (int) color.xyX); | ||
assertEquals(37417, (int) color.xyY); | ||
assertEquals(84, (int) color.brightness); | ||
} | ||
|
||
@Test | ||
public void testFromHSBTypeKnownGood1() { | ||
TradfriColor color = TradfriColor.fromHSBType(HSBType.RED); | ||
assertNotNull(color); | ||
assertEquals(254, (int) color.rgbR); | ||
assertEquals(0, (int) color.rgbG); | ||
assertEquals(0, (int) color.rgbB); | ||
assertEquals(45914, (int) color.xyX); | ||
assertEquals(19615, (int) color.xyY); | ||
assertEquals(254, (int) color.brightness); | ||
} | ||
|
||
@Test | ||
public void testConversionReverse() { | ||
// convert from HSBType | ||
TradfriColor color = TradfriColor.fromHSBType(HSBType.GREEN); | ||
assertNotNull(color); | ||
assertEquals(0, (int) color.rgbR); | ||
assertEquals(254, (int) color.rgbG); // 254 instead of 255 - only approximated calculation | ||
assertEquals(0, (int) color.rgbB); | ||
assertEquals(11299, (int) color.xyX); | ||
assertEquals(48941, (int) color.xyY); | ||
assertEquals(254, (int) color.brightness); | ||
// convert the result again based on the XY values | ||
TradfriColor reverse = TradfriColor.fromCie(color.xyX, color.xyY, color.brightness); | ||
assertNotNull(reverse); | ||
assertEquals(0, (int) reverse.rgbR); | ||
assertEquals(255, (int) reverse.rgbG); // 255 instead of 254 - only approximated calculation | ||
assertEquals(0, (int) reverse.rgbB); | ||
assertEquals(11299, (int) reverse.xyX); | ||
assertEquals(48941, (int) reverse.xyY); | ||
assertEquals(254, (int) reverse.brightness); | ||
} | ||
|
||
@Test | ||
public void testFromColorTemperatureMinMiddleMax() { | ||
// coldest color temperature -> preset 1 | ||
TradfriColor colorMin = TradfriColor.fromColorTemperature(PercentType.ZERO); | ||
assertNotNull(colorMin); | ||
assertEquals(24933, (int) colorMin.xyX); | ||
assertEquals(24691, (int) colorMin.xyY); | ||
// middle color temperature -> preset 2 | ||
TradfriColor colorMiddle = TradfriColor.fromColorTemperature(new PercentType(50)); | ||
assertNotNull(colorMiddle); | ||
assertEquals(30138, (int) colorMiddle.xyX); | ||
assertEquals(26909, (int) colorMiddle.xyY); | ||
// warmest color temperature -> preset 3 | ||
TradfriColor colorMax = TradfriColor.fromColorTemperature(PercentType.HUNDRED); | ||
assertNotNull(colorMax); | ||
assertEquals(33137, (int) colorMax.xyX); | ||
assertEquals(27211, (int) colorMax.xyY); | ||
} | ||
|
||
@Test | ||
public void testFromColorTemperatureInbetween() { | ||
// 30 percent must be between preset 1 and 2 | ||
TradfriColor color2 = TradfriColor.fromColorTemperature(new PercentType(30)); | ||
assertNotNull(color2); | ||
assertEquals(28056, (int) color2.xyX); | ||
assertEquals(26022, (int) color2.xyY); | ||
// 70 percent must be between preset 2 and 3 | ||
TradfriColor color3 = TradfriColor.fromColorTemperature(new PercentType(70)); | ||
assertNotNull(color3); | ||
assertEquals(31338, (int) color3.xyX); | ||
assertEquals(27030, (int) color3.xyY); | ||
} | ||
|
||
@Test | ||
public void testCalculateColorTemperature() { | ||
// preset 1 -> coldest -> 0 percent | ||
PercentType preset1 = TradfriColor.calculateColorTemperature(24933, 24691); | ||
assertEquals(0, preset1.intValue()); | ||
// preset 2 -> middle -> 50 percent | ||
PercentType preset2 = TradfriColor.calculateColorTemperature(30138, 26909); | ||
assertEquals(50, preset2.intValue()); | ||
// preset 3 -> warmest -> 100 percent | ||
PercentType preset3 = TradfriColor.calculateColorTemperature(33137, 27211); | ||
assertEquals(100, preset3.intValue()); | ||
// preset 3 -> warmest -> 100 percent | ||
PercentType colder = TradfriColor.calculateColorTemperature(22222, 23333); | ||
assertEquals(0, colder.intValue()); | ||
// preset 3 -> warmest -> 100 percent | ||
PercentType temp3 = TradfriColor.calculateColorTemperature(34000, 34000); | ||
assertEquals(100, temp3.intValue()); | ||
// mixed case 1 | ||
PercentType mixed1 = TradfriColor.calculateColorTemperature(0, 1000000); | ||
assertEquals(0, mixed1.intValue()); | ||
// mixed case 1 | ||
PercentType mixed2 = TradfriColor.calculateColorTemperature(1000000, 0); | ||
assertEquals(100, mixed2.intValue()); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -71,6 +71,28 @@ | |
</config-description> | ||
</thing-type> | ||
|
||
<thing-type id="0200"> | ||
<supported-bridge-type-refs> | ||
<bridge-type-ref id="gateway"/> | ||
</supported-bridge-type-refs> | ||
|
||
<label>Color Light</label> | ||
<description>A dimmable light that supports full colors and color temperature settings.</description> | ||
|
||
<channels> | ||
<channel id="brightness" typeId="brightness"/> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The color channel already accepts all the same (PercentType) commands as the brightness channel, so a thing that has the color channel, should not have the brightness channel as well as this is redundant. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @kaikreuzer
Further we have a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Iirc when sending only the brightness value (0 - 100) to a color item it will be interpreted as brightness only. So in your example all bulbs should change their brightness. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah well I think you're right. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You remember correctly! The ColorItem takes care of this: If it gets updated with a percent type, it keeps everything else from the previous state and only adjusts the brightness. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried this, but got unexpected results.
My current code has already a special handling for PercentType on the color channel, so the functionality is OK. But the ColorItem.setState doesn't help here, I think. Looking at the HueLightHandler in comparison, there's also special handling for PercentType:
|
||
<channel id="color_temperature" typeId="color_temperature"/> | ||
<channel id="color" typeId="color"/> | ||
</channels> | ||
|
||
<config-description> | ||
<parameter name="id" type="integer" required="true"> | ||
<label>ID</label> | ||
<description>The identifier of the light on the gateway</description> | ||
</parameter> | ||
</config-description> | ||
</thing-type> | ||
|
||
<!-- note that this isn't yet supported by the code as we do not receive any data from the gateway for it --> | ||
<thing-type id="0820" listed="false"> | ||
<supported-bridge-type-refs> | ||
|
@@ -108,4 +130,11 @@ | |
<category>ColorLight</category> | ||
</channel-type> | ||
|
||
<channel-type id="color"> | ||
<item-type>Color</item-type> | ||
<label>Color</label> | ||
<description>Control the color of the light.</description> | ||
<category>ColorLight</category> | ||
</channel-type> | ||
|
||
</thing:thing-descriptions> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In case of a color lamp with adjustable color temperature and brightness the corresponding ZigBee ID should be 210 instead of 200.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The real device ID of this lamps is 200 (0x0200), please see #4251 (confirmed on hardware).
Do we take the real device ID, or the device ID that we imagine that is correct?
The whole thingType naming based on technical device IDs, that the IKEA gateway do not even expose, is anyway a bit.. hmm
But that's anoter issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When creating it this way I was hoping that IKEA would stay close to the specification, which would be the best way to figure out the capabilities of the device. This is what we ended up with in the hue binding after many 3rd party devices were supported by it. I'd guess that sooner or later IKEA will come to the same conclusion and our approach will prove to be the right choice☺️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sry didn't look into #4251. You already complained your choice. And this is another break with the ZigBee protocol caused by IKEA developers.
To be compliant I would suggest to use the same thing-type definition as we use in the Hue and other bindings. In this case it should be the device ID of what we think the bulb is capable of -> 210. If not, we should remove the color_temperature channel as well (where later one is IMHO the worse way).
btw. I didn't mentioned it before: You did a great job so far.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My personal feeling is also that 210 is the right choice, and not 200. But as the real device ID was 210, I renamed it so stick with the previous naming scheme.
I'm happy to re-rename it to 210, cause this better reflects the capabilities of the Thing.
P.S: After re-reading my previous comment, it sounded a bit offensive. That was not intentional.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean 200, I guess. ;-) Okay, we give it a try.
Oh no, everything was alright. I am fine with it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, 200... All these numbers!
I changed it now to 210 in the binding and the documentation. PR update ongoing with the other changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, my comment above actually meant that we SHOULD go for the real Zigbee type, because sooner or later other devices will appear with the 210 type - and maybe they then need a different logic to be supported (e.g. hardware instead of software color temp setting). So I was actually fine with the "200" choice.
@cweitkamp The other option would be that we think about doing "software calculation" on those (hue) as well - do you think that would be possible?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But I don't have a too strong opinion on 200 vs. 210 - if you both now agreed that 210 is the better choice, so be it. We can still revisit this once we see more devices that bring us more clarity on how the gateway handles them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, @cweitkamp has also good arguments.
I'm absolutely against removing the color_temperature channel from the new thing. See my discussion above; but replace "brightness" with "color temperature". And this can not be handled with the color channel, at least not without rules or something.