I’m new to the inner python world of HA integrations and I’m perplexed about how this error should be solved: alexa_media calls hass.bus.async_fire from a thread other than the event loop
sensor.py
has been throwing the error and I’ve figured out it’s when an echo alarm is dismissed/snoozed and I’m not sure if the code should be decorated with @callback so it runs in the event loop
or if self.hass.bus.async_fire
should be changed to self.hass.bus.fire
and left to run in the executor.
Event loop using @callback and hass.bus.async_fire:
def _process_raw_notifications(self):
self._all = (
list(map(self._fix_alarm_date_time, self._n_dict.items()))
if self._n_dict
else []
)
self._all = list(map(self._update_recurring_alarm, self._all))
self._all = sorted(self._all, key=lambda x: x[1][self._sensor_property])
self._prior_value = self._next if self._active else None
self._active = (
list(filter(lambda x: x[1]["status"] in ("ON", "SNOOZED"), self._all))
if self._all
else []
)
self._next = self._active[0][1] if self._active else None
alarm = next(
(alarm[1] for alarm in self._all if alarm[1].get("id") == self._amz_id),
None,
)
if alarm_just_dismissed(alarm, self._status, self._version):
self._dismissed = dt.now().isoformat()
self._attr_native_value = self._process_state(self._next)
self._status = self._next.get("status", "OFF") if self._next else "OFF"
self._version = self._next.get("version", "0") if self._next else None
self._amz_id = self._next.get("id") if self._next else None
if self._attr_native_value is None
if self._attr_native_value is None or self._next != self._prior_value:
# cancel any event triggers
if self._tracker:
_LOGGER.debug(
"%s: Cancelling old event",
self,
)
self._tracker()
if self._attr_native_value is not None and self._status != "SNOOZED":
_LOGGER.debug(
"%s: Scheduling event in %s",
self,
dt.as_utc(self._attr_native_value) - dt.utcnow(),
)
self._tracker = async_track_point_in_utc_time(
self.hass,
self._trigger_event, < = = = = =
dt.as_utc(self._attr_native_value),
)
@callback <<<<<<<<<<<
def _trigger_event(self, time_date) -> None:
_LOGGER.debug(
"%s:Firing %s at %s",
self,
"alexa_media_notification_event",
dt.as_local(time_date),
)
self.hass.bus.async_fire( < = = = = =
"alexa_media_notification_event",
event_data={
"email": hide_email(self._account),
"device": {"name": self.name, "entity_id": self.entity_id},
"event": self._active[0],
},
)
Executor with hass.bus.fire:
def _process_raw_notifications(self):
self._all = (
list(map(self._fix_alarm_date_time, self._n_dict.items()))
if self._n_dict
else []
)
self._all = list(map(self._update_recurring_alarm, self._all))
self._all = sorted(self._all, key=lambda x: x[1][self._sensor_property])
self._prior_value = self._next if self._active else None
self._active = (
list(filter(lambda x: x[1]["status"] in ("ON", "SNOOZED"), self._all))
if self._all
else []
)
self._next = self._active[0][1] if self._active else None
alarm = next(
(alarm[1] for alarm in self._all if alarm[1].get("id") == self._amz_id),
None,
)
if alarm_just_dismissed(alarm, self._status, self._version):
self._dismissed = dt.now().isoformat()
self._attr_native_value = self._process_state(self._next)
self._status = self._next.get("status", "OFF") if self._next else "OFF"
self._version = self._next.get("version", "0") if self._next else None
self._amz_id = self._next.get("id") if self._next else None
if self._attr_native_value is None
if self._attr_native_value is None or self._next != self._prior_value:
# cancel any event triggers
if self._tracker:
_LOGGER.debug(
"%s: Cancelling old event",
self,
)
self._tracker()
if self._attr_native_value is not None and self._status != "SNOOZED":
_LOGGER.debug(
"%s: Scheduling event in %s",
self,
dt.as_utc(self._attr_native_value) - dt.utcnow(),
)
self._tracker = async_track_point_in_utc_time(
self.hass,
self._trigger_event, < = = = = =
dt.as_utc(self._attr_native_value),
)
< = = = = =
def _trigger_event(self, time_date) -> None:
_LOGGER.debug(
"%s:Firing %s at %s",
self,
"alexa_media_notification_event",
dt.as_local(time_date),
)
hass.bus.fire( <<<<<<<<<<<
"alexa_media_notification_event",
event_data={
"email": hide_email(self._account),
"device": {"name": self.name, "entity_id": self.entity_id},
"event": self._active[0],
},
)
They both eliminate the error for me so, which one is correct in this particular case
Or does it really not matter since _trigger_event
is only being called at one point in the code?