Sync area changes to google (#70936)

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
pull/71174/head
Paulus Schoutsen 2022-04-27 22:32:13 -07:00
parent 250a2aa260
commit 7b69e20db7
2 changed files with 98 additions and 6 deletions

View File

@ -9,8 +9,8 @@ from hass_nabucasa.google_report_state import ErrorResponse
from homeassistant.components.google_assistant.const import DOMAIN as GOOGLE_DOMAIN
from homeassistant.components.google_assistant.helpers import AbstractConfig
from homeassistant.const import CLOUD_NEVER_EXPOSED_ENTITIES
from homeassistant.core import CoreState, split_entity_id
from homeassistant.helpers import entity_registry as er, start
from homeassistant.core import CoreState, Event, callback, split_entity_id
from homeassistant.helpers import device_registry as dr, entity_registry as er, start
from homeassistant.setup import async_setup_component
from .const import (
@ -103,6 +103,10 @@ class CloudGoogleConfig(AbstractConfig):
er.EVENT_ENTITY_REGISTRY_UPDATED,
self._handle_entity_registry_updated,
)
self.hass.bus.async_listen(
dr.EVENT_DEVICE_REGISTRY_UPDATED,
self._handle_device_registry_updated,
)
def should_expose(self, state):
"""If a state object should be exposed."""
@ -217,9 +221,14 @@ class CloudGoogleConfig(AbstractConfig):
self._cur_entity_prefs = prefs.google_entity_configs
self._cur_default_expose = prefs.google_default_expose
async def _handle_entity_registry_updated(self, event):
@callback
def _handle_entity_registry_updated(self, event: Event) -> None:
"""Handle when entity registry updated."""
if not self.enabled or not self._cloud.is_logged_in:
if (
not self.enabled
or not self._cloud.is_logged_in
or self.hass.state != CoreState.running
):
return
# Only consider entity registry updates if info relevant for Google has changed
@ -233,7 +242,30 @@ class CloudGoogleConfig(AbstractConfig):
if not self._should_expose_entity_id(entity_id):
return
if self.hass.state != CoreState.running:
self.async_schedule_google_sync_all()
@callback
def _handle_device_registry_updated(self, event: Event) -> None:
"""Handle when device registry updated."""
if (
not self.enabled
or not self._cloud.is_logged_in
or self.hass.state != CoreState.running
):
return
# Device registry is only used for area changes. All other changes are ignored.
if event.data["action"] != "update" or "area_id" not in event.data["changes"]:
return
# Check if any exposed entity uses the device area
if not any(
entity_entry.area_id is None
and self._should_expose_entity_id(entity_entry.entity_id)
for entity_entry in er.async_entries_for_device(
er.async_get(self.hass), event.data["device_id"]
)
):
return
self.async_schedule_google_sync_all()

View File

@ -10,7 +10,7 @@ from homeassistant.components.cloud.google_config import CloudGoogleConfig
from homeassistant.components.google_assistant import helpers as ga_helpers
from homeassistant.const import EVENT_HOMEASSISTANT_STARTED
from homeassistant.core import CoreState, State
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.helpers.entity import EntityCategory
from homeassistant.util.dt import utcnow
@ -191,6 +191,66 @@ async def test_google_entity_registry_sync(hass, mock_cloud_login, cloud_prefs):
assert len(mock_sync.mock_calls) == 3
async def test_google_device_registry_sync(hass, mock_cloud_login, cloud_prefs):
"""Test Google config responds to device registry."""
config = CloudGoogleConfig(
hass, GACTIONS_SCHEMA({}), "mock-user-id", cloud_prefs, hass.data["cloud"]
)
ent_reg = er.async_get(hass)
entity_entry = ent_reg.async_get_or_create(
"light", "hue", "1234", device_id="1234", area_id="ABCD"
)
with patch.object(config, "async_sync_entities_all"):
await config.async_initialize()
await hass.async_block_till_done()
await config.async_connect_agent_user("mock-user-id")
with patch.object(config, "async_schedule_google_sync_all") as mock_sync:
# Device registry updated with non-relevant changes
hass.bus.async_fire(
dr.EVENT_DEVICE_REGISTRY_UPDATED,
{
"action": "update",
"device_id": "1234",
"changes": ["manufacturer"],
},
)
await hass.async_block_till_done()
assert len(mock_sync.mock_calls) == 0
# Device registry updated with relevant changes
# but entity has area ID so not impacted
hass.bus.async_fire(
dr.EVENT_DEVICE_REGISTRY_UPDATED,
{
"action": "update",
"device_id": "1234",
"changes": ["area_id"],
},
)
await hass.async_block_till_done()
assert len(mock_sync.mock_calls) == 0
ent_reg.async_update_entity(entity_entry.entity_id, area_id=None)
# Device registry updated with relevant changes
# but entity has area ID so not impacted
hass.bus.async_fire(
dr.EVENT_DEVICE_REGISTRY_UPDATED,
{
"action": "update",
"device_id": "1234",
"changes": ["area_id"],
},
)
await hass.async_block_till_done()
assert len(mock_sync.mock_calls) == 1
async def test_sync_google_when_started(hass, mock_cloud_login, cloud_prefs):
"""Test Google config syncs on init."""
config = CloudGoogleConfig(