Home Assistant Unofficial Reference 2024.12.1
recorder.py
Go to the documentation of this file.
1 """Helpers to check recorder."""
2 
3 from __future__ import annotations
4 
5 import asyncio
6 from collections.abc import Callable, Generator
7 from contextlib import contextmanager
8 from dataclasses import dataclass, field
9 import functools
10 import logging
11 from typing import TYPE_CHECKING, Any
12 
13 from homeassistant.core import HomeAssistant, callback
14 from homeassistant.util.hass_dict import HassKey
15 
16 if TYPE_CHECKING:
17  from sqlalchemy.orm.session import Session
18 
19  from homeassistant.components.recorder import Recorder
20 
21 _LOGGER = logging.getLogger(__name__)
22 
23 DOMAIN: HassKey[RecorderData] = HassKey("recorder")
24 DATA_INSTANCE: HassKey[Recorder] = HassKey("recorder_instance")
25 
26 
27 @dataclass(slots=True)
29  """Recorder data stored in hass.data."""
30 
31  recorder_platforms: dict[str, Any] = field(default_factory=dict)
32  db_connected: asyncio.Future[bool] = field(default_factory=asyncio.Future)
33 
34 
35 @callback
36 def async_migration_in_progress(hass: HomeAssistant) -> bool:
37  """Check to see if a recorder migration is in progress."""
38  # pylint: disable-next=import-outside-toplevel
39  from homeassistant.components import recorder
40 
41  return recorder.util.async_migration_in_progress(hass)
42 
43 
44 @callback
45 def async_migration_is_live(hass: HomeAssistant) -> bool:
46  """Check to see if a recorder migration is live."""
47  # pylint: disable-next=import-outside-toplevel
48  from homeassistant.components import recorder
49 
50  return recorder.util.async_migration_is_live(hass)
51 
52 
53 @callback
54 def async_initialize_recorder(hass: HomeAssistant) -> None:
55  """Initialize recorder data."""
56  # pylint: disable-next=import-outside-toplevel
58 
59  hass.data[DOMAIN] = RecorderData()
60  async_setup(hass)
61 
62 
63 async def async_wait_recorder(hass: HomeAssistant) -> bool:
64  """Wait for recorder to initialize and return connection status.
65 
66  Returns False immediately if the recorder is not enabled.
67  """
68  if DOMAIN not in hass.data:
69  return False
70  return await hass.data[DOMAIN].db_connected
71 
72 
73 @functools.lru_cache(maxsize=1)
74 def get_instance(hass: HomeAssistant) -> Recorder:
75  """Get the recorder instance."""
76  return hass.data[DATA_INSTANCE]
77 
78 
79 @contextmanager
81  *,
82  hass: HomeAssistant | None = None,
83  session: Session | None = None,
84  exception_filter: Callable[[Exception], bool] | None = None,
85  read_only: bool = False,
86 ) -> Generator[Session]:
87  """Provide a transactional scope around a series of operations.
88 
89  read_only is used to indicate that the session is only used for reading
90  data and that no commit is required. It does not prevent the session
91  from writing and is not a security measure.
92  """
93  if session is None and hass is not None:
94  session = get_instance(hass).get_session()
95 
96  if session is None:
97  raise RuntimeError("Session required")
98 
99  need_rollback = False
100  try:
101  yield session
102  if not read_only and session.get_transaction():
103  need_rollback = True
104  session.commit()
105  except Exception as err:
106  _LOGGER.exception("Error executing query")
107  if need_rollback:
108  session.rollback()
109  if not exception_filter or not exception_filter(err):
110  raise
111  finally:
112  session.close()
bool async_setup(HomeAssistant hass, ConfigType config)
Definition: __init__.py:86
Recorder get_instance(HomeAssistant hass)
Definition: recorder.py:74
bool async_migration_is_live(HomeAssistant hass)
Definition: recorder.py:45
None async_initialize_recorder(HomeAssistant hass)
Definition: recorder.py:54
bool async_wait_recorder(HomeAssistant hass)
Definition: recorder.py:63
Generator[Session] session_scope(*HomeAssistant|None hass=None, Session|None session=None, Callable[[Exception], bool]|None exception_filter=None, bool read_only=False)
Definition: recorder.py:86
bool async_migration_in_progress(HomeAssistant hass)
Definition: recorder.py:36