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))), ), )
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])
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
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], )
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)
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)
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))))
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)))
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))), )
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)
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()
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)
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")
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
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
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__