def _async_migrate_unique_id(hass: HomeAssistant, platform_config: list[ConfigType]) -> None: """Change unique_ids used in 2021.4 to include target_temperature GA.""" entity_registry = er.async_get(hass) for entity_config in platform_config: # normalize group address strings - ga_temperature_state was the old uid ga_temperature_state = parse_device_group_address( entity_config[ClimateSchema.CONF_TEMPERATURE_ADDRESS][0]) old_uid = str(ga_temperature_state) entity_id = entity_registry.async_get_entity_id( "climate", DOMAIN, old_uid) if entity_id is None: continue ga_target_temperature_state = parse_device_group_address(entity_config[ ClimateSchema.CONF_TARGET_TEMPERATURE_STATE_ADDRESS][0]) target_temp = entity_config.get( ClimateSchema.CONF_TARGET_TEMPERATURE_ADDRESS) ga_target_temperature = (parse_device_group_address(target_temp[0]) if target_temp is not None else None) setpoint_shift = entity_config.get( ClimateSchema.CONF_SETPOINT_SHIFT_ADDRESS) ga_setpoint_shift = (parse_device_group_address(setpoint_shift[0]) if setpoint_shift is not None else None) new_uid = (f"{ga_temperature_state}_" f"{ga_target_temperature_state}_" f"{ga_target_temperature}_" f"{ga_setpoint_shift}") entity_registry.async_update_entity(entity_id, new_unique_id=new_uid)
def _async_migrate_unique_id(hass: HomeAssistant, discovery_info: DiscoveryInfoType | None) -> None: """Change unique_ids used in 2021.4 to include position_target GA.""" entity_registry = er.async_get(hass) if not discovery_info or not discovery_info["platform_config"]: return platform_config = discovery_info["platform_config"] for entity_config in platform_config: # normalize group address strings - ga_updown was the old uid but is optional updown_addresses = entity_config.get( CoverSchema.CONF_MOVE_LONG_ADDRESS) if updown_addresses is None: continue ga_updown = parse_device_group_address(updown_addresses[0]) old_uid = str(ga_updown) entity_id = entity_registry.async_get_entity_id( "cover", DOMAIN, old_uid) if entity_id is None: continue position_target_addresses = entity_config.get( CoverSchema.CONF_POSITION_ADDRESS) ga_position_target = (parse_device_group_address( position_target_addresses[0]) if position_target_addresses is not None else None) new_uid = f"{ga_updown}_{ga_position_target}" entity_registry.async_update_entity(entity_id, new_unique_id=new_uid)
def ga_validator(value: Any) -> str | int: """Validate that value is parsable as GroupAddress or InternalGroupAddress.""" if isinstance(value, (str, int)): try: parse_device_group_address(value) return value except CouldNotParseAddress: pass raise vol.Invalid( f"value '{value}' is not a valid KNX group address '<main>/<middle>/<sub>', '<main>/<sub>' or '<free>' (eg.'1/2/3', '9/234', '123'), nor xknx internal address 'i-<string>'." )
async def service_send_to_knx_bus(self, call: ServiceCall) -> None: """Service for sending an arbitrary KNX message to the KNX bus.""" attr_address = call.data[KNX_ADDRESS] attr_payload = call.data[SERVICE_KNX_ATTR_PAYLOAD] attr_type = call.data.get(SERVICE_KNX_ATTR_TYPE) attr_response = call.data[SERVICE_KNX_ATTR_RESPONSE] payload: DPTBinary | DPTArray if attr_type is not None: transcoder = DPTBase.parse_transcoder(attr_type) if transcoder is None: raise ValueError( f"Invalid type for knx.send service: {attr_type}") payload = DPTArray(transcoder.to_knx(attr_payload)) elif isinstance(attr_payload, int): payload = DPTBinary(attr_payload) else: payload = DPTArray(attr_payload) for address in attr_address: telegram = Telegram( destination_address=parse_device_group_address(address), payload=GroupValueResponse(payload) if attr_response else GroupValueWrite(payload), ) await self.xknx.telegrams.put(telegram)
async def service_read_to_knx_bus(self, call: ServiceCall) -> None: """Service for sending a GroupValueRead telegram to the KNX bus.""" for address in call.data[KNX_ADDRESS]: telegram = Telegram( destination_address=parse_device_group_address(address), payload=GroupValueRead(), ) await self.xknx.telegrams.put(telegram)
def unpack_group_addresses( addresses: GroupAddressesType | None, ) -> DeviceGroupAddress | None: """Parse group addresses and assign passive addresses when given.""" if addresses is None: return None if not isinstance(addresses, list): return parse_device_group_address(addresses) active, *passive = map(parse_device_group_address, addresses) self.passive_group_addresses.extend(passive) # type: ignore return active
def _async_migrate_unique_id(hass: HomeAssistant, platform_config: list[ConfigType]) -> None: """Change unique_ids used in 2021.4 to exchange individual color switch address for brightness address.""" entity_registry = er.async_get(hass) for entity_config in platform_config: individual_colors_config = entity_config.get( LightSchema.CONF_INDIVIDUAL_COLORS) if individual_colors_config is None: continue try: ga_red_switch = individual_colors_config[ LightSchema.CONF_RED][KNX_ADDRESS][0] ga_green_switch = individual_colors_config[ LightSchema.CONF_GREEN][KNX_ADDRESS][0] ga_blue_switch = individual_colors_config[ LightSchema.CONF_BLUE][KNX_ADDRESS][0] except KeyError: continue # normalize group address strings ga_red_switch = parse_device_group_address(ga_red_switch) ga_green_switch = parse_device_group_address(ga_green_switch) ga_blue_switch = parse_device_group_address(ga_blue_switch) # white config is optional so it has to be checked for `None` extra white_config = individual_colors_config.get(LightSchema.CONF_WHITE) white_switch = (white_config.get(KNX_ADDRESS) if white_config is not None else None) ga_white_switch = (parse_device_group_address(white_switch[0]) if white_switch is not None else None) old_uid = (f"{ga_red_switch}_" f"{ga_green_switch}_" f"{ga_blue_switch}_" f"{ga_white_switch}") entity_id = entity_registry.async_get_entity_id( "light", DOMAIN, old_uid) if entity_id is None: continue ga_red_brightness = parse_device_group_address( individual_colors_config[LightSchema.CONF_RED][ LightSchema.CONF_BRIGHTNESS_ADDRESS][0]) ga_green_brightness = parse_device_group_address( individual_colors_config[LightSchema.CONF_GREEN][ LightSchema.CONF_BRIGHTNESS_ADDRESS][0]) ga_blue_brightness = parse_device_group_address( individual_colors_config[LightSchema.CONF_BLUE][ LightSchema.CONF_BRIGHTNESS_ADDRESS][0]) new_uid = f"{ga_red_brightness}_{ga_green_brightness}_{ga_blue_brightness}" entity_registry.async_update_entity(entity_id, new_unique_id=new_uid)
def test_parse_invalid(self, address_test): """Test if the function raises CouldNotParseAddress on invalid values.""" with pytest.raises(CouldNotParseAddress): parse_device_group_address(address_test)
def test_parse_internal_group_address(self, address_test): """Test if the function returns InternalGroupAddress objects.""" assert isinstance(parse_device_group_address(address_test), InternalGroupAddress)