From 81ed3940c70ed04bde8b7a7c0d628f6f2e377eda Mon Sep 17 00:00:00 2001 From: Thomas <10558666+mosandlt@users.noreply.github.com> Date: Fri, 25 Sep 2026 16:10:04 +0200 Subject: [PATCH] bosch_shc: add Motion Detector 2 automatic sensitivity switch entity (#182937) Co-authored-by: Claude Sonnet 5 --- .../components/bosch_shc/strings.json | 3 + homeassistant/components/bosch_shc/switch.py | 22 +++++++ tests/components/bosch_shc/conftest.py | 4 ++ tests/components/bosch_shc/test_switch.py | 66 +++++++++++++++++++ 4 files changed, 95 insertions(+) diff --git a/homeassistant/components/bosch_shc/strings.json b/homeassistant/components/bosch_shc/strings.json index dcc57e0aa3fb..fc1341665908 100644 --- a/homeassistant/components/bosch_shc/strings.json +++ b/homeassistant/components/bosch_shc/strings.json @@ -116,6 +116,9 @@ "routing": { "name": "Range extension" }, + "smart_sensitivity_enabled": { + "name": "Automatic sensitivity" + }, "tamper_protection_enabled": { "name": "Sabotage detection" } diff --git a/homeassistant/components/bosch_shc/switch.py b/homeassistant/components/bosch_shc/switch.py index e2cd66ed075f..44edf230a241 100644 --- a/homeassistant/components/bosch_shc/switch.py +++ b/homeassistant/components/bosch_shc/switch.py @@ -153,6 +153,15 @@ SWITCH_TYPES: dict[str, SHCSwitchEntityDescription] = { on_value=True, should_poll=False, ), + "smart_sensitivity_enabled": SHCSwitchEntityDescription( + key="smart_sensitivity_enabled", + translation_key="smart_sensitivity_enabled", + device_class=SwitchDeviceClass.SWITCH, + entity_category=EntityCategory.CONFIG, + on_key="smart_sensitivity_enabled", + on_value=True, + should_poll=False, + ), } @@ -379,6 +388,19 @@ async def async_setup_entry( if getattr(switch, "supports_display_configuration", False) ) + entities.extend( + SHCSwitch( + hass=hass, + device=switch, + parent_id=shc_info.unique_id, + entry_id=config_entry.entry_id, + description=SWITCH_TYPES["smart_sensitivity_enabled"], + unique_id_suffix="smart_sensitivity", + ) + for switch in session.device_helper.motion_detectors2 + if switch.supports_smart_sensitivity + ) + async_add_entities(entities) diff --git a/tests/components/bosch_shc/conftest.py b/tests/components/bosch_shc/conftest.py index 4610bc3bc9c0..8896b8c02a87 100644 --- a/tests/components/bosch_shc/conftest.py +++ b/tests/components/bosch_shc/conftest.py @@ -393,6 +393,8 @@ def motion_detector2_device( name: str = "Motion Detector", pet_immunity_enabled: bool = False, tamper_protection_enabled: bool = False, + supports_smart_sensitivity: bool = False, + smart_sensitivity_enabled: bool = False, ) -> SHCMotionDetector2: """Build a minimal device double for the motion_detectors2 bucket.""" device = create_autospec(SHCMotionDetector2, instance=True, spec_set=True) @@ -407,6 +409,8 @@ def motion_detector2_device( device.status = "AVAILABLE" device.pet_immunity_enabled = pet_immunity_enabled device.tamper_protection_enabled = tamper_protection_enabled + device.supports_smart_sensitivity = supports_smart_sensitivity + device.smart_sensitivity_enabled = smart_sensitivity_enabled return device diff --git a/tests/components/bosch_shc/test_switch.py b/tests/components/bosch_shc/test_switch.py index 8283775465a1..f0d551b732f8 100644 --- a/tests/components/bosch_shc/test_switch.py +++ b/tests/components/bosch_shc/test_switch.py @@ -657,3 +657,69 @@ async def test_smart_plug_compact_energy_saving_mode( blocking=True, ) assert device.energy_saving_mode_enabled is True + + +@pytest.mark.parametrize( + "device_buckets", + [ + { + "motion_detectors2": [ + motion_detector2_device( + supports_smart_sensitivity=True, smart_sensitivity_enabled=False + ) + ] + } + ], + indirect=True, +) +@pytest.mark.usefixtures("mock_session") +async def test_motion_detector2_smart_sensitivity( + hass: HomeAssistant, + mock_session: MagicMock, + mock_config_entry: MockConfigEntry, +) -> None: + """A Motion Detector 2's automatic sensitivity is exposed and controllable.""" + await setup_integration(hass, mock_config_entry) + device = mock_session.device_helper.motion_detectors2[0] + + state = hass.states.get("switch.motion_detector_automatic_sensitivity") + assert state is not None + assert state.state == "off" + + await hass.services.async_call( + SWITCH_DOMAIN, + SERVICE_TURN_ON, + {ATTR_ENTITY_ID: "switch.motion_detector_automatic_sensitivity"}, + blocking=True, + ) + assert device.smart_sensitivity_enabled is True + + await hass.services.async_call( + SWITCH_DOMAIN, + SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: "switch.motion_detector_automatic_sensitivity"}, + blocking=True, + ) + assert device.smart_sensitivity_enabled is False + + +@pytest.mark.parametrize( + "device_buckets", + [ + { + "motion_detectors2": [ + motion_detector2_device(supports_smart_sensitivity=False) + ] + } + ], + indirect=True, +) +@pytest.mark.usefixtures("mock_session") +async def test_motion_detector2_no_smart_sensitivity_support( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, +) -> None: + """No switch is created for a Motion Detector 2 without smart-sensitivity support.""" + await setup_integration(hass, mock_config_entry) + + assert hass.states.get("switch.motion_detector_automatic_sensitivity") is None