From 78f4ed48c466e4f704b0feea94e502506b32a9b3 Mon Sep 17 00:00:00 2001 From: Steven B <51370195+sdb9696@users.noreply.github.com> Date: Fri, 20 Sep 2024 08:09:26 +0100 Subject: [PATCH 1/2] Add in-home chime switch to ring --- homeassistant/components/ring/icons.json | 6 +++ homeassistant/components/ring/strings.json | 3 ++ homeassistant/components/ring/switch.py | 16 ++++++- tests/components/ring/device_mocks.py | 16 +++++++ .../ring/snapshots/test_switch.ambr | 47 +++++++++++++++++++ tests/components/ring/test_switch.py | 27 +++++++---- tests/conftest.py | 5 +- 7 files changed, 107 insertions(+), 13 deletions(-) diff --git a/homeassistant/components/ring/icons.json b/homeassistant/components/ring/icons.json index 0798d910b7b556..a5411e3e54f547 100644 --- a/homeassistant/components/ring/icons.json +++ b/homeassistant/components/ring/icons.json @@ -49,6 +49,12 @@ "switch": { "siren": { "default": "mdi:alarm-bell" + }, + "in_home_chime": { + "default": "mdi:bell-ring-outline", + "state": { + "on": "mdi:bell-ring" + } } } } diff --git a/homeassistant/components/ring/strings.json b/homeassistant/components/ring/strings.json index 201832b9465601..1094b3abd4291f 100644 --- a/homeassistant/components/ring/strings.json +++ b/homeassistant/components/ring/strings.json @@ -109,6 +109,9 @@ "switch": { "siren": { "name": "[%key:component::siren::title%]" + }, + "in_home_chime": { + "name": "In-home chime" } } }, diff --git a/homeassistant/components/ring/switch.py b/homeassistant/components/ring/switch.py index f3a7d9a1252020..79c049792dbbf4 100644 --- a/homeassistant/components/ring/switch.py +++ b/homeassistant/components/ring/switch.py @@ -5,7 +5,8 @@ import logging from typing import Any, Generic, Self, cast -from ring_doorbell import RingCapability, RingStickUpCam +from ring_doorbell import RingCapability, RingDoorBell, RingStickUpCam +from ring_doorbell.const import DOORBELL_EXISTING_TYPE from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription from homeassistant.const import Platform @@ -26,6 +27,8 @@ _LOGGER = logging.getLogger(__name__) +IN_HOME_CHIME_IS_PRESENT = {v for k, v in DOORBELL_EXISTING_TYPE.items() if k != 2} + @dataclass(frozen=True, kw_only=True) class RingSwitchEntityDescription( @@ -54,6 +57,17 @@ class RingSwitchEntityDescription( new_platform=Platform.SIREN, breaks_in_ha_version="2025.4.0" ), ), + RingSwitchEntityDescription[RingDoorBell]( + key="in_home_chime", + translation_key="in_home_chime", + exists_fn=lambda device: device.family == "doorbots" + and device.existing_doorbell_type in IN_HOME_CHIME_IS_PRESENT, + is_on_fn=lambda device: device.existing_doorbell_type_enabled or False, + turn_on_fn=lambda device: device.async_set_existing_doorbell_type_enabled(True), + turn_off_fn=lambda device: device.async_set_existing_doorbell_type_enabled( + False + ), + ), ) diff --git a/tests/components/ring/device_mocks.py b/tests/components/ring/device_mocks.py index cdb93d9911d6b3..99ee6cd11be9f4 100644 --- a/tests/components/ring/device_mocks.py +++ b/tests/components/ring/device_mocks.py @@ -18,6 +18,7 @@ RingOther, RingStickUpCam, ) +from ring_doorbell.const import DOORBELL_EXISTING_TYPE from homeassistant.components.ring.const import DOMAIN from homeassistant.util import dt as dt_util @@ -173,6 +174,21 @@ def update_history_data(fixture): ) ) + if device_family == "doorbots": + mock_device.configure_mock( + existing_doorbell_type=DOORBELL_EXISTING_TYPE[ + device_dict["settings"]["chime_settings"].get("type", 2) + ] + ) + mock_device.configure_mock( + existing_doorbell_type_enabled=device_dict["settings"][ + "chime_settings" + ].get("enable", False) + ) + mock_device.async_set_existing_doorbell_type_enabled.side_effect = ( + lambda i: mock_device.configure_mock(existing_doorbell_type_enabled=i) + ) + if device_family == "other": for prop in ("doorbell_volume", "mic_volume", "voice_volume"): mock_device.configure_mock( diff --git a/tests/components/ring/snapshots/test_switch.ambr b/tests/components/ring/snapshots/test_switch.ambr index 2d56cf3ad1372b..c45b36c430bf77 100644 --- a/tests/components/ring/snapshots/test_switch.ambr +++ b/tests/components/ring/snapshots/test_switch.ambr @@ -1,4 +1,51 @@ # serializer version: 1 +# name: test_states[switch.front_door_in_home_chime-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'switch', + 'entity_category': None, + 'entity_id': 'switch.front_door_in_home_chime', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'In-home chime', + 'platform': 'ring', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'in_home_chime', + 'unique_id': '987654-in_home_chime', + 'unit_of_measurement': None, + }) +# --- +# name: test_states[switch.front_door_in_home_chime-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'attribution': 'Data provided by Ring.com', + 'friendly_name': 'Front Door In-home chime', + }), + 'context': , + 'entity_id': 'switch.front_door_in_home_chime', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- # name: test_states[switch.front_siren-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ diff --git a/tests/components/ring/test_switch.py b/tests/components/ring/test_switch.py index c0d49ad2896c37..a29dbf72cde39c 100644 --- a/tests/components/ring/test_switch.py +++ b/tests/components/ring/test_switch.py @@ -103,35 +103,44 @@ async def test_siren_on_reports_correctly( assert state.attributes.get("friendly_name") == "Internal Siren" -async def test_siren_can_be_turned_on_and_off( - hass: HomeAssistant, mock_ring_client, create_deprecated_siren_entity +@pytest.mark.parametrize( + ("entity_id"), + [ + ("switch.front_siren"), + ("switch.front_door_in_home_chime"), + ], +) +async def test_switch_can_be_turned_on_and_off( + hass: HomeAssistant, + mock_ring_client, + create_deprecated_siren_entity, + entity_id, ) -> None: - """Tests the siren turns on correctly.""" + """Tests the switch turns on and off correctly.""" await setup_platform(hass, Platform.SWITCH) - state = hass.states.get("switch.front_siren") - assert state.state == STATE_OFF + assert hass.states.get(entity_id) await hass.services.async_call( SWITCH_DOMAIN, SERVICE_TURN_ON, - {ATTR_ENTITY_ID: "switch.front_siren"}, + {ATTR_ENTITY_ID: entity_id}, blocking=True, ) await hass.async_block_till_done() - state = hass.states.get("switch.front_siren") + state = hass.states.get(entity_id) assert state.state == STATE_ON await hass.services.async_call( SWITCH_DOMAIN, SERVICE_TURN_OFF, - {ATTR_ENTITY_ID: "switch.front_siren"}, + {ATTR_ENTITY_ID: entity_id}, blocking=True, ) await hass.async_block_till_done() - state = hass.states.get("switch.front_siren") + state = hass.states.get(entity_id) assert state.state == STATE_OFF diff --git a/tests/conftest.py b/tests/conftest.py index cfcfaf8526ce5a..870aadbb19ea97 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -32,7 +32,6 @@ import freezegun import multidict import pytest -import pytest_socket import requests_mock import respx from syrupy.assertion import SnapshotAssertion @@ -163,8 +162,8 @@ def pytest_runtest_setup() -> None: freezegun: Modified to include https://github.com/spulec/freezegun/pull/424 """ - pytest_socket.socket_allow_hosts(["127.0.0.1"]) - pytest_socket.disable_socket(allow_unix_socket=True) + # pytest_socket.socket_allow_hosts(["127.0.0.1"]) + # pytest_socket.disable_socket(allow_unix_socket=True) freezegun.api.datetime_to_fakedatetime = ha_datetime_to_fakedatetime # type: ignore[attr-defined] freezegun.api.FakeDatetime = HAFakeDatetime # type: ignore[attr-defined] From 347bc51cce23141e4defdc7ac4bef3dd9a8f9ec8 Mon Sep 17 00:00:00 2001 From: Steven B <51370195+sdb9696@users.noreply.github.com> Date: Fri, 20 Sep 2024 09:31:48 +0100 Subject: [PATCH 2/2] Fix accidental conftest change --- tests/conftest.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 870aadbb19ea97..cfcfaf8526ce5a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -32,6 +32,7 @@ import freezegun import multidict import pytest +import pytest_socket import requests_mock import respx from syrupy.assertion import SnapshotAssertion @@ -162,8 +163,8 @@ def pytest_runtest_setup() -> None: freezegun: Modified to include https://github.com/spulec/freezegun/pull/424 """ - # pytest_socket.socket_allow_hosts(["127.0.0.1"]) - # pytest_socket.disable_socket(allow_unix_socket=True) + pytest_socket.socket_allow_hosts(["127.0.0.1"]) + pytest_socket.disable_socket(allow_unix_socket=True) freezegun.api.datetime_to_fakedatetime = ha_datetime_to_fakedatetime # type: ignore[attr-defined] freezegun.api.FakeDatetime = HAFakeDatetime # type: ignore[attr-defined]