def _template_changed_listener(event: Event, updates: List[TrackTemplateResult]) -> None: """Check if condition is correct and run action.""" track_result = updates.pop() template = track_result.template last_result = track_result.last_result result = track_result.result if isinstance(result, TemplateError): _LOGGER.error( "Error while processing template: %s", template.template, exc_info=result, ) return if (not isinstance(last_result, TemplateError) and result_as_boolean(last_result) or not result_as_boolean(result)): return hass.async_run_job( action, event.data.get("entity_id"), event.data.get("old_state"), event.data.get("new_state"), )
def _update_state(self, result): super()._update_state(result) if self._delay_cancel: self._delay_cancel() self._delay_cancel = None state = None if isinstance( result, TemplateError) else result_as_boolean(result) if state == self._state: return # state without delay if (state is None or (state and not self._delay_on) or (not state and not self._delay_off)): self._state = state return @callback def _set_state(_): """Set state of template binary sensor.""" self._state = state self.async_write_ha_state() delay = (self._delay_on if state else self._delay_off).seconds # state with delay. Cancelled if template result changes. self._delay_cancel = async_call_later(self.hass, delay, _set_state)
def _async_template_result_changed(event, updates): track_template_result = updates.pop() template = track_template_result.template result = track_template_result.result entity = event and event.data.get("entity_id") if isinstance(result, TemplateError): _LOGGER.error( "TemplateError('%s') " "while processing template '%s' " "in entity '%s'", result, template, self.entity_id, ) should_trigger = False else: should_trigger = result_as_boolean(result) for obs in self.observations_by_template[template]: if should_trigger: obs_entry = {"entity_id": entity, **obs} else: obs_entry = None self.current_observations[obs["id"]] = obs_entry if event: self.async_set_context(event.context) self._recalculate_and_write_state()
def template_listener(event, updates): """Listen for state changes and calls action.""" nonlocal delay_cancel result = updates.pop().result if delay_cancel: # pylint: disable=not-callable delay_cancel() delay_cancel = None if not result_as_boolean(result): return entity_id = event.data.get("entity_id") from_s = event.data.get("old_state") to_s = event.data.get("new_state") @callback def call_action(*_): """Call action with right context.""" hass.async_run_hass_job( job, { "trigger": { "platform": "template", "entity_id": entity_id, "from_state": from_s, "to_state": to_s, "for": time_delta if not time_delta else period, "description": f"{entity_id} via template", } }, (to_s.context if to_s else None), ) if not time_delta: call_action() return variables = { "trigger": { "platform": platform_type, "entity_id": entity_id, "from_state": from_s, "to_state": to_s, } } try: period = cv.positive_time_period( template.render_complex(time_delta, variables)) except (exceptions.TemplateError, vol.Invalid) as ex: _LOGGER.error("Error rendering '%s' for template: %s", automation_info["name"], ex) return delay_cancel = async_call_later(hass, period.seconds, call_action)
def _async_power_changed(self, event, updates): """Update current power.""" result = updates.pop().result if isinstance(result, TemplateError): _LOGGER.warning('Unable to update power from template: %s', result) else: self._current_hvac_mode = self._last_hvac_mode if result_as_boolean( result) else HVAC_MODE_OFF self.schedule_update_ha_state()
def _handle_coordinator_update(self) -> None: """Handle update of the data.""" self._process_data() if self._delay_cancel: self._delay_cancel() self._delay_cancel = None if self._auto_off_cancel: self._auto_off_cancel() self._auto_off_cancel = None self._auto_off_time = None if not self.available: self.async_write_ha_state() return raw = self._rendered.get(CONF_STATE) state = template.result_as_boolean(raw) key = CONF_DELAY_ON if state else CONF_DELAY_OFF delay = self._rendered.get(key) or self._config.get(key) # state without delay. None means rendering failed. if self._state == state or state is None or delay is None: self._set_state(state) return if not isinstance(delay, timedelta): try: delay = cv.positive_time_period(delay) except vol.Invalid as err: logging.getLogger(__name__).warning( "Error rendering %s template: %s", key, err ) return # state with delay. Cancelled if new trigger received self._delay_cancel = async_call_later( self.hass, delay.total_seconds(), partial(self._set_state, state) )
class PlexMediaSearchResult: """Represents results from a Plex media media_content_id search. Results are used by media_player.play_media implementations. """ def __init__(self, media, params=None) -> None: """Initialize the result.""" self.media = media self._params = params or {} @property def offset(self) -> int: """Provide the appropriate offset based on payload contents.""" if offset := self._params.get("offset", 0): return offset * 1000 resume = self._params.get("resume", False) if isinstance(resume, str): resume = result_as_boolean(resume) if resume: return self.media.viewOffset return 0
def _update_available(self, result): if isinstance(result, TemplateError): self._available = True return self._available = result_as_boolean(result)
def template_listener(event, updates): """Listen for state changes and calls action.""" nonlocal delay_cancel, armed result = updates.pop().result if isinstance(result, exceptions.TemplateError): _LOGGER.warning( "Error evaluating 'template' trigger for '%s': %s", automation_info["name"], result, ) return if delay_cancel: # pylint: disable=not-callable delay_cancel() delay_cancel = None if not result_as_boolean(result): armed = True return # Only fire when previously armed. if not armed: return # Fire! armed = False entity_id = event and event.data.get("entity_id") from_s = event and event.data.get("old_state") to_s = event and event.data.get("new_state") if entity_id is not None: description = f"{entity_id} via template" else: description = "time change or manual update via template" template_variables = { "platform": platform_type, "entity_id": entity_id, "from_state": from_s, "to_state": to_s, } trigger_variables = { "for": time_delta, "description": description, "id": trigger_id, } @callback def call_action(*_): """Call action with right context.""" nonlocal trigger_variables hass.async_run_hass_job( job, {"trigger": { **template_variables, **trigger_variables }}, (to_s.context if to_s else None), ) if not time_delta: call_action() return try: period = cv.positive_time_period( template.render_complex(time_delta, {"trigger": template_variables})) except (exceptions.TemplateError, vol.Invalid) as ex: _LOGGER.error("Error rendering '%s' for template: %s", automation_info["name"], ex) return trigger_variables["for"] = period delay_cancel = async_call_later(hass, period.seconds, call_action)
async def async_attach_trigger(hass, config, action, automation_info, *, platform_type="template"): """Listen for state changes based on configuration.""" trigger_id = automation_info.get("trigger_id") if automation_info else None value_template = config.get(CONF_VALUE_TEMPLATE) value_template.hass = hass time_delta = config.get(CONF_FOR) template.attach(hass, time_delta) delay_cancel = None job = HassJob(action) armed = False # Arm at setup if the template is already false. try: if not result_as_boolean( value_template.async_render(automation_info["variables"])): armed = True except exceptions.TemplateError as ex: _LOGGER.warning( "Error initializing 'template' trigger for '%s': %s", automation_info["name"], ex, ) @callback def template_listener(event, updates): """Listen for state changes and calls action.""" nonlocal delay_cancel, armed result = updates.pop().result if isinstance(result, exceptions.TemplateError): _LOGGER.warning( "Error evaluating 'template' trigger for '%s': %s", automation_info["name"], result, ) return if delay_cancel: # pylint: disable=not-callable delay_cancel() delay_cancel = None if not result_as_boolean(result): armed = True return # Only fire when previously armed. if not armed: return # Fire! armed = False entity_id = event and event.data.get("entity_id") from_s = event and event.data.get("old_state") to_s = event and event.data.get("new_state") if entity_id is not None: description = f"{entity_id} via template" else: description = "time change or manual update via template" template_variables = { "platform": platform_type, "entity_id": entity_id, "from_state": from_s, "to_state": to_s, } trigger_variables = { "for": time_delta, "description": description, "id": trigger_id, } @callback def call_action(*_): """Call action with right context.""" nonlocal trigger_variables hass.async_run_hass_job( job, {"trigger": { **template_variables, **trigger_variables }}, (to_s.context if to_s else None), ) if not time_delta: call_action() return try: period = cv.positive_time_period( template.render_complex(time_delta, {"trigger": template_variables})) except (exceptions.TemplateError, vol.Invalid) as ex: _LOGGER.error("Error rendering '%s' for template: %s", automation_info["name"], ex) return trigger_variables["for"] = period delay_cancel = async_call_later(hass, period.seconds, call_action) info = async_track_template_result( hass, [TrackTemplate(value_template, automation_info["variables"])], template_listener, ) unsub = info.async_remove @callback def async_remove(): """Remove state listeners async.""" unsub() if delay_cancel: # pylint: disable=not-callable delay_cancel() return async_remove
def shuffle(self) -> bool: """Return value of shuffle parameter.""" shuffle = self._params.get("shuffle", False) if isinstance(shuffle, str): shuffle = result_as_boolean(shuffle) return shuffle