22
33from __future__ import annotations
44
5+ import asyncio
56import logging
67import time
78from datetime import UTC , datetime
@@ -349,24 +350,31 @@ async def _sync_automation_entities(self, entities: list[Any]) -> dict[str, int]
349350 scripts = [e for e in entities if e .domain == "script" ]
350351 scenes = [e for e in entities if e .domain == "scene" ]
351352
352- # --- Automations ---
353+ # --- Automations (concurrent config fetches) ---
353354 seen_automation_ids : set [str ] = set ()
355+ _FETCH_CONCURRENCY = 10
356+ sem = asyncio .Semaphore (_FETCH_CONCURRENCY )
357+
358+ async def _fetch_config (aid : str ) -> tuple [str , dict [str , Any ] | None ]:
359+ async with sem :
360+ try :
361+ return aid , await self .ha .get_automation_config (aid )
362+ except (httpx .HTTPError , TimeoutError , ConnectionError ) as exc :
363+ logger .warning ("Failed to fetch config for automation %s: %s" , aid , exc )
364+ return aid , None
365+
366+ automation_meta : list [tuple [Any , str ]] = []
354367 for entity in automations :
355368 attrs = entity .attributes or {}
356369 ha_automation_id = attrs .get ("id" , entity .entity_id .split ("." , 1 )[- 1 ])
357370 seen_automation_ids .add (ha_automation_id )
371+ automation_meta .append ((entity , ha_automation_id ))
358372
359- # Fetch full config from HA (trigger/condition/action)
360- config : dict [str , Any ] | None = None
361- try :
362- config = await self .ha .get_automation_config (ha_automation_id )
363- except (httpx .HTTPError , TimeoutError , ConnectionError ) as exc :
364- logger .warning (
365- "Failed to fetch config for automation %s: %s" ,
366- ha_automation_id ,
367- exc ,
368- )
373+ config_results = await asyncio .gather (* (_fetch_config (aid ) for _ , aid in automation_meta ))
374+ config_map : dict [str , dict [str , Any ] | None ] = dict (config_results )
369375
376+ for entity , ha_automation_id in automation_meta :
377+ attrs = entity .attributes or {}
370378 await self .automation_repo .upsert (
371379 {
372380 "ha_automation_id" : ha_automation_id ,
@@ -375,7 +383,7 @@ async def _sync_automation_entities(self, entities: list[Any]) -> dict[str, int]
375383 "state" : entity .state or "off" ,
376384 "mode" : attrs .get ("mode" , "single" ),
377385 "last_triggered" : attrs .get ("last_triggered" ),
378- "config" : config ,
386+ "config" : config_map . get ( ha_automation_id ) ,
379387 }
380388 )
381389 stats ["automations_synced" ] += 1
@@ -385,28 +393,31 @@ async def _sync_automation_entities(self, entities: list[Any]) -> dict[str, int]
385393 for stale_id in existing_automation_ids - seen_automation_ids :
386394 await self .automation_repo .delete (stale_id )
387395
388- # --- Scripts ---
396+ # --- Scripts (concurrent config fetches) ---
389397 seen_script_ids : set [str ] = set ()
398+
399+ async def _fetch_script_config (sid : str ) -> tuple [str , dict [str , Any ] | None ]:
400+ async with sem :
401+ try :
402+ return sid , await self .ha .get_script_config (sid )
403+ except (httpx .HTTPError , TimeoutError , ConnectionError ) as exc :
404+ logger .warning ("Failed to fetch config for script %s: %s" , sid , exc )
405+ return sid , None
406+
407+ script_meta : list [tuple [Any , str ]] = []
390408 for entity in scripts :
391- attrs = entity .attributes or {}
392409 seen_script_ids .add (entity .entity_id )
393-
394- # Fetch full config from HA (sequence/fields)
395410 script_id = entity .entity_id .split ("." , 1 )[- 1 ]
396- sequence : list [Any ] | None = None
397- fields : dict [str , Any ] | None = None
398- try :
399- script_config = await self .ha .get_script_config (script_id )
400- if script_config :
401- sequence = script_config .get ("sequence" )
402- fields = script_config .get ("fields" )
403- except (httpx .HTTPError , TimeoutError , ConnectionError ) as exc :
404- logger .warning (
405- "Failed to fetch config for script %s: %s" ,
406- script_id ,
407- exc ,
408- )
411+ script_meta .append ((entity , script_id ))
412+
413+ script_results = await asyncio .gather (
414+ * (_fetch_script_config (sid ) for _ , sid in script_meta )
415+ )
416+ script_config_map : dict [str , dict [str , Any ] | None ] = dict (script_results )
409417
418+ for entity , script_id in script_meta :
419+ attrs = entity .attributes or {}
420+ sc = script_config_map .get (script_id )
410421 await self .script_repo .upsert (
411422 {
412423 "entity_id" : entity .entity_id ,
@@ -415,8 +426,8 @@ async def _sync_automation_entities(self, entities: list[Any]) -> dict[str, int]
415426 "mode" : attrs .get ("mode" , "single" ),
416427 "icon" : attrs .get ("icon" ),
417428 "last_triggered" : attrs .get ("last_triggered" ),
418- "sequence" : sequence ,
419- "fields" : fields ,
429+ "sequence" : sc . get ( " sequence" ) if sc else None ,
430+ "fields" : sc . get ( " fields" ) if sc else None ,
420431 }
421432 )
422433 stats ["scripts_synced" ] += 1
0 commit comments