bosch_shc: add Door/Window Contact II Plus vibration detection switch entity (#183063)

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Thomas
2026-09-25 21:00:48 +01:00
committed by GitHub
co-authored by Claude Sonnet 5
parent 454e13dbfb
commit aa7ea20b93
4 changed files with 104 additions and 0 deletions
@@ -127,6 +127,9 @@
},
"tamper_protection_enabled": {
"name": "Sabotage detection"
},
"vibration_enabled": {
"name": "Vibration detection"
}
},
"valve": {
@@ -10,6 +10,7 @@ from boschshcpy import (
PowerSwitchService,
PrivacyModeService,
SHCShutterContact2,
SHCShutterContact2Plus,
SHCSmartPlug,
SilentModeService,
ThermostatService,
@@ -180,6 +181,15 @@ SWITCH_TYPES: dict[str, SHCSwitchEntityDescription] = {
on_value=True,
should_poll=False,
),
"vibration_enabled": SHCSwitchEntityDescription(
key="vibration_enabled",
translation_key="vibration_enabled",
device_class=SwitchDeviceClass.SWITCH,
entity_category=EntityCategory.CONFIG,
on_key="enabled",
on_value=True,
should_poll=False,
),
}
@@ -329,6 +339,19 @@ 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["vibration_enabled"],
unique_id_suffix="vibration_enabled",
)
for switch in session.device_helper.shutter_contacts2
if isinstance(switch, SHCShutterContact2Plus)
)
entities.extend(
SHCSwitch(
hass=hass,
+25
View File
@@ -18,6 +18,7 @@ from boschshcpy import (
SHCPresenceSimulationSystem,
SHCShutterContact,
SHCShutterContact2,
SHCShutterContact2Plus,
SHCShutterControl,
SHCSmartPlug,
SHCSmartPlugCompact,
@@ -418,6 +419,30 @@ def shutter_contact2_device(
return device
def shutter_contact2_plus_device(
device_id: str = "hdm:ZigBee:shuttercontact1",
name: str = "Shutter contact",
bypass: BypassService.State = BypassService.State.BYPASS_INACTIVE,
bypass_infinite: bool = False,
vibration_enabled: bool = False,
) -> SHCShutterContact2Plus:
"""Build a minimal device double for a vibration-capable Door/Window Contact II Plus."""
device = create_autospec(SHCShutterContact2Plus, 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 = "SWD2_PLUS"
device.device_services = []
device.deleted = False
device.status = "AVAILABLE"
device.bypass = bypass
device.bypass_infinite = bypass_infinite
device.enabled = vibration_enabled
return device
def motion_detector2_device(
device_id: str = "hdm:ZigBee:motiondetector1",
name: str = "Motion Detector",
+53
View File
@@ -23,6 +23,7 @@ from .conftest import (
presence_simulation_system_device,
setup_integration,
shutter_contact2_device,
shutter_contact2_plus_device,
smart_plug_compact_device,
smart_plug_device,
smoke_detector_device,
@@ -385,6 +386,58 @@ async def test_shutter_contact2_bypass_unique_id(
assert bypass_entry.unique_id != bypass_infinite_entry.unique_id
@pytest.mark.parametrize(
"device_buckets",
[{"shutter_contacts2": [shutter_contact2_plus_device(vibration_enabled=False)]}],
indirect=True,
)
@pytest.mark.usefixtures("mock_session")
async def test_shutter_contact2_plus_vibration_enabled(
hass: HomeAssistant,
mock_session: MagicMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""A Door/Window Contact II Plus's vibration detection is exposed and controllable."""
await setup_integration(hass, mock_config_entry)
device = mock_session.device_helper.shutter_contacts2[0]
state = hass.states.get("switch.shutter_contact_vibration_detection")
assert state is not None
assert state.state == "off"
await hass.services.async_call(
SWITCH_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: "switch.shutter_contact_vibration_detection"},
blocking=True,
)
assert device.enabled is True
await hass.services.async_call(
SWITCH_DOMAIN,
SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: "switch.shutter_contact_vibration_detection"},
blocking=True,
)
assert device.enabled is False
@pytest.mark.parametrize(
"device_buckets",
[{"shutter_contacts2": [shutter_contact2_device()]}],
indirect=True,
)
@pytest.mark.usefixtures("mock_session")
async def test_shutter_contact2_no_vibration_enabled_support(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
) -> None:
"""No vibration switch is created for a plain (non-Plus) Door/Window Contact II."""
await setup_integration(hass, mock_config_entry)
assert hass.states.get("switch.shutter_contact_vibration_detection") is None
@pytest.mark.parametrize(
"device_buckets",
[{"motion_detectors2": [motion_detector2_device(pet_immunity_enabled=False)]}],