Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions homeassistant/components/automation/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
CONF_PLATFORM,
CONF_ZONE,
EVENT_AUTOMATION_TRIGGERED,
EVENT_HOMEASSISTANT_START,
EVENT_HOMEASSISTANT_STARTED,
SERVICE_RELOAD,
SERVICE_TOGGLE,
SERVICE_TURN_OFF,
Expand Down Expand Up @@ -409,7 +409,7 @@ async def async_enable(self):

# 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

Expand All @@ -419,10 +419,10 @@ async def async_enable_automation(event):
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()

Expand All @@ -439,15 +439,17 @@ async def async_disable(self):

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
)

Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/automation/homeassistant.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
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

Expand Down Expand Up @@ -40,7 +40,7 @@ def hass_shutdown(event):

# 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}})
)
Expand Down
27 changes: 24 additions & 3 deletions homeassistant/components/cloud/google_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@
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 (
Expand All @@ -32,6 +37,7 @@ def __init__(self, hass, config, cloud_user, prefs, cloud):
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):
Expand Down Expand Up @@ -169,6 +175,21 @@ async def _handle_entity_registry_updated(self, event):

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)
1 change: 1 addition & 0 deletions homeassistant/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@
EVENT_CORE_CONFIG_UPDATE = "core_config_updated"
EVENT_HOMEASSISTANT_CLOSE = "homeassistant_close"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should rename this event in that case to EVENT_HOMEASSISTANT_STOPPED

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Too late :) I think close is fine.

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"
Expand Down
2 changes: 2 additions & 0 deletions homeassistant/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
EVENT_HOMEASSISTANT_CLOSE,
EVENT_HOMEASSISTANT_FINAL_WRITE,
EVENT_HOMEASSISTANT_START,
EVENT_HOMEASSISTANT_STARTED,
EVENT_HOMEASSISTANT_STOP,
EVENT_SERVICE_REGISTERED,
EVENT_SERVICE_REMOVED,
Expand Down Expand Up @@ -279,6 +280,7 @@ async def async_start(self) -> None:

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.
Expand Down
2 changes: 2 additions & 0 deletions tests/components/automation/test_homeassistant.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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"):
Expand Down
5 changes: 3 additions & 2 deletions tests/components/automation/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
ATTR_ENTITY_ID,
ATTR_NAME,
EVENT_AUTOMATION_TRIGGERED,
EVENT_HOMEASSISTANT_START,
EVENT_HOMEASSISTANT_STARTED,
STATE_OFF,
STATE_ON,
)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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")

Expand Down
36 changes: 25 additions & 11 deletions tests/components/cloud/test_google_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
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

Expand All @@ -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)
Expand Down Expand Up @@ -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
)
Expand All @@ -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
)
Expand All @@ -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(
Expand Down Expand Up @@ -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