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,39 +774,40 @@ class _TrackTemplateResultInfo:
"""Force recalculate the template."""
self._refresh(None)
@callback
def _event_triggers_template(self, template: Template, event: Event) -> bool:
"""Determine if a template should be re-rendered from an event."""
entity_id = event.data.get(ATTR_ENTITY_ID)
return (
self._info[template].filter(entity_id)
or event.data.get("new_state") is None
or event.data.get("old_state") is None
and self._info[template].filter_lifecycle(entity_id)
)
def _render_template_if_ready(
self,
track_template_: TrackTemplate,
now: datetime,
event: Optional[Event],
) -> Union[bool, TrackTemplateResult]:
"""Re-render the template if conditions match.
@callback
def _refresh(self, event: Optional[Event]) -> None:
updates = []
info_changed = False
now = dt_util.utcnow()
Returns False if the template was not be re-rendered
for track_template_ in self._track_templates:
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 self._event_triggers_template(template, event):
continue
) and not _event_triggers_rerender(event, info):
return False
if self._rate_limit.async_schedule_action(
template,
self._info[template].rate_limit or track_template_.rate_limit,
info.rate_limit or track_template_.rate_limit,
now,
self._refresh,
event,
):
continue
return False
_LOGGER.debug(
"Template update %s triggered by event: %s",
@ -815,10 +816,7 @@ class _TrackTemplateResultInfo:
)
self._rate_limit.async_triggered(template, now)
self._info[template] = template.async_render_to_info(
track_template_.variables
)
info_changed = True
self._info[template] = template.async_render_to_info(track_template_.variables)
try:
result: Union[str, TemplateError] = self._info[template].result()
@ -829,14 +827,27 @@ class _TrackTemplateResultInfo:
# 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
def _refresh(self, event: Optional[Event]) -> None:
updates = []
info_changed = False
now = dt_util.utcnow()
for track_template_ in self._track_templates:
update = self._render_template_if_ready(track_template_, now, event)
if not update:
continue
if isinstance(result, TemplateError) and isinstance(
last_result, TemplateError
):
continue
updates.append(TrackTemplateResult(template, last_result, result))
info_changed = True
if isinstance(update, TrackTemplateResult):
updates.append(update)
if info_changed:
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(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))