Simplify nest event handling (#44367)
* Simplify nest event handling Use device specific update callbacks rather than a global callback. The motivation is to prepare for a follow up change that will store camera specific event tokens on the camera itself, so that a service can later fetch event specific image snapshots, which would be difficult to send across the event bus. * Increase nest camera test coverage * Remove unnecessary device updates for nest cameras * Remove unused imports * Fix device id check to look at returned entry * Remove unused imports after rebase * Partial revert of nest event simplification * Push more update logic into the nest library * Revert nest device_info changes * Revert test changes to restore global update behavior * Bump nest library version to support new callback interfacespull/44566/head
parent
9531b08f2a
commit
51b88337ca
|
@ -3,7 +3,7 @@
|
|||
import asyncio
|
||||
import logging
|
||||
|
||||
from google_nest_sdm.event import AsyncEventCallback, EventMessage
|
||||
from google_nest_sdm.event import EventMessage
|
||||
from google_nest_sdm.exceptions import AuthException, GoogleNestException
|
||||
from google_nest_sdm.google_nest_subscriber import GoogleNestSubscriber
|
||||
import voluptuous as vol
|
||||
|
@ -24,7 +24,6 @@ from homeassistant.helpers import (
|
|||
config_entry_oauth2_flow,
|
||||
config_validation as cv,
|
||||
)
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||
|
||||
from . import api, config_flow
|
||||
from .const import (
|
||||
|
@ -34,7 +33,6 @@ from .const import (
|
|||
DOMAIN,
|
||||
OAUTH2_AUTHORIZE,
|
||||
OAUTH2_TOKEN,
|
||||
SIGNAL_NEST_UPDATE,
|
||||
)
|
||||
from .events import EVENT_NAME_MAP, NEST_EVENT
|
||||
from .legacy import async_setup_legacy, async_setup_legacy_entry
|
||||
|
@ -106,7 +104,7 @@ async def async_setup(hass: HomeAssistant, config: dict):
|
|||
return True
|
||||
|
||||
|
||||
class SignalUpdateCallback(AsyncEventCallback):
|
||||
class SignalUpdateCallback:
|
||||
"""An EventCallback invoked when new events arrive from subscriber."""
|
||||
|
||||
def __init__(self, hass: HomeAssistant):
|
||||
|
@ -116,17 +114,8 @@ class SignalUpdateCallback(AsyncEventCallback):
|
|||
async def async_handle_event(self, event_message: EventMessage):
|
||||
"""Process an incoming EventMessage."""
|
||||
if not event_message.resource_update_name:
|
||||
_LOGGER.debug("Ignoring event with no device_id")
|
||||
return
|
||||
device_id = event_message.resource_update_name
|
||||
_LOGGER.debug("Update for %s @ %s", device_id, event_message.timestamp)
|
||||
traits = event_message.resource_update_traits
|
||||
if traits:
|
||||
_LOGGER.debug("Trait update %s", traits.keys())
|
||||
# This event triggered an update to a device that changed some
|
||||
# properties which the DeviceManager should already have received.
|
||||
# Send a signal to refresh state of all listening devices.
|
||||
async_dispatcher_send(self._hass, SIGNAL_NEST_UPDATE)
|
||||
events = event_message.resource_update_events
|
||||
if not events:
|
||||
return
|
||||
|
@ -134,7 +123,6 @@ class SignalUpdateCallback(AsyncEventCallback):
|
|||
device_registry = await self._hass.helpers.device_registry.async_get_registry()
|
||||
device_entry = device_registry.async_get_device({(DOMAIN, device_id)}, ())
|
||||
if not device_entry:
|
||||
_LOGGER.debug("Ignoring event for unregistered device '%s'", device_id)
|
||||
return
|
||||
for event in events:
|
||||
event_type = EVENT_NAME_MAP.get(event)
|
||||
|
@ -170,7 +158,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
|
|||
subscriber = GoogleNestSubscriber(
|
||||
auth, config[CONF_PROJECT_ID], config[CONF_SUBSCRIBER_ID]
|
||||
)
|
||||
subscriber.set_update_callback(SignalUpdateCallback(hass))
|
||||
callback = SignalUpdateCallback(hass)
|
||||
subscriber.set_update_callback(callback.async_handle_event)
|
||||
|
||||
try:
|
||||
await subscriber.start_async()
|
||||
|
|
|
@ -13,12 +13,11 @@ from homeassistant.components.camera import SUPPORT_STREAM, Camera
|
|||
from homeassistant.components.ffmpeg import async_get_image
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.exceptions import PlatformNotReady
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.event import async_track_point_in_utc_time
|
||||
from homeassistant.helpers.typing import HomeAssistantType
|
||||
from homeassistant.util.dt import utcnow
|
||||
|
||||
from .const import DATA_SUBSCRIBER, DOMAIN, SIGNAL_NEST_UPDATE
|
||||
from .const import DATA_SUBSCRIBER, DOMAIN
|
||||
from .device_info import DeviceInfo
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -151,13 +150,8 @@ class NestCamera(Camera):
|
|||
|
||||
async def async_added_to_hass(self):
|
||||
"""Run when entity is added to register update signal handler."""
|
||||
# Event messages trigger the SIGNAL_NEST_UPDATE, which is intercepted
|
||||
# here to re-fresh the signals from _device. Unregister this callback
|
||||
# when the entity is removed.
|
||||
self.async_on_remove(
|
||||
async_dispatcher_connect(
|
||||
self.hass, SIGNAL_NEST_UPDATE, self.async_write_ha_state
|
||||
)
|
||||
self._device.add_update_listener(self.async_write_ha_state)
|
||||
)
|
||||
|
||||
async def async_camera_image(self):
|
||||
|
|
|
@ -36,10 +36,9 @@ from homeassistant.components.climate.const import (
|
|||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS
|
||||
from homeassistant.exceptions import PlatformNotReady
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.typing import HomeAssistantType
|
||||
|
||||
from .const import DATA_SUBSCRIBER, DOMAIN, SIGNAL_NEST_UPDATE
|
||||
from .const import DATA_SUBSCRIBER, DOMAIN
|
||||
from .device_info import DeviceInfo
|
||||
|
||||
# Mapping for sdm.devices.traits.ThermostatMode mode field
|
||||
|
@ -126,16 +125,9 @@ class ThermostatEntity(ClimateEntity):
|
|||
|
||||
async def async_added_to_hass(self):
|
||||
"""Run when entity is added to register update signal handler."""
|
||||
# Event messages trigger the SIGNAL_NEST_UPDATE, which is intercepted
|
||||
# here to re-fresh the signals from _device. Unregister this callback
|
||||
# when the entity is removed.
|
||||
self._supported_features = self._get_supported_features()
|
||||
self.async_on_remove(
|
||||
async_dispatcher_connect(
|
||||
self.hass,
|
||||
SIGNAL_NEST_UPDATE,
|
||||
self.async_write_ha_state,
|
||||
)
|
||||
self._device.add_update_listener(self.async_write_ha_state)
|
||||
)
|
||||
|
||||
@property
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
"documentation": "https://www.home-assistant.io/integrations/nest",
|
||||
"requirements": [
|
||||
"python-nest==4.1.0",
|
||||
"google-nest-sdm==0.2.1"
|
||||
"google-nest-sdm==0.2.5"
|
||||
],
|
||||
"codeowners": [
|
||||
"@awarecan",
|
||||
|
|
|
@ -15,11 +15,10 @@ from homeassistant.const import (
|
|||
TEMP_CELSIUS,
|
||||
)
|
||||
from homeassistant.exceptions import PlatformNotReady
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.helpers.typing import HomeAssistantType
|
||||
|
||||
from .const import DATA_SUBSCRIBER, DOMAIN, SIGNAL_NEST_UPDATE
|
||||
from .const import DATA_SUBSCRIBER, DOMAIN
|
||||
from .device_info import DeviceInfo
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -80,15 +79,8 @@ class SensorBase(Entity):
|
|||
|
||||
async def async_added_to_hass(self):
|
||||
"""Run when entity is added to register update signal handler."""
|
||||
# Event messages trigger the SIGNAL_NEST_UPDATE, which is intercepted
|
||||
# here to re-fresh the signals from _device. Unregister this callback
|
||||
# when the entity is removed.
|
||||
self.async_on_remove(
|
||||
async_dispatcher_connect(
|
||||
self.hass,
|
||||
SIGNAL_NEST_UPDATE,
|
||||
self.async_write_ha_state,
|
||||
)
|
||||
self._device.add_update_listener(self.async_write_ha_state)
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -681,7 +681,7 @@ google-cloud-pubsub==2.1.0
|
|||
google-cloud-texttospeech==0.4.0
|
||||
|
||||
# homeassistant.components.nest
|
||||
google-nest-sdm==0.2.1
|
||||
google-nest-sdm==0.2.5
|
||||
|
||||
# homeassistant.components.google_travel_time
|
||||
googlemaps==2.5.1
|
||||
|
|
|
@ -352,7 +352,7 @@ google-api-python-client==1.6.4
|
|||
google-cloud-pubsub==2.1.0
|
||||
|
||||
# homeassistant.components.nest
|
||||
google-nest-sdm==0.2.1
|
||||
google-nest-sdm==0.2.5
|
||||
|
||||
# homeassistant.components.gree
|
||||
greeclimate==0.10.3
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
"""Common libraries for test setup."""
|
||||
|
||||
import time
|
||||
from typing import Awaitable, Callable
|
||||
|
||||
from google_nest_sdm.device_manager import DeviceManager
|
||||
from google_nest_sdm.event import AsyncEventCallback, EventMessage
|
||||
from google_nest_sdm.event import EventMessage
|
||||
from google_nest_sdm.google_nest_subscriber import GoogleNestSubscriber
|
||||
|
||||
from homeassistant.components.nest import DOMAIN
|
||||
|
@ -59,9 +60,8 @@ class FakeSubscriber(GoogleNestSubscriber):
|
|||
def __init__(self, device_manager: FakeDeviceManager):
|
||||
"""Initialize Fake Subscriber."""
|
||||
self._device_manager = device_manager
|
||||
self._callback = None
|
||||
|
||||
def set_update_callback(self, callback: AsyncEventCallback):
|
||||
def set_update_callback(self, callback: Callable[[EventMessage], Awaitable[None]]):
|
||||
"""Capture the callback set by Home Assistant."""
|
||||
self._callback = callback
|
||||
|
||||
|
@ -81,7 +81,7 @@ class FakeSubscriber(GoogleNestSubscriber):
|
|||
"""Simulate a received pubsub message, invoked by tests."""
|
||||
# Update device state, then invoke HomeAssistant to refresh
|
||||
await self._device_manager.async_handle_event(event_message)
|
||||
await self._callback.async_handle_event(event_message)
|
||||
await self._callback(event_message)
|
||||
|
||||
|
||||
async def async_setup_sdm_platform(hass, platform, devices={}, structures={}):
|
||||
|
|
|
@ -7,7 +7,8 @@ import homeassistant.components.automation as automation
|
|||
from homeassistant.components.device_automation.exceptions import (
|
||||
InvalidDeviceAutomationConfig,
|
||||
)
|
||||
from homeassistant.components.nest import DOMAIN, NEST_EVENT
|
||||
from homeassistant.components.nest import DOMAIN
|
||||
from homeassistant.components.nest.events import NEST_EVENT
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from .common import async_setup_sdm_platform
|
||||
|
|
Loading…
Reference in New Issue