diff --git a/homeassistant/components/bosch_shc/strings.json b/homeassistant/components/bosch_shc/strings.json index 7dac8015b548..f5e4cc400c81 100644 --- a/homeassistant/components/bosch_shc/strings.json +++ b/homeassistant/components/bosch_shc/strings.json @@ -101,6 +101,9 @@ "child_lock": { "name": "Child lock" }, + "pet_immunity_enabled": { + "name": "Pet immunity" + }, "routing": { "name": "Range extension" } diff --git a/homeassistant/components/bosch_shc/switch.py b/homeassistant/components/bosch_shc/switch.py index 34cc500cd605..6ffd56be5220 100644 --- a/homeassistant/components/bosch_shc/switch.py +++ b/homeassistant/components/bosch_shc/switch.py @@ -108,6 +108,15 @@ SWITCH_TYPES: dict[str, SHCSwitchEntityDescription] = { on_value=BypassService.State.BYPASS_ACTIVE, should_poll=False, ), + "pet_immunity_enabled": SHCSwitchEntityDescription( + key="pet_immunity_enabled", + translation_key="pet_immunity_enabled", + device_class=SwitchDeviceClass.SWITCH, + entity_category=EntityCategory.CONFIG, + on_key="pet_immunity_enabled", + on_value=True, + should_poll=False, + ), } @@ -257,6 +266,18 @@ async def async_setup_entry( for switch in session.device_helper.shutter_contacts2 ) + entities.extend( + SHCSwitch( + hass=hass, + device=switch, + parent_id=shc_info.unique_id, + entry_id=config_entry.entry_id, + description=SWITCH_TYPES["pet_immunity_enabled"], + unique_id_suffix="pet_immunity", + ) + for switch in session.device_helper.motion_detectors2 + ) + async_add_entities(entities) diff --git a/tests/components/bosch_shc/conftest.py b/tests/components/bosch_shc/conftest.py index c12836b1ebbd..1fc833076608 100644 --- a/tests/components/bosch_shc/conftest.py +++ b/tests/components/bosch_shc/conftest.py @@ -14,6 +14,7 @@ from boschshcpy import ( SHCLightSwitchBSM, SHCMicromoduleBlinds, SHCMicromoduleRelay, + SHCMotionDetector2, SHCPresenceSimulationSystem, SHCShutterContact2, SHCShutterControl, @@ -73,6 +74,7 @@ _EMPTY_DEVICE_BUCKETS: dict[str, Any] = { "micromodule_relays", "micromodule_shutter_controls", "motion_detectors", + "motion_detectors2", "roomthermostats", "shutter_contacts", "shutter_contacts2", @@ -332,3 +334,23 @@ def shutter_contact2_device( device.bypass = bypass device.bypass_infinite = bypass_infinite return device + + +def motion_detector2_device( + device_id: str = "hdm:ZigBee:motiondetector1", + name: str = "Motion Detector", + pet_immunity_enabled: bool = False, +) -> SHCMotionDetector2: + """Build a minimal device double for the motion_detectors2 bucket.""" + device = create_autospec(SHCMotionDetector2, instance=True, spec_set=True) + device.name = name + device.id = device_id + device.root_device_id = "test-mac" + device.serial = f"serial-{device_id}" + device.manufacturer = "Bosch" + device.device_model = "MD2" + device.device_services = [] + device.deleted = False + device.status = "AVAILABLE" + device.pet_immunity_enabled = pet_immunity_enabled + return device diff --git a/tests/components/bosch_shc/test_switch.py b/tests/components/bosch_shc/test_switch.py index 53ced8857858..d21f63c378e4 100644 --- a/tests/components/bosch_shc/test_switch.py +++ b/tests/components/bosch_shc/test_switch.py @@ -19,6 +19,7 @@ from homeassistant.helpers import entity_registry as er from .conftest import ( light_switch_bsm_device, micromodule_relay_device, + motion_detector2_device, presence_simulation_system_device, setup_integration, shutter_contact2_device, @@ -317,3 +318,39 @@ async def test_shutter_contact2_bypass_unique_id( assert bypass_entry is not None assert bypass_infinite_entry is not None assert bypass_entry.unique_id != bypass_infinite_entry.unique_id + + +@pytest.mark.parametrize( + "device_buckets", + [{"motion_detectors2": [motion_detector2_device(pet_immunity_enabled=False)]}], + indirect=True, +) +@pytest.mark.usefixtures("mock_session") +async def test_motion_detector2_pet_immunity( + hass: HomeAssistant, + mock_session: MagicMock, + mock_config_entry: MockConfigEntry, +) -> None: + """A Motion Detector 2's pet immunity setting 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_pet_immunity") + 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_pet_immunity"}, + blocking=True, + ) + assert device.pet_immunity_enabled is True + + await hass.services.async_call( + SWITCH_DOMAIN, + SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: "switch.motion_detector_pet_immunity"}, + blocking=True, + ) + assert device.pet_immunity_enabled is False