From 4709e60ff64c7e7ba3930d3ec312980bc339bf72 Mon Sep 17 00:00:00 2001 From: Jan Bouwhuis Date: Sat, 7 Oct 2023 19:39:04 +0200 Subject: [PATCH] Rework on Google Assistant doorbell support (#100930) * Rework on Google Assistant doorbell event * Additional comment on syncing notificatiions * Update homeassistant/components/google_assistant/trait.py * Only sync event if state attr changed * Update comment --- homeassistant/components/google_assistant/helpers.py | 2 +- .../components/google_assistant/report_state.py | 10 +++++++++- homeassistant/components/google_assistant/trait.py | 6 +++++- tests/components/google_assistant/test_trait.py | 2 +- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/google_assistant/helpers.py b/homeassistant/components/google_assistant/helpers.py index ee8e5872348..b2cda5522ee 100644 --- a/homeassistant/components/google_assistant/helpers.py +++ b/homeassistant/components/google_assistant/helpers.py @@ -240,7 +240,7 @@ class AbstractConfig(ABC): async def async_sync_notification( self, agent_user_id: str, event_id: str, payload: dict[str, Any] ) -> HTTPStatus: - """Sync notification to Google.""" + """Sync notifications to Google.""" # Remove any pending sync self._google_sync_unsub.pop(agent_user_id, lambda: None)() status = await self.async_report_state(payload, agent_user_id, event_id) diff --git a/homeassistant/components/google_assistant/report_state.py b/homeassistant/components/google_assistant/report_state.py index 87af12ad0fc..aec50011200 100644 --- a/homeassistant/components/google_assistant/report_state.py +++ b/homeassistant/components/google_assistant/report_state.py @@ -80,7 +80,15 @@ def async_enable_report_state(hass: HomeAssistant, google_config: AbstractConfig ): return - if (notifications := entity.notifications_serialize()) is not None: + # We only trigger notifications on changes in the state value, not attributes. + # This is mainly designed for our event entity types + # We need to synchronize notifications using a `SYNC` response, + # together with other state changes. + if ( + old_state + and old_state.state != new_state.state + and (notifications := entity.notifications_serialize()) is not None + ): event_id = uuid4().hex payload = { "devices": {"notifications": {entity.state.entity_id: notifications}} diff --git a/homeassistant/components/google_assistant/trait.py b/homeassistant/components/google_assistant/trait.py index a39dfd3f3dc..a3b6638de11 100644 --- a/homeassistant/components/google_assistant/trait.py +++ b/homeassistant/components/google_assistant/trait.py @@ -382,10 +382,14 @@ class ObjectDetection(_Trait): return None # Only notify if last event was less then 30 seconds ago - time_stamp = datetime.fromisoformat(self.state.state) + time_stamp: datetime = datetime.fromisoformat(self.state.state) if (utcnow() - time_stamp) > timedelta(seconds=30): return None + # A doorbell event is treated as an object detection of 1 unclassified object. + # The implementation follows the pattern from the Smart Home Doorbell Guide: + # https://developers.home.google.com/cloud-to-cloud/guides/doorbell + # The detectionTimestamp is the time in ms from January 1, 1970, 00:00:00 (UTC) return { "ObjectDetection": { "objects": { diff --git a/tests/components/google_assistant/test_trait.py b/tests/components/google_assistant/test_trait.py index db4257bb621..903ba5ca036 100644 --- a/tests/components/google_assistant/test_trait.py +++ b/tests/components/google_assistant/test_trait.py @@ -223,7 +223,7 @@ async def test_onoff_input_boolean(hass: HomeAssistant) -> None: @pytest.mark.freeze_time("2023-08-01T00:02:57+00:00") async def test_doorbell_event(hass: HomeAssistant) -> None: - """Test doorbell event trait support for input_boolean domain.""" + """Test doorbell event trait support for event domain.""" assert trait.ObjectDetection.supported(event.DOMAIN, 0, "doorbell", None) state = State(