22
33from __future__ import annotations
44
5- import asyncio
5+ from asyncio import sleep as asyncio_sleep
66from collections import defaultdict
77from collections .abc import Callable
88from dataclasses import dataclass
2929 HomeConnectApiError ,
3030 HomeConnectError ,
3131 HomeConnectRequestError ,
32+ TooManyRequestsError ,
3233 UnauthorizedError ,
3334)
3435from aiohomeconnect .model .program import EnumerateProgram , ProgramDefinitionOption
3536from propcache .api import cached_property
3637
3738from homeassistant .config_entries import ConfigEntry
3839from homeassistant .core import CALLBACK_TYPE , HomeAssistant , callback
39- from homeassistant .exceptions import ConfigEntryAuthFailed
40+ from homeassistant .exceptions import ConfigEntryAuthFailed , ConfigEntryNotReady
4041from homeassistant .helpers import device_registry as dr
4142from homeassistant .helpers .update_coordinator import DataUpdateCoordinator , UpdateFailed
4243
43- from .const import APPLIANCES_WITH_PROGRAMS , DOMAIN
44+ from .const import API_DEFAULT_RETRY_AFTER , APPLIANCES_WITH_PROGRAMS , DOMAIN
4445from .utils import get_dict_from_home_connect_error
4546
4647_LOGGER = logging .getLogger (__name__ )
@@ -154,7 +155,7 @@ def start_event_listener(self) -> None:
154155 f"home_connect-events_listener_task-{ self .config_entry .entry_id } " ,
155156 )
156157
157- async def _event_listener (self ) -> None :
158+ async def _event_listener (self ) -> None : # noqa: C901
158159 """Match event with listener for event type."""
159160 retry_time = 10
160161 while True :
@@ -269,7 +270,7 @@ async def _event_listener(self) -> None:
269270 type (error ).__name__ ,
270271 retry_time ,
271272 )
272- await asyncio . sleep (retry_time )
273+ await asyncio_sleep (retry_time )
273274 retry_time = min (retry_time * 2 , 3600 )
274275 except HomeConnectApiError as error :
275276 _LOGGER .error ("Error while listening for events: %s" , error )
@@ -278,6 +279,13 @@ async def _event_listener(self) -> None:
278279 )
279280 break
280281
282+ # Trigger to delete the possible depaired device entities
283+ # from known_entities variable at common.py
284+ for listener , context in self ._special_listeners .values ():
285+ assert isinstance (context , tuple )
286+ if EventKey .BSH_COMMON_APPLIANCE_DEPAIRED in context :
287+ listener ()
288+
281289 @callback
282290 def _call_event_listener (self , event_message : EventMessage ) -> None :
283291 """Call listener for event."""
@@ -295,6 +303,42 @@ def _call_all_event_listeners_for_appliance(self, ha_id: str) -> None:
295303
296304 async def _async_update_data (self ) -> dict [str , HomeConnectApplianceData ]:
297305 """Fetch data from Home Connect."""
306+ await self ._async_setup ()
307+
308+ for appliance_data in self .data .values ():
309+ appliance = appliance_data .info
310+ ha_id = appliance .ha_id
311+ while True :
312+ try :
313+ self .data [ha_id ] = await self ._get_appliance_data (
314+ appliance , self .data .get (ha_id )
315+ )
316+ except TooManyRequestsError as err :
317+ _LOGGER .debug (
318+ "Rate limit exceeded on initial fetch: %s" ,
319+ err ,
320+ )
321+ await asyncio_sleep (err .retry_after or API_DEFAULT_RETRY_AFTER )
322+ else :
323+ break
324+
325+ for listener , context in self ._special_listeners .values ():
326+ assert isinstance (context , tuple )
327+ if EventKey .BSH_COMMON_APPLIANCE_PAIRED in context :
328+ listener ()
329+
330+ return self .data
331+
332+ async def async_setup (self ) -> None :
333+ """Set up the devices."""
334+ try :
335+ await self ._async_setup ()
336+ except UpdateFailed as err :
337+ raise ConfigEntryNotReady from err
338+
339+ async def _async_setup (self ) -> None :
340+ """Set up the devices."""
341+ old_appliances = set (self .data .keys ())
298342 try :
299343 appliances = await self .client .get_home_appliances ()
300344 except UnauthorizedError as error :
@@ -312,12 +356,38 @@ async def _async_update_data(self) -> dict[str, HomeConnectApplianceData]:
312356 translation_placeholders = get_dict_from_home_connect_error (error ),
313357 ) from error
314358
315- return {
316- appliance .ha_id : await self ._get_appliance_data (
317- appliance , self .data .get (appliance .ha_id )
359+ for appliance in appliances .homeappliances :
360+ self .device_registry .async_get_or_create (
361+ config_entry_id = self .config_entry .entry_id ,
362+ identifiers = {(DOMAIN , appliance .ha_id )},
363+ manufacturer = appliance .brand ,
364+ name = appliance .name ,
365+ model = appliance .vib ,
318366 )
319- for appliance in appliances .homeappliances
320- }
367+ if appliance .ha_id not in self .data :
368+ self .data [appliance .ha_id ] = HomeConnectApplianceData (
369+ commands = set (),
370+ events = {},
371+ info = appliance ,
372+ options = {},
373+ programs = [],
374+ settings = {},
375+ status = {},
376+ )
377+ else :
378+ self .data [appliance .ha_id ].info .connected = appliance .connected
379+ old_appliances .remove (appliance .ha_id )
380+
381+ for ha_id in old_appliances :
382+ self .data .pop (ha_id , None )
383+ device = self .device_registry .async_get_device (
384+ identifiers = {(DOMAIN , ha_id )}
385+ )
386+ if device :
387+ self .device_registry .async_update_device (
388+ device_id = device .id ,
389+ remove_config_entry_id = self .config_entry .entry_id ,
390+ )
321391
322392 async def _get_appliance_data (
323393 self ,
@@ -339,6 +409,8 @@ async def _get_appliance_data(
339409 await self .client .get_settings (appliance .ha_id )
340410 ).settings
341411 }
412+ except TooManyRequestsError :
413+ raise
342414 except HomeConnectError as error :
343415 _LOGGER .debug (
344416 "Error fetching settings for %s: %s" ,
@@ -353,6 +425,8 @@ async def _get_appliance_data(
353425 status .key : status
354426 for status in (await self .client .get_status (appliance .ha_id )).status
355427 }
428+ except TooManyRequestsError :
429+ raise
356430 except HomeConnectError as error :
357431 _LOGGER .debug (
358432 "Error fetching status for %s: %s" ,
@@ -369,6 +443,8 @@ async def _get_appliance_data(
369443 if appliance .type in APPLIANCES_WITH_PROGRAMS :
370444 try :
371445 all_programs = await self .client .get_all_programs (appliance .ha_id )
446+ except TooManyRequestsError :
447+ raise
372448 except HomeConnectError as error :
373449 _LOGGER .debug (
374450 "Error fetching programs for %s: %s" ,
@@ -427,6 +503,8 @@ async def _get_appliance_data(
427503 await self .client .get_available_commands (appliance .ha_id )
428504 ).commands
429505 }
506+ except TooManyRequestsError :
507+ raise
430508 except HomeConnectError :
431509 commands = set ()
432510
@@ -461,6 +539,8 @@ async def get_options_definitions(
461539 ).options
462540 or []
463541 }
542+ except TooManyRequestsError :
543+ raise
464544 except HomeConnectError as error :
465545 _LOGGER .debug (
466546 "Error fetching options for %s: %s" ,
0 commit comments