bosch_shc: add Thermostat silent mode switch entity (#183062)

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Thomas
2026-09-25 20:58:59 +01:00
committed by GitHub
co-authored by Claude Sonnet 5
parent b8d535cdcf
commit 454e13dbfb
4 changed files with 93 additions and 1 deletions
@@ -119,6 +119,9 @@
"routing": {
"name": "Range extension"
},
"silent_mode": {
"name": "Whisper mode"
},
"smart_sensitivity_enabled": {
"name": "Automatic sensitivity"
},
@@ -11,6 +11,7 @@ from boschshcpy import (
PrivacyModeService,
SHCShutterContact2,
SHCSmartPlug,
SilentModeService,
ThermostatService,
)
from boschshcpy.device import SHCDevice
@@ -161,6 +162,15 @@ SWITCH_TYPES: dict[str, SHCSwitchEntityDescription] = {
on_value=True,
should_poll=False,
),
"silent_mode": SHCSwitchEntityDescription(
key="silent_mode",
translation_key="silent_mode",
device_class=SwitchDeviceClass.SWITCH,
entity_category=EntityCategory.CONFIG,
on_key="silentmode",
on_value=SilentModeService.State.MODE_SILENT,
should_poll=False,
),
"smart_sensitivity_enabled": SHCSwitchEntityDescription(
key="smart_sensitivity_enabled",
translation_key="smart_sensitivity_enabled",
@@ -355,6 +365,19 @@ async def async_setup_entry(
if switch.supports_intrusion_alarm
)
entities.extend(
SHCSwitch(
hass=hass,
device=switch,
parent_id=shc_info.unique_id,
entry_id=config_entry.entry_id,
description=SWITCH_TYPES["silent_mode"],
unique_id_suffix="silent_mode",
)
for switch in session.device_helper.thermostats
if switch.supports_silentmode
)
entities.extend(
SHCSwitch(
hass=hass,
+5
View File
@@ -27,6 +27,7 @@ from boschshcpy import (
SHCTwinguard,
ShutterContactService,
ShutterControlService,
SilentModeService,
ThermostatService,
)
from boschshcpy.services_impl import (
@@ -260,6 +261,8 @@ def thermostat_device(
child_lock: ThermostatService.State = ThermostatService.State.OFF,
position: int = 50,
valvestate: ValveTappetService.State = ValveTappetService.State.VALVE_ADAPTION_SUCCESSFUL,
supports_silentmode: bool = False,
silentmode: SilentModeService.State = SilentModeService.State.MODE_NORMAL,
) -> SHCThermostat:
"""Build a minimal device double for the thermostats/roomthermostats/wallthermostats buckets."""
device = create_autospec(SHCThermostat, instance=True, spec_set=True)
@@ -275,6 +278,8 @@ def thermostat_device(
device.child_lock = child_lock
device.position = position
device.valvestate = valvestate
device.supports_silentmode = supports_silentmode
device.silentmode = silentmode
return device
+62 -1
View File
@@ -3,7 +3,7 @@
from collections.abc import Generator
from unittest.mock import MagicMock, patch
from boschshcpy import BypassService, ThermostatService
from boschshcpy import BypassService, SilentModeService, ThermostatService
import pytest
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
@@ -77,6 +77,67 @@ async def test_thermostat_child_lock(
assert device.child_lock is False
@pytest.mark.parametrize(
"device_buckets",
[
{
"thermostats": [
thermostat_device(
supports_silentmode=True,
silentmode=SilentModeService.State.MODE_NORMAL,
)
]
}
],
indirect=True,
)
@pytest.mark.usefixtures("mock_session")
async def test_thermostat_silent_mode(
hass: HomeAssistant,
mock_session: MagicMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""A thermostat's silent mode is exposed and controllable as a switch."""
await setup_integration(hass, mock_config_entry)
device = mock_session.device_helper.thermostats[0]
state = hass.states.get("switch.thermostat_whisper_mode")
assert state is not None
assert state.state == "off"
await hass.services.async_call(
SWITCH_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: "switch.thermostat_whisper_mode"},
blocking=True,
)
assert device.silentmode is True
await hass.services.async_call(
SWITCH_DOMAIN,
SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: "switch.thermostat_whisper_mode"},
blocking=True,
)
assert device.silentmode is False
@pytest.mark.parametrize(
"device_buckets",
[{"thermostats": [thermostat_device(supports_silentmode=False)]}],
indirect=True,
)
@pytest.mark.usefixtures("mock_session")
async def test_thermostat_no_silent_mode_support(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
) -> None:
"""No switch is created for a thermostat without silent-mode support."""
await setup_integration(hass, mock_config_entry)
assert hass.states.get("switch.thermostat_whisper_mode") is None
@pytest.mark.parametrize(
"device_buckets",
[{"micromodule_relays": [micromodule_relay_device(child_lock=False)]}],