bosch_shc: add Outdoor Camera Gen2 privacy-mode switch entity (#183138)

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Thomas
2026-09-29 19:55:26 +02:00
committed by GitHub
co-authored by Claude Sonnet 5
parent 0c70a62aa0
commit 0aa7f15ddf
3 changed files with 85 additions and 0 deletions
@@ -86,6 +86,13 @@ SWITCH_TYPES: dict[str, SHCSwitchEntityDescription] = {
on_value=PrivacyModeService.State.DISABLED,
should_poll=True,
),
"cameraoutdoorgen2": SHCSwitchEntityDescription(
key="cameraoutdoorgen2",
device_class=SwitchDeviceClass.SWITCH,
on_key="privacymode",
on_value=PrivacyModeService.State.DISABLED,
should_poll=True,
),
"child_lock": SHCSwitchEntityDescription(
key="child_lock",
translation_key="child_lock",
@@ -309,6 +316,17 @@ async def async_setup_entry(
for switch in session.device_helper.camera_360
)
entities.extend(
SHCSwitch(
hass=hass,
device=switch,
parent_id=shc_info.unique_id,
entry_id=config_entry.entry_id,
description=SWITCH_TYPES["cameraoutdoorgen2"],
)
for switch in session.device_helper.camera_outdoor_gen2
)
entities.extend(
SHCSwitch(
hass=hass,
+23
View File
@@ -11,9 +11,11 @@ from boschshcpy import (
BypassService,
CameraLightService,
PowerSwitchService,
PrivacyModeService,
RoutingService,
SHCBatteryDevice,
SHCCameraEyes,
SHCCameraOutdoorGen2,
SHCLightSwitchBSM,
SHCMicromoduleBlinds,
SHCMicromoduleRelay,
@@ -78,6 +80,7 @@ _EMPTY_DEVICE_BUCKETS: dict[str, Any] = {
for bucket in (
"camera_360",
"camera_eyes",
"camera_outdoor_gen2",
"light_switches_bsm",
"micromodule_blinds",
"micromodule_dimmers",
@@ -185,6 +188,26 @@ def camera_eyes_device(
return device
def camera_outdoor_gen2_device(
device_id: str = "hdm:Cameras:outdoorgen2-1",
name: str = "Outdoor Camera",
privacymode: PrivacyModeService.State = PrivacyModeService.State.ENABLED,
) -> SHCCameraOutdoorGen2:
"""Build a minimal device double for the camera_outdoor_gen2 bucket."""
device = create_autospec(SHCCameraOutdoorGen2, 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 = "CAMERA_OUTDOOR_GEN2"
device.device_services = []
device.deleted = False
device.status = "AVAILABLE"
device.privacymode = privacymode
return device
def shutter_control_device(
device_id: str = "hdm:ZigBee:shutter1",
name: str = "Shutter",
+44
View File
@@ -6,6 +6,7 @@ from unittest.mock import MagicMock, patch
from boschshcpy import (
BypassService,
CameraLightService,
PrivacyModeService,
SilentModeService,
ThermostatService,
)
@@ -23,6 +24,7 @@ from homeassistant.helpers import entity_registry as er
from .conftest import (
camera_eyes_device,
camera_outdoor_gen2_device,
light_switch_bsm_device,
micromodule_relay_device,
motion_detector2_device,
@@ -1043,3 +1045,45 @@ async def test_camera_eyes_cameralight(
blocking=True,
)
assert device.cameralight is False
@pytest.mark.parametrize(
"device_buckets",
[
{
"camera_outdoor_gen2": [
camera_outdoor_gen2_device(privacymode=PrivacyModeService.State.ENABLED)
]
}
],
indirect=True,
)
@pytest.mark.usefixtures("mock_session")
async def test_camera_outdoor_gen2_privacy_mode(
hass: HomeAssistant,
mock_session: MagicMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""An Outdoor Camera Gen2's privacy mode is exposed and controllable as a switch."""
await setup_integration(hass, mock_config_entry)
device = mock_session.device_helper.camera_outdoor_gen2[0]
state = hass.states.get("switch.outdoor_camera")
assert state is not None
assert state.state == "off"
await hass.services.async_call(
SWITCH_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: "switch.outdoor_camera"},
blocking=True,
)
assert device.privacymode is True
await hass.services.async_call(
SWITCH_DOMAIN,
SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: "switch.outdoor_camera"},
blocking=True,
)
assert device.privacymode is False