1919 STATE_UNAVAILABLE ,
2020 STATE_UNKNOWN ,
2121)
22- from homeassistant .core import CALLBACK_TYPE , HomeAssistant
22+ from homeassistant .core import CALLBACK_TYPE , HomeAssistant , callback
2323from homeassistant .helpers import (
2424 device_registry as dr ,
2525 entity_registry as er ,
2626 issue_registry as ir ,
2727)
2828from homeassistant .helpers .entity_registry import RegistryEntry
29+ from homeassistant .helpers .event import async_call_later
2930from homeassistant .helpers .update_coordinator import DataUpdateCoordinator
3031from homeassistant .util import dt as dt_util
3132from homeassistant .util .hass_dict import HassKey
@@ -127,6 +128,7 @@ class BatteryNotesSubentryCoordinator(DataUpdateCoordinator[None]):
127128 _previous_battery_low_binary_state : bool | None = None
128129 _source_entity_name : str | None = None
129130 _outlier_filter : LowOutlierFilter | None = None
131+ _link_retry_delay : timedelta = timedelta (minutes = 2 )
130132
131133 def __init__ ( # noqa: PLR0912
132134 self ,
@@ -147,6 +149,7 @@ def __init__( # noqa: PLR0912
147149
148150 if not self ._link_to_source ():
149151 self .is_orphaned = True
152+ self ._schedule_link_retry ()
150153 return
151154
152155 self .battery_type = cast (str , self .subentry .data .get (CONF_BATTERY_TYPE , "" ))
@@ -219,7 +222,31 @@ def __init__( # noqa: PLR0912
219222 )
220223 self .last_reported = last_reported
221224
222- def _link_to_source (self ) -> bool : # noqa: PLR0912
225+ def _schedule_link_retry (self ) -> None :
226+ """Retry linking to source after startup state settles."""
227+
228+ @callback
229+ def _retry_link_to_source (_now : datetime ) -> None :
230+ if not self ._link_to_source (create_issue = True ):
231+ return
232+
233+ self .is_orphaned = False
234+ _LOGGER .debug (
235+ "%s source link restored; reloading entry to create entities" ,
236+ self .subentry .subentry_id ,
237+ )
238+ self .hass .async_create_task (
239+ self .hass .config_entries .async_reload (self .config_entry .entry_id )
240+ )
241+
242+ remove_retry = async_call_later (
243+ self .hass ,
244+ self ._link_retry_delay ,
245+ _retry_link_to_source ,
246+ )
247+ self .config_entry .async_on_unload (remove_retry )
248+
249+ def _link_to_source (self , create_issue : bool = False ) -> bool : # noqa: PLR0912
223250 """Get the source device or entity, determine name and associate our wrapped battery if available."""
224251 device_registry = dr .async_get (self .hass )
225252 entity_registry = er .async_get (self .hass )
@@ -228,23 +255,24 @@ def _link_to_source(self) -> bool: # noqa: PLR0912
228255 entity = entity_registry .async_get (self .source_entity_id )
229256
230257 if not entity :
231- ir .async_create_issue (
232- self .hass ,
233- DOMAIN ,
234- f"missing_device_{ self .subentry .subentry_id } " ,
235- data = {
236- "entry_id" : self .config_entry .entry_id ,
237- "subentry_id" : self .subentry .subentry_id ,
238- "device_id" : self .device_id ,
239- "source_entity_id" : self .source_entity_id ,
240- },
241- is_fixable = True ,
242- severity = ir .IssueSeverity .WARNING ,
243- translation_key = "missing_device" ,
244- translation_placeholders = {
245- "name" : self .subentry .title ,
246- },
247- )
258+ if create_issue :
259+ ir .async_create_issue (
260+ self .hass ,
261+ DOMAIN ,
262+ f"missing_device_{ self .subentry .subentry_id } " ,
263+ data = {
264+ "entry_id" : self .config_entry .entry_id ,
265+ "subentry_id" : self .subentry .subentry_id ,
266+ "device_id" : self .device_id ,
267+ "source_entity_id" : self .source_entity_id ,
268+ },
269+ is_fixable = True ,
270+ severity = ir .IssueSeverity .WARNING ,
271+ translation_key = "missing_device" ,
272+ translation_placeholders = {
273+ "name" : self .subentry .title ,
274+ },
275+ )
248276
249277 _LOGGER .warning (
250278 "%s is orphaned, unable to find entity %s" ,
@@ -314,23 +342,24 @@ def _link_to_source(self) -> bool: # noqa: PLR0912
314342 else :
315343 self .device_name = self .subentry .title
316344
317- ir .async_create_issue (
318- self .hass ,
319- DOMAIN ,
320- f"missing_device_{ self .subentry .subentry_id } " ,
321- data = {
322- "entry_id" : self .config_entry .entry_id ,
323- "subentry_id" : self .subentry .subentry_id ,
324- "device_id" : self .device_id ,
325- "source_entity_id" : self .source_entity_id ,
326- },
327- is_fixable = True ,
328- severity = ir .IssueSeverity .WARNING ,
329- translation_key = "missing_device" ,
330- translation_placeholders = {
331- "name" : self .subentry .title ,
332- },
333- )
345+ if create_issue :
346+ ir .async_create_issue (
347+ self .hass ,
348+ DOMAIN ,
349+ f"missing_device_{ self .subentry .subentry_id } " ,
350+ data = {
351+ "entry_id" : self .config_entry .entry_id ,
352+ "subentry_id" : self .subentry .subentry_id ,
353+ "device_id" : self .device_id ,
354+ "source_entity_id" : self .source_entity_id ,
355+ },
356+ is_fixable = True ,
357+ severity = ir .IssueSeverity .WARNING ,
358+ translation_key = "missing_device" ,
359+ translation_placeholders = {
360+ "name" : self .subentry .title ,
361+ },
362+ )
334363
335364 _LOGGER .warning (
336365 "%s is orphaned, unable to find device %s" ,
0 commit comments