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: shutdownI 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'): |
| This method is a coroutine. | ||
| """ | ||
| start = time() | ||
| hass.async_track_tasks() |
There was a problem hiding this comment.
Track tasks is now enabled by default. It's what we want during startup.
|
|
||
| This method must be run in the event loop. | ||
| """ | ||
| if event_type != EVENT_HOMEASSISTANT_STOP and \ |
There was a problem hiding this comment.
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.loop._thread_ident = threading.get_ident() | ||
| _async_create_timer(self) | ||
| self.bus.async_fire(EVENT_HOMEASSISTANT_START) | ||
| yield from self.async_stop_track_tasks() |
There was a problem hiding this comment.
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.
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.
I think that should not be needed to add a timeout
| """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.
Why not only call loop.create_task?
There was a problem hiding this comment.
Because that's not threadsafe
There was a problem hiding this comment.
You are sure? I found no comments in doc that will be not threadsafe.
There was a problem hiding this comment.
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.
(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.
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_STARTevent 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_starton startup is deprecated and will be removed in Home Assistant 0.45. Use the new automation homeassistant platform instead.hass.stateis 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.stateisCoreState.running.Configuration
Checklist:
If the code does not interact with devices:
toxrun successfully. Your PR cannot be merged unless tests pass