Skip to content
This repository has been archived by the owner on May 7, 2020. It is now read-only.

[Tradfri] Support for new RGB bulbs #4251 #4271

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -81,9 +81,10 @@ public void cleanUp() {

@Test
public void correctSupportedTypes() {
assertThat(discovery.getSupportedThingTypes().size(), is(2));
assertThat(discovery.getSupportedThingTypes().size(), is(3));
assertTrue(discovery.getSupportedThingTypes().contains(TradfriBindingConstants.THING_TYPE_DIMMABLE_LIGHT));
assertTrue(discovery.getSupportedThingTypes().contains(TradfriBindingConstants.THING_TYPE_COLOR_TEMP_LIGHT));
assertTrue(discovery.getSupportedThingTypes().contains(TradfriBindingConstants.THING_TYPE_COLOR_LIGHT));
}

@Test
Expand All @@ -101,4 +102,21 @@ public void validDiscoveryResult() {
assertThat(discoveryResult.getProperties().get(DeviceConfig.ID), is(65537));
assertThat(discoveryResult.getRepresentationProperty(), is(DeviceConfig.ID));
}

@Test
public void validDiscoveryResultColorLightCWS() {
String json = "{\"9001\":\"TRADFRI bulb E27 CWS opal 600lm\",\"9002\":1505151864,\"9020\":1505433527,\"9003\":65550,\"9019\":1,\"9054\":0,\"5750\":2,\"3\":{\"0\":\"IKEA of Sweden\",\"1\":\"TRADFRI bulb E27 CWS opal 600lm\",\"2\":\"\",\"3\":\"1.3.002\",\"6\":1},\"3311\":[{\"5850\":1,\"5708\":0,\"5851\":254,\"5707\":0,\"5709\":33137,\"5710\":27211,\"5711\":0,\"5706\":\"efd275\",\"9003\":0}]}";
JsonObject data = new JsonParser().parse(json).getAsJsonObject();

discovery.onUpdate("65550", data);

assertNotNull(discoveryResult);
assertThat(discoveryResult.getFlag(), is(DiscoveryResultFlag.NEW));
assertThat(discoveryResult.getThingUID(), is(new ThingUID("tradfri:0210:1:65550")));
assertThat(discoveryResult.getThingTypeUID(), is(TradfriBindingConstants.THING_TYPE_COLOR_LIGHT));
assertThat(discoveryResult.getBridgeUID(), is(new ThingUID("tradfri:gateway:1")));
assertThat(discoveryResult.getProperties().get(DeviceConfig.ID), is(65550));
assertThat(discoveryResult.getRepresentationProperty(), is(DeviceConfig.ID));
}

}
@@ -0,0 +1,159 @@
/**
* 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(254, (int) color.rgbR);
assertEquals(2, (int) color.rgbG);
assertEquals(158, (int) color.rgbB);
assertEquals(29577, (int) color.xyX);
assertEquals(12294, (int) color.xyY);
assertEquals(254, (int) color.brightness);
assertNotNull(color.hsbType);
assertEquals(323, color.hsbType.getHue().intValue());
assertEquals(99, color.hsbType.getSaturation().intValue());
assertEquals(100, color.hsbType.getBrightness().intValue());
}

@Test
public void testFromCieKnownGood2() {
TradfriColor color = TradfriColor.fromCie(19983, 37417, 84);
assertNotNull(color);
assertEquals(30, (int) color.rgbR);
assertEquals(84, (int) color.rgbG);
assertEquals(7, (int) color.rgbB);
assertEquals(19983, (int) color.xyX);
assertEquals(37417, (int) color.xyY);
assertEquals(84, (int) color.brightness);
assertNotNull(color.hsbType);
assertEquals(102, color.hsbType.getHue().intValue());
assertEquals(89, color.hsbType.getSaturation().intValue());
assertEquals(33, color.hsbType.getBrightness().intValue());
}

@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);
assertNotNull(color.hsbType);
assertEquals(0, color.hsbType.getHue().intValue());
assertEquals(100, color.hsbType.getSaturation().intValue());
assertEquals(100, color.hsbType.getBrightness().intValue());
}

@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);
assertNotNull(color.hsbType);
assertEquals(120, color.hsbType.getHue().intValue());
assertEquals(100, color.hsbType.getSaturation().intValue());
assertEquals(100, color.hsbType.getBrightness().intValue());
// 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(254, (int) reverse.rgbG);
assertEquals(0, (int) reverse.rgbB);
assertEquals(11299, (int) reverse.xyX);
assertEquals(48941, (int) reverse.xyY);
assertEquals(254, (int) reverse.brightness);
assertNotNull(reverse.hsbType);
assertEquals(120, reverse.hsbType.getHue().intValue());
assertEquals(100, reverse.hsbType.getSaturation().intValue());
assertEquals(100, reverse.hsbType.getBrightness().intValue());
}

@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());
}

}
Expand Up @@ -9,6 +9,8 @@ thing-type.tradfri.0100.label = Dimmbare Lampe (wei
thing-type.tradfri.0100.description = Dimmbare Lampe mit fester Farbtemperatur.
thing-type.tradfri.0220.label = Farbtemperatur Lampe (wei�)
thing-type.tradfri.0220.description = Dimmbare Lampe mit einstellbarer Farbtemperatur.
thing-type.tradfri.0210.label = Farbspektrum Lampe
thing-type.tradfri.0210.description = Dimmbare Lampe mit einstellbarer Farbe und Farbtemperatur.

# thing type configuration
thing-type.config.tradfri.gateway.host.label = IP-Adresse
Expand All @@ -21,9 +23,13 @@ thing-type.config.tradfri.0100.id.label = ID der Lampe
thing-type.config.tradfri.0100.id.description = ID zur Identifikation der Lampe.
thing-type.config.tradfri.0220.id.label = ID der Lampe
thing-type.config.tradfri.0220.id.description = ID zur Identifikation der Lampe.
thing-type.config.tradfri.0210.id.label = ID der Lampe
thing-type.config.tradfri.0210.id.description = ID zur Identifikation der Lampe.

# channel types
channel-type.tradfri.brightness.label = Helligkeit
channel-type.tradfri.brightness.description = Erm�glicht die Steuerung der Helligkeit. Erm�glicht ebenfalls die Lampe ein- und auszuschalten.
channel-type.tradfri.color_temperature.label = Farbtemperatur
channel-type.tradfri.color_temperature.description = Erm�glicht die Steuerung der Farbtemperatur. Von Tageslichtwei� (0) bis Warmwei� (100).
channel-type.tradfri.color.label = Farbe
channel-type.tradfri.color.description = Erm�glicht die Steuerung der Farbe.
Expand Up @@ -71,6 +71,27 @@
</config-description>
</thing-type>

<thing-type id="0210">
<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="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>
Expand Down Expand Up @@ -108,4 +129,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>
19 changes: 15 additions & 4 deletions extensions/binding/org.eclipse.smarthome.binding.tradfri/README.md
Expand Up @@ -12,14 +12,15 @@ The thing type ids are defined according to the lighting devices defined for Zig
|--------------------------|------------------|------------|
| Dimmable Light | 0x0100 | 0100 |
| Colour Temperature Light | 0x0220 | 0220 |

| Extended Colour Light | 0x0210 | 0210 |

The following matrix lists the capabilities (channels) for each of the supported lighting device types:

| Thing type | On/Off | Brightness | Color | Color Temperature |
|-------------|:------:|:----------:|:-----:|:-----------------:|
| 0100 | X | X | | |
| 0220 | X | X | | X |
| 0210 | X | | X | X |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am noticing that this table was already incorrect - neither 0100 nor 0220 nor 0210 should have an X for On/Off... - so we could actually remove the whole column...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very good point, as there is no "onoff" channel. Should I open a new issue for this? I want to extend the documentation anyway with more examples.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could simply remove the column as part of this PR - or we first merge and you can come up with a new PR that enhances the documentation in general.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I vote for option 2 - new PR when the enhancements are done.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok!


## Thing Configuration

Expand All @@ -29,12 +30,19 @@ The devices require only a single (integer) parameter, which is their instance i

## Channels

All devices support the `brightness` channel, while the white spectrum bulbs additionally also support the `color_temperature` channel (refer to the matrix above).
The dimmable bulbs support the `brightness` channel.
The white spectrum bulbs additionally also support the `color_temperature` channel.

Full color bulbs support the `color_temperature` and `color` channels.
Brightness can be changed with the `color` channel.

Refer to the matrix above.

| Channel Type ID | Item Type | Description |
|-------------------|-----------|---------------------------------------------|
| brightness | Dimmer | The brightness of the bulb in percent |
| color_temperature | Dimmer | color temperature from 0%=cold to 100%=warm |
| color | Color | full color |

## Full Example

Expand All @@ -43,14 +51,16 @@ demo.things:
```
Bridge tradfri:gateway:mygateway [ host="192.168.0.177", code="EHPW5rIJKyXFgjH3" ] {
0100 myDimmableBulb [ id=65537 ]
0220 myColorTempBulb [ id=65538 ]
0220 myColorTempBulb [ id=65538 ]
0210 myColorBulb [ id=65539 ]
}
```

demo.items:

```
Dimmer Light { channel="tradfri:0100:mygateway:myDimmableBulb:brightness" }
Dimmer Light { channel="tradfri:0100:mygateway:myDimmableBulb:brightness" }
Color ColorLight { channel="tradfri:0210:mygateway:myColorBulb:color" }
```

demo.sitemap:
Expand All @@ -60,6 +70,7 @@ sitemap demo label="Main Menu"
{
Frame {
Slider item=Light label="Brightness [%.1f %%]"
Colorpicker item=ColorLight
}
}
```
Expand Up @@ -29,17 +29,20 @@ public class TradfriBindingConstants {

public final static ThingTypeUID THING_TYPE_DIMMABLE_LIGHT = new ThingTypeUID(BINDING_ID, "0100");
public final static ThingTypeUID THING_TYPE_COLOR_TEMP_LIGHT = new ThingTypeUID(BINDING_ID, "0220");
public final static ThingTypeUID THING_TYPE_COLOR_LIGHT = new ThingTypeUID(BINDING_ID, "0210");
public final static ThingTypeUID THING_TYPE_DIMMER = new ThingTypeUID(BINDING_ID, "0820");

public static final Set<ThingTypeUID> SUPPORTED_LIGHT_TYPES_UIDS = Collections.unmodifiableSet(
Stream.of(THING_TYPE_DIMMABLE_LIGHT, THING_TYPE_COLOR_TEMP_LIGHT).collect(Collectors.toSet()));
public static final Set<ThingTypeUID> SUPPORTED_LIGHT_TYPES_UIDS = Collections
.unmodifiableSet(Stream.of(THING_TYPE_DIMMABLE_LIGHT, THING_TYPE_COLOR_TEMP_LIGHT, THING_TYPE_COLOR_LIGHT)
.collect(Collectors.toSet()));

// Not yet used - included for future support
public static final Set<ThingTypeUID> SUPPORTED_CONTROLLER_TYPES_UIDS = Collections.singleton(THING_TYPE_DIMMER);

// List of all Channel IDs
public static final String CHANNEL_BRIGHTNESS = "brightness";
public static final String CHANNEL_COLOR_TEMPERATURE = "color_temperature";
public static final String CHANNEL_COLOR = "color";

// IPSO Objects
public static final String DEVICES = "15001";
Expand Down