-
-
Notifications
You must be signed in to change notification settings - Fork 31.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix automations listening to HOMEASSISTANT_START #6936
Conversation
@balloob, thanks for your PR! By analyzing the history of the files in this pull request, we identified @andythigpen, @fabaff and @pvizeli to be potential reviewers. |
a628e72
to
4da2c63
Compare
I think the seconds variant is not realy bad. With this special automation platform we allow to trigger on startup and shutdown. Other automation make it also in this way. Maybe we have other case for that platform in future. like: action:
platform: homeassistant
state: startup
...
action:
platform: homeassistant
state: shutdown I like that. |
Alright. Will support the old method but deprecate it. Then will also add the new platform. |
4da2c63
to
3b46e44
Compare
assert automation.is_on(hass, 'automation.hello') | ||
assert len(calls) == 0 | ||
|
||
with patch.object(hass.loop, 'stop'), patch.object(hass.executor, 'shutdown'): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
line too long (82 > 79 characters)
@@ -74,8 +74,6 @@ def async_from_config_dict(config: Dict[str, Any], | |||
This method is a coroutine. | |||
""" | |||
start = time() | |||
hass.async_track_tasks() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Track tasks is now enabled by default. It's what we want during startup.
@@ -368,10 +367,6 @@ def async_fire(self, event_type: str, event_data=None, | |||
|
|||
This method must be run in the event loop. | |||
""" | |||
if event_type != EVENT_HOMEASSISTANT_STOP and \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was silently (because exception suppressed) killing shutdown tasks (noticed it when adding shutdown event in automation). It should be fine to just wait till all is done. Timer is already stopped so nothing new should come in.
self.bus.async_fire(EVENT_HOMEASSISTANT_START) | ||
yield from self.async_stop_track_tasks() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this fixes the fact that CoreState.starting
was never detectable before, as we would immediately overwrite it.
However, this has the downside that it is impossible for components/platforms to start a permanent async job as a result from EVENT_HOMEASSISTANT_START.
(note that things like MQTT server rely on loop.create_server
which will work. Z-Wave depends on a thread and that will work)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add a timeout to async_stop_track_tasks
after which we will no longer stop tracking tasks?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that should not be needed to add a timeout
@@ -252,7 +246,8 @@ def async_block_till_done(self): | |||
|
|||
def stop(self) -> None: | |||
"""Stop Home Assistant and shuts down all threads.""" | |||
run_coroutine_threadsafe(self.async_stop(), self.loop) | |||
self.loop.call_soon_threadsafe( | |||
self.loop.create_task, self.async_stop()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not only call loop.create_task
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because that's not threadsafe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are sure? I found no comments in doc that will be not threadsafe.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://docs.python.org/3/library/asyncio-dev.html#concurrency-and-multithreading
To schedule a coroutine object from a different thread, the run_coroutine_threadsafe() function should be used.
Also, the tests won't pass if I just call create_task.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(note, we include the run_coroutine_threadsafe
function from Python in HASS because it was only introduced in Python 3.5.1)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
asyncio.ensure_future
maby the same but don't support with python 3.4.2
Description:
To prevent false triggers, we only enable automations after all components are setup. This however introduced a breaking change: we no longer allow people to listen to HOMEASSISTANT_START.
This PR is just to start discussion, the included fix is actually a bad one.
I still want people to be able to run something on startup.
HOMEASSISTANT_START
event andhass.state == CoreState.starting
. This is a hack.hass.state
)This PR forced me to fix how CoreState is set and ensures we wait till all tasks done before we start firing the timer. This caused some changes to how we mock HASS in tests.
Breaking changes
homeassistant_start
on startup is deprecated and will be removed in Home Assistant 0.45. Use the new automation homeassistant platform instead.hass.state
is set toCoreState.starting
. All tasks will be awaited during startup and the timer will only start when that is done. At that point in timehass.state
isCoreState.running
.Configuration
Checklist:
If the code does not interact with devices:
tox
run successfully. Your PR cannot be merged unless tests pass