1 """Google Report State implementation."""
3 from __future__
import annotations
5 from collections
import deque
7 from typing
import TYPE_CHECKING, Any
14 EventStateChangedData,
22 from .const
import DOMAIN
23 from .error
import SmartHomeError
24 from .helpers
import (
27 async_get_google_entity_if_supported_cached,
32 INITIAL_REPORT_DELAY = 60
35 REPORT_STATE_WINDOW = 1
37 _LOGGER = logging.getLogger(__name__)
42 hass: HomeAssistant, google_config: AbstractConfig
44 """Enable state and notification reporting."""
46 unsub_pending: CALLBACK_TYPE |
None =
None
47 pending: deque[dict[str, Any]] = deque([{}])
49 async
def report_states(now=None):
50 """Report the states."""
52 nonlocal unsub_pending
57 while len(pending) > 1:
58 await google_config.async_report_state_all(
59 {
"devices": {
"states": pending.popleft()}}
65 hass, REPORT_STATE_WINDOW, report_states_job
70 report_states_job =
HassJob(report_states)
73 def _async_entity_state_filter(data: EventStateChangedData) -> bool:
76 and (new_state := data[
"new_state"])
77 and google_config.should_expose(new_state)
79 hass, google_config, new_state
83 async
def _async_entity_state_listener(event: Event[EventStateChangedData]) ->
None:
84 """Handle state changes."""
85 nonlocal unsub_pending, checker
87 new_state = data[
"new_state"]
89 assert new_state
is not None
91 hass, google_config, new_state
94 assert entity
is not None
101 (old_state := data[
"old_state"])
102 and old_state.state != new_state.state
103 and (notifications := entity.notifications_serialize())
is not None
105 event_id = uuid4().hex
107 "devices": {
"notifications": {entity.state.entity_id: notifications}}
110 "Sending event notification for entity %s",
111 entity.state.entity_id,
113 result = await google_config.async_sync_notification_all(event_id, payload)
116 "Unable to send notification with result code: %s, check log for more"
121 changed_entity = data[
"entity_id"]
123 entity_data = entity.query_serialize()
124 except SmartHomeError
as err:
125 _LOGGER.debug(
"Not reporting state for %s: %s", changed_entity, err.code)
128 assert checker
is not None
129 if not checker.async_is_significant_change(new_state, extra_arg=entity_data):
132 _LOGGER.debug(
"Scheduling report state for %s: %s", changed_entity, entity_data)
136 if changed_entity
in pending[-1]:
139 pending[-1][changed_entity] = entity_data
141 if unsub_pending
is None:
143 hass, REPORT_STATE_WINDOW, report_states_job
147 def extra_significant_check(
156 """Check if the serialized data has changed."""
157 return old_extra_arg != new_extra_arg
159 async
def initial_report(_now):
160 """Report initially all states."""
161 nonlocal unsub, checker
164 checker = await
create_checker(hass, DOMAIN, extra_significant_check)
167 if not entity.should_expose():
171 entity_data = entity.query_serialize()
172 except SmartHomeError:
177 if not checker.async_is_significant_change(
178 entity.state, extra_arg=entity_data
182 entities[entity.entity_id] = entity_data
187 await google_config.async_report_state_all({
"devices": {
"states": entities}})
189 unsub = hass.bus.async_listen(
191 _async_entity_state_listener,
192 event_filter=_async_entity_state_filter,
196 hass, INITIAL_REPORT_DELAY,
HassJob(initial_report, cancel_on_shutdown=
True)
list[AlexaEntity] async_get_entities(HomeAssistant hass, AbstractConfig config)
GoogleEntity|None async_get_google_entity_if_supported_cached(HomeAssistant hass, AbstractConfig config, State state)
CALLBACK_TYPE async_enable_report_state(HomeAssistant hass, AbstractConfig google_config)
CALLBACK_TYPE async_call_later(HomeAssistant hass, float|timedelta delay, HassJob[[datetime], Coroutine[Any, Any, None]|None]|Callable[[datetime], Coroutine[Any, Any, None]|None] action)
SignificantlyChangedChecker create_checker(HomeAssistant hass, str _domain, ExtraCheckTypeFunc|None extra_significant_check=None)