Simplify template tracking and make it easier to follow (#41030)

This commit is contained in:
J. Nick Koston 2020-10-02 07:27:39 -05:00 committed by GitHub
parent bc8a0209cb
commit ab17b4ab70
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -774,16 +774,65 @@ class _TrackTemplateResultInfo:
"""Force recalculate the template.""" """Force recalculate the template."""
self._refresh(None) self._refresh(None)
@callback def _render_template_if_ready(
def _event_triggers_template(self, template: Template, event: Event) -> bool: self,
"""Determine if a template should be re-rendered from an event.""" track_template_: TrackTemplate,
entity_id = event.data.get(ATTR_ENTITY_ID) now: datetime,
return ( event: Optional[Event],
self._info[template].filter(entity_id) ) -> Union[bool, TrackTemplateResult]:
or event.data.get("new_state") is None """Re-render the template if conditions match.
or event.data.get("old_state") is None
and self._info[template].filter_lifecycle(entity_id) Returns False if the template was not be re-rendered
)
Returns True if the template re-rendered and did not
change.
Returns TrackTemplateResult if the template re-render
generates a new result.
"""
template = track_template_.template
if event:
info = self._info[template]
if not self._rate_limit.async_has_timer(
template
) and not _event_triggers_rerender(event, info):
return False
if self._rate_limit.async_schedule_action(
template,
info.rate_limit or track_template_.rate_limit,
now,
self._refresh,
event,
):
return False
_LOGGER.debug(
"Template update %s triggered by event: %s",
template.template,
event,
)
self._rate_limit.async_triggered(template, now)
self._info[template] = template.async_render_to_info(track_template_.variables)
try:
result: Union[str, TemplateError] = self._info[template].result()
except TemplateError as ex:
result = ex
last_result = self._last_result.get(template)
# Check to see if the result has changed
if result == last_result:
return True
if isinstance(result, TemplateError) and isinstance(last_result, TemplateError):
return True
return TrackTemplateResult(template, last_result, result)
@callback @callback
def _refresh(self, event: Optional[Event]) -> None: def _refresh(self, event: Optional[Event]) -> None:
@ -792,51 +841,13 @@ class _TrackTemplateResultInfo:
now = dt_util.utcnow() now = dt_util.utcnow()
for track_template_ in self._track_templates: for track_template_ in self._track_templates:
template = track_template_.template update = self._render_template_if_ready(track_template_, now, event)
if event: if not update:
if not self._rate_limit.async_has_timer( continue
template
) and not self._event_triggers_template(template, event):
continue
if self._rate_limit.async_schedule_action(
template,
self._info[template].rate_limit or track_template_.rate_limit,
now,
self._refresh,
event,
):
continue
_LOGGER.debug(
"Template update %s triggered by event: %s",
template.template,
event,
)
self._rate_limit.async_triggered(template, now)
self._info[template] = template.async_render_to_info(
track_template_.variables
)
info_changed = True info_changed = True
if isinstance(update, TrackTemplateResult):
try: updates.append(update)
result: Union[str, TemplateError] = self._info[template].result()
except TemplateError as ex:
result = ex
last_result = self._last_result.get(template)
# Check to see if the result has changed
if result == last_result:
continue
if isinstance(result, TemplateError) and isinstance(
last_result, TemplateError
):
continue
updates.append(TrackTemplateResult(template, last_result, result))
if info_changed: if info_changed:
assert self._track_state_changes assert self._track_state_changes
@ -1348,3 +1359,20 @@ def _render_infos_to_track_states(render_infos: Iterable[RenderInfo]) -> TrackSt
return TrackStates(True, set(), set()) return TrackStates(True, set(), set())
return TrackStates(False, *_entities_domains_from_render_infos(render_infos)) return TrackStates(False, *_entities_domains_from_render_infos(render_infos))
@callback
def _event_triggers_rerender(event: Event, info: RenderInfo) -> bool:
"""Determine if a template should be re-rendered from an event."""
entity_id = event.data.get(ATTR_ENTITY_ID)
if info.filter(entity_id):
return True
if (
event.data.get("new_state") is not None
and event.data.get("old_state") is not None
):
return False
return bool(info.filter_lifecycle(entity_id))