Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 71 additions & 3 deletions homeassistant/components/bosch_shc/cover.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

from typing import TYPE_CHECKING, Any, override

from boschshcpy import SHCShutterControl, ShutterControlService
from boschshcpy import SHCMicromoduleBlinds, SHCShutterControl, ShutterControlService

from homeassistant.components.cover import (
ATTR_POSITION,
ATTR_TILT_POSITION,
CoverDeviceClass,
CoverEntity,
CoverEntityFeature,
Expand Down Expand Up @@ -38,15 +39,26 @@ async def async_setup_entry(
parent_id=shc_info.unique_id,
entry_id=config_entry.entry_id,
)
for cover in session.device_helper.shutter_controls
for cover in (
*session.device_helper.shutter_controls,
*session.device_helper.micromodule_shutter_controls,
)
)
async_add_entities(
BlindsControlCover(
hass=hass,
device=blind,
parent_id=shc_info.unique_id,
entry_id=config_entry.entry_id,
)
for blind in session.device_helper.micromodule_blinds
)


class ShutterControlCover(SHCEntity, CoverEntity):
"""Representation of a SHC shutter control device."""

_attr_name = None
_attr_device_class = CoverDeviceClass.SHUTTER
_device: SHCShutterControl
_attr_supported_features = (
CoverEntityFeature.OPEN
Expand All @@ -55,6 +67,14 @@ class ShutterControlCover(SHCEntity, CoverEntity):
| CoverEntityFeature.SET_POSITION
)

@property
@override
def device_class(self) -> CoverDeviceClass:
"""Return the device class."""
if self._device.device_model == "MICROMODULE_AWNING":
return CoverDeviceClass.AWNING
return CoverDeviceClass.SHUTTER

@property
@override
def current_cover_position(self) -> int:
Expand Down Expand Up @@ -99,3 +119,51 @@ def set_cover_position(self, **kwargs: Any) -> None:
"""Move the cover to a specific position."""
position = kwargs[ATTR_POSITION]
self._device.level = position / 100.0


class BlindsControlCover(ShutterControlCover):
"""Representation of a SHC micromodule blinds cover device."""

_device: SHCMicromoduleBlinds
_attr_supported_features = (
CoverEntityFeature.OPEN
| CoverEntityFeature.CLOSE
| CoverEntityFeature.STOP
| CoverEntityFeature.SET_POSITION
| CoverEntityFeature.OPEN_TILT
| CoverEntityFeature.CLOSE_TILT
| CoverEntityFeature.SET_TILT_POSITION
)

@property
@override
def device_class(self) -> CoverDeviceClass:
"""Return the device class."""
return CoverDeviceClass.BLIND

@override
def stop_cover(self, **kwargs: Any) -> None:
"""Stop the cover."""
self._device.stop_blinds()

@property
@override
def current_cover_tilt_position(self) -> int:
"""Return the current cover tilt position."""
return round((1.0 - self._device.current_angle) * 100.0)

@override
def open_cover_tilt(self, **kwargs: Any) -> None:
"""Open the cover tilt."""
self._device.target_angle = 0.0

@override
def close_cover_tilt(self, **kwargs: Any) -> None:
"""Close the cover tilt."""
self._device.target_angle = 1.0

@override
def set_cover_tilt_position(self, **kwargs: Any) -> None:
"""Move the cover tilt to a specific position."""
tilt_position = kwargs[ATTR_TILT_POSITION]
self._device.target_angle = 1.0 - (tilt_position / 100.0)
5 changes: 4 additions & 1 deletion homeassistant/components/bosch_shc/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from boschshcpy import (
SHCLightSwitchBSM,
SHCMicromoduleShutterControl,
SHCSmartPlug,
SHCSmartPlugCompact,
SHCThermostat,
Expand Down Expand Up @@ -47,7 +48,7 @@ class SHCSensorEntityDescription[_DeviceT: SHCDevice](SensorEntityDescription):
attributes_fn: Callable[[_DeviceT], dict[str, Any]] | None = None


_PowerMeterDevice = SHCSmartPlug | SHCLightSwitchBSM
_PowerMeterDevice = SHCSmartPlug | SHCLightSwitchBSM | SHCMicromoduleShutterControl

TEMPERATURE_SENSOR = "temperature"
HUMIDITY_SENSOR = "humidity"
Expand Down Expand Up @@ -263,6 +264,8 @@ async def async_setup_entry(
power_meter_devices: list[_PowerMeterDevice] = [
*session.device_helper.smart_plugs,
*session.device_helper.light_switches_bsm,
*session.device_helper.micromodule_shutter_controls,
*session.device_helper.micromodule_blinds,
]
entities.extend(
SHCSensor(
Expand Down
58 changes: 57 additions & 1 deletion tests/components/bosch_shc/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@
from typing import Any
from unittest.mock import MagicMock, create_autospec, patch

from boschshcpy import BatteryLevelService, SHCBatteryDevice
from boschshcpy import (
BatteryLevelService,
SHCBatteryDevice,
SHCMicromoduleBlinds,
SHCShutterControl,
ShutterControlService,
)
import pytest

from homeassistant.components.bosch_shc.const import (
Expand Down Expand Up @@ -43,9 +49,12 @@ def mock_config_entry() -> MockConfigEntry:
_EMPTY_DEVICE_BUCKETS: dict[str, list[Any]] = {
bucket: []
for bucket in (
"micromodule_blinds",
"micromodule_shutter_controls",
"motion_detectors",
"shutter_contacts",
"shutter_contacts2",
"shutter_controls",
"smoke_detectors",
"thermostats",
"twinguards",
Expand Down Expand Up @@ -112,3 +121,50 @@ def battery_only_device(
device.status = "AVAILABLE"
device.deleted = False
return device


def shutter_control_device(
device_id: str = "hdm:ZigBee:shutter1",
name: str = "Shutter",
device_model: str = "BBL",
level: float = 1.0,
operation_state: ShutterControlService.State = ShutterControlService.State.STOPPED,
) -> SHCShutterControl:
"""Build a minimal device double for the shutter_controls/micromodule_shutter_controls buckets."""
device = create_autospec(SHCShutterControl, 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 = device_model
device.device_services = []
device.deleted = False
device.status = "AVAILABLE"
device.level = level
device.operation_state = operation_state
return device


def micromodule_blinds_device(
device_id: str = "hdm:ZigBee:blinds1",
name: str = "Blinds",
level: float = 1.0,
current_angle: float = 0.0,
operation_state: ShutterControlService.State = ShutterControlService.State.STOPPED,
) -> SHCMicromoduleBlinds:
"""Build a minimal device double for the micromodule_blinds bucket."""
device = create_autospec(SHCMicromoduleBlinds, 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 = "MICROMODULE_BLINDS"
device.device_services = []
device.deleted = False
device.status = "AVAILABLE"
device.level = level
device.current_angle = current_angle
device.operation_state = operation_state
return device
Loading
Loading