예제 #1
0
 def test_set(self):
     """Test setting value."""
     xknx = XKNX()
     remote_value = RemoteValueColorRGBW(
         xknx, group_address=GroupAddress("1/2/3"))
     self.loop.run_until_complete(remote_value.set((100, 101, 102, 103)))
     self.assertEqual(xknx.telegrams.qsize(), 1)
     telegram = xknx.telegrams.get_nowait()
     self.assertEqual(
         telegram,
         Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(
                 DPTArray((0x64, 0x65, 0x66, 0x67, 0x00, 0x0F))),
         ),
     )
     self.loop.run_until_complete(remote_value.set((100, 101, 104, 105)))
     self.assertEqual(xknx.telegrams.qsize(), 1)
     telegram = xknx.telegrams.get_nowait()
     self.assertEqual(
         telegram,
         Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(
                 DPTArray((0x64, 0x65, 0x68, 0x69, 0x00, 0x0F))),
         ),
     )
예제 #2
0
 def test_process(self):
     """Test process telegram."""
     xknx = XKNX(loop=self.loop)
     remote_value = RemoteValueColorRGBW(xknx, group_address=GroupAddress("1/2/3"))
     telegram = Telegram(
         group_address=GroupAddress("1/2/3"),
         payload=DPTArray((0x64, 0x65, 0x66, 0x67, 0x00, 0x0F)),
     )
     self.loop.run_until_complete(remote_value.process(telegram))
     self.assertEqual(remote_value.value, [100, 101, 102, 103])
예제 #3
0
    async def test_to_process_error(self):
        """Test process errornous telegram."""
        xknx = XKNX()
        remote_value = RemoteValueColorRGBW(xknx, group_address=GroupAddress("1/2/3"))

        telegram = Telegram(
            destination_address=GroupAddress("1/2/3"),
            payload=GroupValueWrite(DPTBinary(1)),
        )
        assert await remote_value.process(telegram) is False

        telegram = Telegram(
            destination_address=GroupAddress("1/2/3"),
            payload=GroupValueWrite(DPTArray((0x64, 0x65, 0x66))),
        )
        assert await remote_value.process(telegram) is False

        telegram = Telegram(
            destination_address=GroupAddress("1/2/3"),
            payload=GroupValueWrite(
                DPTArray((0x00, 0x00, 0x0F, 0x64, 0x65, 0x66, 0x67))
            ),
        )
        assert await remote_value.process(telegram) is False

        assert remote_value.value is None
예제 #4
0
 def test_from_knx(self):
     """Test from_knx function with normal operation."""
     xknx = XKNX()
     remote_value = RemoteValueColorRGBW(xknx)
     self.assertEqual(
         remote_value.from_knx(
             DPTArray((0x64, 0x65, 0x66, 0x7F, 0x00, 0x00))),
         [0, 0, 0, 0],
     )
     self.assertEqual(
         remote_value.from_knx(
             DPTArray((0x64, 0x65, 0x66, 0x7F, 0x00, 0x0F))),
         [100, 101, 102, 127],
     )
     self.assertEqual(
         remote_value.from_knx(
             DPTArray((0x64, 0x65, 0x66, 0x7F, 0x00, 0x00))),
         [100, 101, 102, 127],
     )
     self.assertEqual(
         remote_value.from_knx(
             DPTArray((0xFF, 0x65, 0x66, 0xFF, 0x00, 0x09))),
         [255, 101, 102, 255],
     )
     self.assertEqual(
         remote_value.from_knx(
             DPTArray((0x64, 0x65, 0x66, 0x7F, 0x00, 0x01))),
         [255, 101, 102, 127],
     )
예제 #5
0
 async def test_process(self):
     """Test process telegram."""
     xknx = XKNX()
     remote_value = RemoteValueColorRGBW(xknx, group_address=GroupAddress("1/2/3"))
     telegram = Telegram(
         destination_address=GroupAddress("1/2/3"),
         payload=GroupValueWrite(DPTArray((0x64, 0x65, 0x66, 0x67, 0x00, 0x0F))),
     )
     await remote_value.process(telegram)
     assert remote_value.value == (100, 101, 102, 103)
예제 #6
0
 def test_to_knx(self):
     """Test to_knx function with normal operation."""
     xknx = XKNX()
     remote_value = RemoteValueColorRGBW(xknx)
     input_list = [100, 101, 102, 127]
     input_tuple = (100, 101, 102, 127)
     expected = DPTArray((0x64, 0x65, 0x66, 0x7F, 0x00, 0x0F))
     self.assertEqual(remote_value.to_knx(input_tuple), expected)
     self.assertEqual(remote_value.to_knx(input_list), expected)
     self.assertEqual(remote_value.to_knx(input_tuple + (15, )), expected)
     self.assertEqual(remote_value.to_knx(input_list + [15]), expected)
     self.assertEqual(remote_value.to_knx(input_tuple + (0, 15)), expected)
     self.assertEqual(remote_value.to_knx(input_list + [0, 15]), expected)
예제 #7
0
 def test_set(self):
     """Test setting value."""
     xknx = XKNX(loop=self.loop)
     remote_value = RemoteValueColorRGBW(
         xknx, group_address=GroupAddress("1/2/3"))
     self.loop.run_until_complete(
         asyncio.Task(remote_value.set((100, 101, 102, 103))))
     self.assertEqual(xknx.telegrams.qsize(), 1)
     telegram = xknx.telegrams.get_nowait()
     self.assertEqual(
         telegram,
         Telegram(GroupAddress('1/2/3'),
                  payload=DPTArray((0x64, 0x65, 0x66, 0x67, 0x00, 0x0f))))
     self.loop.run_until_complete(
         asyncio.Task(remote_value.set((100, 101, 104, 105))))
     self.assertEqual(xknx.telegrams.qsize(), 1)
     telegram = xknx.telegrams.get_nowait()
     self.assertEqual(
         telegram,
         Telegram(GroupAddress('1/2/3'),
                  payload=DPTArray((0x64, 0x65, 0x68, 0x69, 0x00, 0x0f))))
예제 #8
0
 def test_to_process_error(self):
     """Test process errornous telegram."""
     xknx = XKNX(loop=self.loop)
     remote_value = RemoteValueColorRGBW(
         xknx, group_address=GroupAddress("1/2/3"))
     with self.assertRaises(CouldNotParseTelegram):
         telegram = Telegram(group_address=GroupAddress("1/2/3"),
                             payload=DPTBinary(1))
         self.loop.run_until_complete(
             asyncio.Task(remote_value.process(telegram)))
     with self.assertRaises(CouldNotParseTelegram):
         telegram = Telegram(group_address=GroupAddress("1/2/3"),
                             payload=DPTArray((0x64, 0x65, 0x66)))
         self.loop.run_until_complete(
             asyncio.Task(remote_value.process(telegram)))
     with self.assertRaises(CouldNotParseTelegram):
         telegram = Telegram(group_address=GroupAddress("1/2/3"),
                             payload=DPTArray((0x00, 0x00, 0x0f, 0x64, 0x65,
                                               0x66, 0x67)))
         self.loop.run_until_complete(
             asyncio.Task(remote_value.process(telegram)))
예제 #9
0
 async def test_set(self):
     """Test setting value."""
     xknx = XKNX()
     remote_value = RemoteValueColorRGBW(xknx, group_address=GroupAddress("1/2/3"))
     await remote_value.set((100, 101, 102, 103))
     assert xknx.telegrams.qsize() == 1
     telegram = xknx.telegrams.get_nowait()
     assert telegram == Telegram(
         destination_address=GroupAddress("1/2/3"),
         payload=GroupValueWrite(DPTArray((0x64, 0x65, 0x66, 0x67, 0x00, 0x0F))),
     )
     await remote_value.set((100, 101, 104, 105))
     assert xknx.telegrams.qsize() == 1
     telegram = xknx.telegrams.get_nowait()
     assert telegram == Telegram(
         destination_address=GroupAddress("1/2/3"),
         payload=GroupValueWrite(DPTArray((0x64, 0x65, 0x68, 0x69, 0x00, 0x0F))),
     )
예제 #10
0
 def test_from_knx(self):
     """Test from_knx function with normal operation."""
     xknx = XKNX()
     remote_value = RemoteValueColorRGBW(xknx)
     assert remote_value.from_knx(
         DPTArray((0x64, 0x65, 0x66, 0x7F, 0x00, 0x00))) == (0, 0, 0, 0)
     assert remote_value.from_knx(
         DPTArray(
             (0x64, 0x65, 0x66, 0x7F, 0x00, 0x0F))) == (100, 101, 102, 127)
     assert remote_value.from_knx(
         DPTArray(
             (0x64, 0x65, 0x66, 0x7F, 0x00, 0x00))) == (100, 101, 102, 127)
     assert remote_value.from_knx(
         DPTArray(
             (0xFF, 0x65, 0x66, 0xFF, 0x00, 0x09))) == (255, 101, 102, 255)
     assert remote_value.from_knx(
         DPTArray(
             (0x64, 0x65, 0x66, 0x7F, 0x00, 0x01))) == (255, 101, 102, 127)
예제 #11
0
async def main():
    """Connect to KNX/IP bus and set different colors."""
    xknx = XKNX()
    await xknx.start()

    rgbw = RemoteValueColorRGBW(
        xknx,
        group_address="1/1/40",
        group_address_state="1/1/41",
        device_name="RGBWLight",
    )

    await rgbw.set([255, 255, 255, 0, 15])  # cold-white
    await asyncio.sleep(1)
    await rgbw.set([0, 0, 0, 255, 15])  # warm-white
    await asyncio.sleep(1)
    await rgbw.set([0, 0, 0, 0, 15])  # off
    await asyncio.sleep(1)

    await rgbw.set([255, 0, 0, 0])  # red
    await asyncio.sleep(1)
    await rgbw.set([0, 255, 0, 0])  # green
    await asyncio.sleep(1)
    await rgbw.set([0, 0, 255, 0])  # blue
    await asyncio.sleep(1)
    await rgbw.set([0, 0, 0, 0, 15])  # off
    await asyncio.sleep(1)

    await rgbw.set([255, 255, 0, 0, 15])
    await asyncio.sleep(1)
    await rgbw.set([0, 255, 255, 0, 15])
    await asyncio.sleep(1)
    await rgbw.set([255, 0, 255, 0, 15])
    await asyncio.sleep(1)
    await rgbw.set([0, 0, 0, 0, 15])  # off
    await asyncio.sleep(1)

    await xknx.stop()
예제 #12
0
 async def test_to_process_error(self):
     """Test process errornous telegram."""
     xknx = XKNX()
     remote_value = RemoteValueColorRGBW(
         xknx, group_address=GroupAddress("1/2/3"))
     with pytest.raises(CouldNotParseTelegram):
         telegram = Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTBinary(1)),
         )
         await remote_value.process(telegram)
     with pytest.raises(CouldNotParseTelegram):
         telegram = Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray((0x64, 0x65, 0x66))),
         )
         await remote_value.process(telegram)
     with pytest.raises(CouldNotParseTelegram):
         telegram = Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(
                 DPTArray((0x00, 0x00, 0x0F, 0x64, 0x65, 0x66, 0x67))),
         )
         await remote_value.process(telegram)
예제 #13
0
 def test_to_knx_error(self):
     """Test to_knx function with wrong parametern."""
     xknx = XKNX()
     remote_value = RemoteValueColorRGBW(xknx)
     with self.assertRaises(ConversionError):
         remote_value.to_knx((101, 102, 103))
     with self.assertRaises(ConversionError):
         remote_value.to_knx((0, 0, 15, 101, 102, 103, 104))
     with self.assertRaises(ConversionError):
         remote_value.to_knx((256, 101, 102, 103))
     with self.assertRaises(ConversionError):
         remote_value.to_knx((100, 256, 102, 103))
     with self.assertRaises(ConversionError):
         remote_value.to_knx((100, 101, 256, 103))
     with self.assertRaises(ConversionError):
         remote_value.to_knx((100, 101, 102, 256))
     with self.assertRaises(ConversionError):
         remote_value.to_knx((100, -101, 102, 103))
     with self.assertRaises(ConversionError):
         remote_value.to_knx(("100", 101, 102, 103))
     with self.assertRaises(ConversionError):
         remote_value.to_knx("100, 101, 102, 103")
예제 #14
0
    def __init__(
        self,
        xknx: XKNX,
        name: str,
        group_address_switch: GroupAddressesType | None = None,
        group_address_switch_state: GroupAddressesType | None = None,
        group_address_brightness: GroupAddressesType | None = None,
        group_address_brightness_state: GroupAddressesType | None = None,
        group_address_color: GroupAddressesType | None = None,
        group_address_color_state: GroupAddressesType | None = None,
        group_address_rgbw: GroupAddressesType | None = None,
        group_address_rgbw_state: GroupAddressesType | None = None,
        group_address_tunable_white: GroupAddressesType | None = None,
        group_address_tunable_white_state: GroupAddressesType | None = None,
        group_address_color_temperature: GroupAddressesType | None = None,
        group_address_color_temperature_state: GroupAddressesType
        | None = None,
        group_address_switch_red: GroupAddressesType | None = None,
        group_address_switch_red_state: GroupAddressesType | None = None,
        group_address_brightness_red: GroupAddressesType | None = None,
        group_address_brightness_red_state: GroupAddressesType | None = None,
        group_address_switch_green: GroupAddressesType | None = None,
        group_address_switch_green_state: GroupAddressesType | None = None,
        group_address_brightness_green: GroupAddressesType | None = None,
        group_address_brightness_green_state: GroupAddressesType | None = None,
        group_address_switch_blue: GroupAddressesType | None = None,
        group_address_switch_blue_state: GroupAddressesType | None = None,
        group_address_brightness_blue: GroupAddressesType | None = None,
        group_address_brightness_blue_state: GroupAddressesType | None = None,
        group_address_switch_white: GroupAddressesType | None = None,
        group_address_switch_white_state: GroupAddressesType | None = None,
        group_address_brightness_white: GroupAddressesType | None = None,
        group_address_brightness_white_state: GroupAddressesType | None = None,
        min_kelvin: int | None = None,
        max_kelvin: int | None = None,
        device_updated_cb: DeviceCallbackType | None = None,
    ):
        """Initialize Light class."""
        super().__init__(xknx, name, device_updated_cb)

        self.switch = RemoteValueSwitch(
            xknx,
            group_address_switch,
            group_address_switch_state,
            device_name=self.name,
            feature_name="State",
            after_update_cb=self.after_update,
        )

        self.brightness = RemoteValueScaling(
            xknx,
            group_address_brightness,
            group_address_brightness_state,
            device_name=self.name,
            feature_name="Brightness",
            after_update_cb=self.after_update,
            range_from=0,
            range_to=255,
        )

        self.color = RemoteValueColorRGB(
            xknx,
            group_address_color,
            group_address_color_state,
            device_name=self.name,
            after_update_cb=self.after_update,
        )

        self.rgbw = RemoteValueColorRGBW(
            xknx,
            group_address_rgbw,
            group_address_rgbw_state,
            device_name=self.name,
            after_update_cb=self.after_update,
        )

        self.tunable_white = RemoteValueScaling(
            xknx,
            group_address_tunable_white,
            group_address_tunable_white_state,
            device_name=self.name,
            feature_name="Tunable white",
            after_update_cb=self.after_update,
            range_from=0,
            range_to=255,
        )

        self.color_temperature = RemoteValueDpt2ByteUnsigned(
            xknx,
            group_address_color_temperature,
            group_address_color_temperature_state,
            device_name=self.name,
            feature_name="Color temperature",
            after_update_cb=self.after_update,
        )

        self.red = _SwitchAndBrightness(
            xknx,
            self.name,
            "red",
            group_address_switch_red,
            group_address_switch_red_state,
            group_address_brightness_red,
            group_address_brightness_red_state,
            self.after_update,
        )

        self.green = _SwitchAndBrightness(
            xknx,
            self.name,
            "green",
            group_address_switch_green,
            group_address_switch_green_state,
            group_address_brightness_green,
            group_address_brightness_green_state,
            self.after_update,
        )

        self.blue = _SwitchAndBrightness(
            xknx,
            self.name,
            "blue",
            group_address_switch_blue,
            group_address_switch_blue_state,
            group_address_brightness_blue,
            group_address_brightness_blue_state,
            self.after_update,
        )

        self.white = _SwitchAndBrightness(
            xknx,
            self.name,
            "white",
            group_address_switch_white,
            group_address_switch_white_state,
            group_address_brightness_white,
            group_address_brightness_white_state,
            self.after_update,
        )

        self.min_kelvin = min_kelvin
        self.max_kelvin = max_kelvin
예제 #15
0
    def __init__(self,
                 xknx,
                 name,
                 group_address_switch=None,
                 group_address_switch_state=None,
                 group_address_brightness=None,
                 group_address_brightness_state=None,
                 group_address_color=None,
                 group_address_color_state=None,
                 group_address_rgbw=None,
                 group_address_rgbw_state=None,
                 group_address_tunable_white=None,
                 group_address_tunable_white_state=None,
                 group_address_color_temperature=None,
                 group_address_color_temperature_state=None,
                 min_kelvin=None,
                 max_kelvin=None,
                 device_updated_cb=None):
        """Initialize Light class."""
        # pylint: disable=too-many-arguments
        super().__init__(xknx, name, device_updated_cb)

        self.switch = RemoteValueSwitch(xknx,
                                        group_address_switch,
                                        group_address_switch_state,
                                        device_name=self.name,
                                        feature_name="State",
                                        after_update_cb=self.after_update)

        self.brightness = RemoteValueScaling(xknx,
                                             group_address_brightness,
                                             group_address_brightness_state,
                                             device_name=self.name,
                                             feature_name="Brightness",
                                             after_update_cb=self.after_update,
                                             range_from=0,
                                             range_to=255)

        self.color = RemoteValueColorRGB(xknx,
                                         group_address_color,
                                         group_address_color_state,
                                         device_name=self.name,
                                         after_update_cb=self.after_update)

        self.rgbw = RemoteValueColorRGBW(xknx,
                                         group_address_rgbw,
                                         group_address_rgbw_state,
                                         device_name=self.name,
                                         after_update_cb=self.after_update)

        self.tunable_white = RemoteValueScaling(
            xknx,
            group_address_tunable_white,
            group_address_tunable_white_state,
            device_name=self.name,
            feature_name="Tunable white",
            after_update_cb=self.after_update,
            range_from=0,
            range_to=255)

        self.color_temperature = RemoteValueDpt2ByteUnsigned(
            xknx,
            group_address_color_temperature,
            group_address_color_temperature_state,
            device_name=self.name,
            feature_name="Color temperature",
            after_update_cb=self.after_update)

        self.min_kelvin = min_kelvin
        self.max_kelvin = max_kelvin
예제 #16
0
class Light(Device):
    """Class for managing a light."""

    # pylint: disable=too-many-locals
    DEFAULT_MIN_KELVIN = 2700  # 370 mireds
    DEFAULT_MAX_KELVIN = 6000  # 166 mireds

    def __init__(self,
                 xknx,
                 name,
                 group_address_switch=None,
                 group_address_switch_state=None,
                 group_address_brightness=None,
                 group_address_brightness_state=None,
                 group_address_color=None,
                 group_address_color_state=None,
                 group_address_rgbw=None,
                 group_address_rgbw_state=None,
                 group_address_tunable_white=None,
                 group_address_tunable_white_state=None,
                 group_address_color_temperature=None,
                 group_address_color_temperature_state=None,
                 min_kelvin=None,
                 max_kelvin=None,
                 device_updated_cb=None):
        """Initialize Light class."""
        # pylint: disable=too-many-arguments
        super().__init__(xknx, name, device_updated_cb)

        self.switch = RemoteValueSwitch(xknx,
                                        group_address_switch,
                                        group_address_switch_state,
                                        device_name=self.name,
                                        feature_name="State",
                                        after_update_cb=self.after_update)

        self.brightness = RemoteValueScaling(xknx,
                                             group_address_brightness,
                                             group_address_brightness_state,
                                             device_name=self.name,
                                             feature_name="Brightness",
                                             after_update_cb=self.after_update,
                                             range_from=0,
                                             range_to=255)

        self.color = RemoteValueColorRGB(xknx,
                                         group_address_color,
                                         group_address_color_state,
                                         device_name=self.name,
                                         after_update_cb=self.after_update)

        self.rgbw = RemoteValueColorRGBW(xknx,
                                         group_address_rgbw,
                                         group_address_rgbw_state,
                                         device_name=self.name,
                                         after_update_cb=self.after_update)

        self.tunable_white = RemoteValueScaling(
            xknx,
            group_address_tunable_white,
            group_address_tunable_white_state,
            device_name=self.name,
            feature_name="Tunable white",
            after_update_cb=self.after_update,
            range_from=0,
            range_to=255)

        self.color_temperature = RemoteValueDpt2ByteUnsigned(
            xknx,
            group_address_color_temperature,
            group_address_color_temperature_state,
            device_name=self.name,
            feature_name="Color temperature",
            after_update_cb=self.after_update)

        self.min_kelvin = min_kelvin
        self.max_kelvin = max_kelvin

    def _iter_remote_values(self):
        """Iterate the devices RemoteValue classes."""
        yield from (self.switch, self.brightness, self.color, self.rgbw,
                    self.tunable_white, self.color_temperature)

    @property
    def supports_brightness(self):
        """Return if light supports brightness."""
        return self.brightness.initialized

    @property
    def supports_color(self):
        """Return if light supports color."""
        return self.color.initialized

    @property
    def supports_rgbw(self):
        """Return if light supports RGBW."""
        return self.rgbw.initialized

    @property
    def supports_tunable_white(self):
        """Return if light supports tunable white / relative color temperature."""
        return self.tunable_white.initialized

    @property
    def supports_color_temperature(self):
        """Return if light supports absolute color temperature."""
        return self.color_temperature.initialized

    @classmethod
    def from_config(cls, xknx, name, config):
        """Initialize object from configuration structure."""
        group_address_switch = \
            config.get('group_address_switch')
        group_address_switch_state = \
            config.get('group_address_switch_state')
        group_address_brightness = \
            config.get('group_address_brightness')
        group_address_brightness_state = \
            config.get('group_address_brightness_state')
        group_address_color = \
            config.get('group_address_color')
        group_address_color_state = \
            config.get('group_address_color_state')
        group_address_rgbw = \
            config.get('group_address_rgbw')
        group_address_rgbw_state = \
            config.get('group_address_rgbw_state')
        group_address_tunable_white = \
            config.get('group_address_tunable_white')
        group_address_tunable_white_state = \
            config.get('group_address_tunable_white_state')
        group_address_color_temperature = \
            config.get('group_address_color_temperature')
        group_address_color_temperature_state = \
            config.get('group_address_color_temperature_state')
        min_kelvin = \
            config.get('min_kelvin', Light.DEFAULT_MIN_KELVIN)
        max_kelvin = \
            config.get('max_kelvin', Light.DEFAULT_MAX_KELVIN)

        return cls(
            xknx,
            name,
            group_address_switch=group_address_switch,
            group_address_switch_state=group_address_switch_state,
            group_address_brightness=group_address_brightness,
            group_address_brightness_state=group_address_brightness_state,
            group_address_color=group_address_color,
            group_address_color_state=group_address_color_state,
            group_address_rgbw=group_address_rgbw,
            group_address_rgbw_state=group_address_rgbw_state,
            group_address_tunable_white=group_address_tunable_white,
            group_address_tunable_white_state=group_address_tunable_white_state,
            group_address_color_temperature=group_address_color_temperature,
            group_address_color_temperature_state=
            group_address_color_temperature_state,
            min_kelvin=min_kelvin,
            max_kelvin=max_kelvin)

    def __str__(self):
        """Return object as readable string."""
        str_brightness = '' if not self.supports_brightness else \
            ' brightness="{0}"'.format(
                self.brightness.group_addr_str())

        str_color = '' if not self.supports_color else \
            ' color="{0}"'.format(
                self.color.group_addr_str())

        str_rgbw = '' if not self.supports_rgbw else \
            ' rgbw="{0}"'.format(
                self.rgbw.group_addr_str())

        str_tunable_white = '' if not self.supports_tunable_white else \
            ' tunable white="{0}"'.format(
                self.tunable_white.group_addr_str())

        str_color_temperature = '' if not self.supports_color_temperature else \
            ' color temperature="{0}"'.format(
                self.color_temperature.group_addr_str())

        return '<Light name="{0}" ' \
            'switch="{1}"{2}{3}{4}{5}{6} />' \
            .format(
                self.name,
                self.switch.group_addr_str(),
                str_brightness,
                str_color,
                str_rgbw,
                str_tunable_white,
                str_color_temperature)

    @property
    def state(self):
        """Return the current switch state of the device."""
        # None will return False
        return bool(self.switch.value)

    async def set_on(self):
        """Switch light on."""
        await self.switch.on()

    async def set_off(self):
        """Switch light off."""
        await self.switch.off()

    @property
    def current_brightness(self):
        """Return current brightness of light."""
        return self.brightness.value

    async def set_brightness(self, brightness):
        """Set brightness of light."""
        if not self.supports_brightness:
            self.xknx.logger.warning("Dimming not supported for device %s",
                                     self.get_name())
            return
        await self.brightness.set(brightness)

    @property
    def current_color(self):
        """
        Return current color of light.

        If the device supports RGBW, get the current RGB+White values instead.
        """
        if self.supports_rgbw:
            if not self.rgbw.value:
                return None, None
            return self.rgbw.value[:3], self.rgbw.value[3]
        return self.color.value, None

    async def set_color(self, color, white=None):
        """
        Set color of a light device.

        If also the white value is given and the device supports RGBW,
        set all four values.
        """
        if white is not None:
            if self.supports_rgbw:
                await self.rgbw.set(list(color) + [white])
                return
            self.xknx.logger.warning("RGBW not supported for device %s",
                                     self.get_name())
        else:
            if self.supports_color:
                await self.color.set(color)
                return
            self.xknx.logger.warning("Colors not supported for device %s",
                                     self.get_name())

    @property
    def current_tunable_white(self):
        """Return current relative color temperature of light."""
        return self.tunable_white.value

    async def set_tunable_white(self, tunable_white):
        """Set relative color temperature of light."""
        if not self.supports_tunable_white:
            self.xknx.logger.warning(
                "Tunable white not supported for device %s", self.get_name())
            return
        await self.tunable_white.set(tunable_white)

    @property
    def current_color_temperature(self):
        """Return current absolute color temperature of light."""
        return self.color_temperature.value

    async def set_color_temperature(self, color_temperature):
        """Set absolute color temperature of light."""
        if not self.supports_color_temperature:
            self.xknx.logger.warning(
                "Absolute Color Temperature not supported for device %s",
                self.get_name())
            return
        await self.color_temperature.set(color_temperature)

    async def do(self, action):
        """Execute 'do' commands."""
        if action == "on":
            await self.set_on()
        elif action == "off":
            await self.set_off()
        elif action.startswith("brightness:"):
            await self.set_brightness(int(action[11:]))
        elif action.startswith("tunable_white:"):
            await self.set_tunable_white(int(action[14:]))
        elif action.startswith("color_temperature:"):
            await self.set_color_temperature(int(action[18:]))
        else:
            self.xknx.logger.warning(
                "Could not understand action %s for device %s", action,
                self.get_name())

    async def process_group_write(self, telegram):
        """Process incoming GROUP WRITE telegram."""
        for remote_value in self._iter_remote_values():
            await remote_value.process(telegram)

    def __eq__(self, other):
        """Equal operator."""
        return self.__dict__ == other.__dict__