1 """Provide pre-made queries on top of the recorder component."""
3 from __future__
import annotations
5 from datetime
import datetime
as dt, timedelta
6 from http
import HTTPStatus
7 from typing
import cast
9 from aiohttp
import web
10 import voluptuous
as vol
23 from .
import websocket_api
24 from .const
import DOMAIN
25 from .helpers
import entities_may_have_state_changes_after, has_states_before
27 CONF_ORDER =
"use_include_order"
31 CONFIG_SCHEMA = vol.Schema(
34 cv.deprecated(CONF_INCLUDE),
35 cv.deprecated(CONF_EXCLUDE),
36 cv.deprecated(CONF_ORDER),
37 INCLUDE_EXCLUDE_BASE_FILTER_SCHEMA.extend(
38 {vol.Optional(CONF_ORDER, default=
False): cv.boolean}
42 extra=vol.ALLOW_EXTRA,
46 async
def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
47 """Set up the history hooks."""
49 frontend.async_register_built_in_panel(hass,
"history",
"history",
"hass:chart-box")
50 websocket_api.async_setup(hass)
55 """Handle history period requests."""
57 url =
"/api/history/period"
58 name =
"api:history:view-period"
59 extra_urls = [
"/api/history/period/{datetime}"]
62 self, request: web.Request, datetime: str |
None =
None
64 """Return history over a period of time."""
68 if datetime
and (datetime_ := dt_util.parse_datetime(datetime))
is None:
69 return self.json_message(
"Invalid datetime", HTTPStatus.BAD_REQUEST)
71 if not (entity_ids_str := query.get(
"filter_entity_id"))
or not (
72 entity_ids := entity_ids_str.strip().lower().split(
",")
74 return self.json_message(
75 "filter_entity_id is missing", HTTPStatus.BAD_REQUEST
78 hass = request.app[KEY_HASS]
80 for entity_id
in entity_ids:
82 return self.json_message(
83 "Invalid filter_entity_id", HTTPStatus.BAD_REQUEST
86 now = dt_util.utcnow()
88 start_time = dt_util.as_utc(datetime_)
90 start_time = now - _ONE_DAY
95 if end_time_str := query.get(
"end_time"):
96 if end_time := dt_util.parse_datetime(end_time_str):
97 end_time = dt_util.as_utc(end_time)
99 return self.json_message(
"Invalid end_time", HTTPStatus.BAD_REQUEST)
101 end_time = start_time + _ONE_DAY
103 include_start_time_state =
"skip_initial_state" not in query
104 significant_changes_only = query.get(
"significant_changes_only",
"1") !=
"0"
106 minimal_response =
"minimal_response" in request.query
107 no_attributes =
"no_attributes" in request.query
114 or not include_start_time_state
117 hass, entity_ids, start_time, no_attributes
130 include_start_time_state,
131 significant_changes_only,
142 entity_ids: list[str],
143 include_start_time_state: bool,
144 significant_changes_only: bool,
145 minimal_response: bool,
148 """Fetch significant stats from the database as json."""
152 history.get_significant_states_with_session(
159 include_start_time_state,
160 significant_changes_only,
web.Response get(self, web.Request request, str|None datetime=None)
web.Response _sorted_significant_states_json(self, HomeAssistant hass, dt start_time, dt end_time, list[str] entity_ids, bool include_start_time_state, bool significant_changes_only, bool minimal_response, bool no_attributes)
bool has_states_before(HomeAssistant hass, dt run_time)
bool entities_may_have_state_changes_after(HomeAssistant hass, Iterable entity_ids, dt start_time, bool no_attributes)
bool async_setup(HomeAssistant hass, ConfigType config)
Recorder get_instance(HomeAssistant hass)
Generator[Session] session_scope(*HomeAssistant|None hass=None, Session|None session=None, Callable[[Exception], bool]|None exception_filter=None, bool read_only=False)
def valid_entity_id(hass)