Add Home Assistant Started event (#34657)

This commit is contained in:
Paulus Schoutsen 2020-04-24 14:13:39 -07:00
parent f3f2aa807b
commit 214d6f5cf5
8 changed files with 68 additions and 25 deletions

View file

@ -14,7 +14,7 @@ from homeassistant.const import (
CONF_PLATFORM,
CONF_ZONE,
EVENT_AUTOMATION_TRIGGERED,
EVENT_HOMEASSISTANT_START,
EVENT_HOMEASSISTANT_STARTED,
SERVICE_RELOAD,
SERVICE_TOGGLE,
SERVICE_TURN_OFF,
@ -408,7 +408,7 @@ class AutomationEntity(ToggleEntity, RestoreEntity):
# HomeAssistant is starting up
if self.hass.state != CoreState.not_running:
self._async_detach_triggers = await self._async_attach_triggers()
self._async_detach_triggers = await self._async_attach_triggers(False)
self.async_write_ha_state()
return
@ -418,10 +418,10 @@ class AutomationEntity(ToggleEntity, RestoreEntity):
if not self._is_enabled or self._async_detach_triggers is not None:
return
self._async_detach_triggers = await self._async_attach_triggers()
self._async_detach_triggers = await self._async_attach_triggers(True)
self.hass.bus.async_listen_once(
EVENT_HOMEASSISTANT_START, async_enable_automation
EVENT_HOMEASSISTANT_STARTED, async_enable_automation
)
self.async_write_ha_state()
@ -438,15 +438,17 @@ class AutomationEntity(ToggleEntity, RestoreEntity):
self.async_write_ha_state()
async def _async_attach_triggers(self):
async def _async_attach_triggers(
self, home_assistant_start: bool
) -> Optional[Callable[[], None]]:
"""Set up the triggers."""
removes = []
info = {"name": self._name}
info = {"name": self._name, "home_assistant_start": home_assistant_start}
for conf in self._trigger_config:
platform = importlib.import_module(f".{conf[CONF_PLATFORM]}", __name__)
remove = await platform.async_attach_trigger(
remove = await platform.async_attach_trigger( # type: ignore
self.hass, conf, self.async_trigger, info
)

View file

@ -4,7 +4,7 @@ import logging
import voluptuous as vol
from homeassistant.const import CONF_EVENT, CONF_PLATFORM, EVENT_HOMEASSISTANT_STOP
from homeassistant.core import CoreState, callback
from homeassistant.core import callback
# mypy: allow-untyped-defs
@ -40,7 +40,7 @@ async def async_attach_trigger(hass, config, action, automation_info):
# Automation are enabled while hass is starting up, fire right away
# Check state because a config reload shouldn't trigger it.
if hass.state == CoreState.starting:
if automation_info["home_assistant_start"]:
hass.async_run_job(
action({"trigger": {"platform": "homeassistant", "event": event}})
)

View file

@ -6,7 +6,12 @@ from hass_nabucasa import cloud_api
from hass_nabucasa.google_report_state import ErrorResponse
from homeassistant.components.google_assistant.helpers import AbstractConfig
from homeassistant.const import CLOUD_NEVER_EXPOSED_ENTITIES, HTTP_OK
from homeassistant.const import (
CLOUD_NEVER_EXPOSED_ENTITIES,
EVENT_HOMEASSISTANT_STARTED,
HTTP_OK,
)
from homeassistant.core import CoreState, callback
from homeassistant.helpers import entity_registry
from .const import (
@ -32,6 +37,7 @@ class CloudGoogleConfig(AbstractConfig):
self._cloud = cloud
self._cur_entity_prefs = self._prefs.google_entity_configs
self._sync_entities_lock = asyncio.Lock()
self._sync_on_started = False
@property
def enabled(self):
@ -169,6 +175,21 @@ class CloudGoogleConfig(AbstractConfig):
entity_id = event.data["entity_id"]
# Schedule a sync if a change was made to an entity that Google knows about
if self._should_expose_entity_id(entity_id):
if not self._should_expose_entity_id(entity_id):
return
if self.hass.state == CoreState.running:
self.async_schedule_google_sync_all()
return
if self._sync_on_started:
return
self._sync_on_started = True
@callback
async def sync_google(_):
"""Sync entities to Google."""
await self.async_sync_entities_all()
self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STARTED, sync_google)

View file

@ -183,6 +183,7 @@ EVENT_COMPONENT_LOADED = "component_loaded"
EVENT_CORE_CONFIG_UPDATE = "core_config_updated"
EVENT_HOMEASSISTANT_CLOSE = "homeassistant_close"
EVENT_HOMEASSISTANT_START = "homeassistant_start"
EVENT_HOMEASSISTANT_STARTED = "homeassistant_started"
EVENT_HOMEASSISTANT_STOP = "homeassistant_stop"
EVENT_HOMEASSISTANT_FINAL_WRITE = "homeassistant_final_write"
EVENT_LOGBOOK_ENTRY = "logbook_entry"

View file

@ -50,6 +50,7 @@ from homeassistant.const import (
EVENT_HOMEASSISTANT_CLOSE,
EVENT_HOMEASSISTANT_FINAL_WRITE,
EVENT_HOMEASSISTANT_START,
EVENT_HOMEASSISTANT_STARTED,
EVENT_HOMEASSISTANT_STOP,
EVENT_SERVICE_REGISTERED,
EVENT_SERVICE_REMOVED,
@ -279,6 +280,7 @@ class HomeAssistant:
self.state = CoreState.running
_async_create_timer(self)
self.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
def add_job(self, target: Callable[..., Any], *args: Any) -> None:
"""Add job to the executor pool.

View file

@ -25,6 +25,7 @@ async def test_if_fires_on_hass_start(hass):
assert len(calls) == 0
await hass.async_start()
await hass.async_block_till_done()
assert automation.is_on(hass, "automation.hello")
assert len(calls) == 1
@ -61,6 +62,7 @@ async def test_if_fires_on_hass_shutdown(hass):
await hass.async_start()
assert automation.is_on(hass, "automation.hello")
await hass.async_block_till_done()
assert len(calls) == 0
with patch.object(hass.loop, "stop"):

View file

@ -10,7 +10,7 @@ from homeassistant.const import (
ATTR_ENTITY_ID,
ATTR_NAME,
EVENT_AUTOMATION_TRIGGERED,
EVENT_HOMEASSISTANT_START,
EVENT_HOMEASSISTANT_STARTED,
STATE_OFF,
STATE_ON,
)
@ -700,6 +700,7 @@ async def test_initial_value_on(hass):
assert automation.is_on(hass, "automation.hello")
await hass.async_start()
await hass.async_block_till_done()
hass.bus.async_fire("test_event")
await hass.async_block_till_done()
assert len(calls) == 1
@ -822,7 +823,7 @@ async def test_automation_not_trigger_on_bootstrap(hass):
await hass.async_block_till_done()
assert len(calls) == 0
hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
await hass.async_block_till_done()
assert automation.is_on(hass, "automation.hello")

View file

@ -6,7 +6,8 @@ from asynctest import patch
from homeassistant.components.cloud import GACTIONS_SCHEMA
from homeassistant.components.cloud.google_config import CloudGoogleConfig
from homeassistant.components.google_assistant import helpers as ga_helpers
from homeassistant.const import HTTP_NOT_FOUND
from homeassistant.const import EVENT_HOMEASSISTANT_STARTED, HTTP_NOT_FOUND
from homeassistant.core import CoreState
from homeassistant.helpers.entity_registry import EVENT_ENTITY_REGISTRY_UPDATED
from homeassistant.util.dt import utcnow
@ -25,9 +26,7 @@ async def test_google_update_report_state(hass, cloud_prefs):
await config.async_initialize()
await config.async_connect_agent_user("mock-user-id")
with patch.object(
config, "async_sync_entities", side_effect=mock_coro
) as mock_sync, patch(
with patch.object(config, "async_sync_entities") as mock_sync, patch(
"homeassistant.components.google_assistant.report_state.async_enable_report_state"
) as mock_report_state:
await cloud_prefs.async_update(google_report_state=True)
@ -67,9 +66,9 @@ async def test_google_update_expose_trigger_sync(hass, cloud_prefs):
await config.async_initialize()
await config.async_connect_agent_user("mock-user-id")
with patch.object(
config, "async_sync_entities", side_effect=mock_coro
) as mock_sync, patch.object(ga_helpers, "SYNC_DELAY", 0):
with patch.object(config, "async_sync_entities") as mock_sync, patch.object(
ga_helpers, "SYNC_DELAY", 0
):
await cloud_prefs.async_update_google_entity_config(
entity_id="light.kitchen", should_expose=True
)
@ -79,9 +78,9 @@ async def test_google_update_expose_trigger_sync(hass, cloud_prefs):
assert len(mock_sync.mock_calls) == 1
with patch.object(
config, "async_sync_entities", side_effect=mock_coro
) as mock_sync, patch.object(ga_helpers, "SYNC_DELAY", 0):
with patch.object(config, "async_sync_entities") as mock_sync, patch.object(
ga_helpers, "SYNC_DELAY", 0
):
await cloud_prefs.async_update_google_entity_config(
entity_id="light.kitchen", should_expose=False
)
@ -107,7 +106,7 @@ async def test_google_entity_registry_sync(hass, mock_cloud_login, cloud_prefs):
await config.async_connect_agent_user("mock-user-id")
with patch.object(
config, "async_schedule_google_sync_all", side_effect=mock_coro
config, "async_schedule_google_sync_all"
) as mock_sync, patch.object(ga_helpers, "SYNC_DELAY", 0):
# Created entity
hass.bus.async_fire(
@ -148,3 +147,18 @@ async def test_google_entity_registry_sync(hass, mock_cloud_login, cloud_prefs):
await hass.async_block_till_done()
assert len(mock_sync.mock_calls) == 3
# When hass is not started yet we wait till started
hass.state = CoreState.starting
hass.bus.async_fire(
EVENT_ENTITY_REGISTRY_UPDATED,
{"action": "create", "entity_id": "light.kitchen"},
)
await hass.async_block_till_done()
assert len(mock_sync.mock_calls) == 3
with patch.object(config, "async_sync_entities_all") as mock_sync:
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
await hass.async_block_till_done()
assert len(mock_sync.mock_calls) == 1