Skip to content

Commit 6b79aa7

Browse files
authored
Use Entity Description in Shelly cover platform (home-assistant#154085)
1 parent f6fb4c8 commit 6b79aa7

File tree

1 file changed

+64
-21
lines changed

1 file changed

+64
-21
lines changed

homeassistant/components/shelly/cover.py

Lines changed: 64 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from __future__ import annotations
44

55
import asyncio
6+
from dataclasses import dataclass
67
from typing import Any, cast
78

89
from aioshelly.block_device import Block
@@ -13,19 +14,50 @@
1314
ATTR_TILT_POSITION,
1415
CoverDeviceClass,
1516
CoverEntity,
17+
CoverEntityDescription,
1618
CoverEntityFeature,
1719
)
1820
from homeassistant.core import HomeAssistant, callback
1921
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
2022

2123
from .const import RPC_COVER_UPDATE_TIME_SEC
2224
from .coordinator import ShellyBlockCoordinator, ShellyConfigEntry, ShellyRpcCoordinator
23-
from .entity import ShellyBlockEntity, ShellyRpcEntity
24-
from .utils import get_device_entry_gen, get_rpc_key_ids
25+
from .entity import (
26+
BlockEntityDescription,
27+
RpcEntityDescription,
28+
ShellyBlockAttributeEntity,
29+
ShellyRpcAttributeEntity,
30+
async_setup_entry_attribute_entities,
31+
async_setup_entry_rpc,
32+
)
33+
from .utils import get_device_entry_gen
2534

2635
PARALLEL_UPDATES = 0
2736

2837

38+
@dataclass(frozen=True, kw_only=True)
39+
class BlockCoverDescription(BlockEntityDescription, CoverEntityDescription):
40+
"""Class to describe a BLOCK cover."""
41+
42+
43+
@dataclass(frozen=True, kw_only=True)
44+
class RpcCoverDescription(RpcEntityDescription, CoverEntityDescription):
45+
"""Class to describe a RPC cover."""
46+
47+
48+
BLOCK_COVERS = {
49+
("roller", "roller"): BlockCoverDescription(
50+
key="roller|roller",
51+
)
52+
}
53+
54+
RPC_COVERS = {
55+
"cover": RpcCoverDescription(
56+
key="cover",
57+
),
58+
}
59+
60+
2961
async def async_setup_entry(
3062
hass: HomeAssistant,
3163
config_entry: ShellyConfigEntry,
@@ -46,13 +78,11 @@ def async_setup_block_entry(
4678
) -> None:
4779
"""Set up cover for device."""
4880
coordinator = config_entry.runtime_data.block
49-
assert coordinator and coordinator.device.blocks
50-
blocks = [block for block in coordinator.device.blocks if block.type == "roller"]
51-
52-
if not blocks:
53-
return
81+
assert coordinator
5482

55-
async_add_entities(BlockShellyCover(coordinator, block) for block in blocks)
83+
async_setup_entry_attribute_entities(
84+
hass, config_entry, async_add_entities, BLOCK_COVERS, BlockShellyCover
85+
)
5686

5787

5888
@callback
@@ -64,26 +94,32 @@ def async_setup_rpc_entry(
6494
"""Set up entities for RPC device."""
6595
coordinator = config_entry.runtime_data.rpc
6696
assert coordinator
67-
cover_key_ids = get_rpc_key_ids(coordinator.device.status, "cover")
68-
69-
if not cover_key_ids:
70-
return
7197

72-
async_add_entities(RpcShellyCover(coordinator, id_) for id_ in cover_key_ids)
98+
async_setup_entry_rpc(
99+
hass, config_entry, async_add_entities, RPC_COVERS, RpcShellyCover
100+
)
73101

74102

75-
class BlockShellyCover(ShellyBlockEntity, CoverEntity):
103+
class BlockShellyCover(ShellyBlockAttributeEntity, CoverEntity):
76104
"""Entity that controls a cover on block based Shelly devices."""
77105

106+
entity_description: BlockCoverDescription
78107
_attr_device_class = CoverDeviceClass.SHUTTER
79108
_attr_supported_features: CoverEntityFeature = (
80109
CoverEntityFeature.OPEN | CoverEntityFeature.CLOSE | CoverEntityFeature.STOP
81110
)
82111

83-
def __init__(self, coordinator: ShellyBlockCoordinator, block: Block) -> None:
112+
def __init__(
113+
self,
114+
coordinator: ShellyBlockCoordinator,
115+
block: Block,
116+
attribute: str,
117+
description: BlockCoverDescription,
118+
) -> None:
84119
"""Initialize block cover."""
85-
super().__init__(coordinator, block)
120+
super().__init__(coordinator, block, attribute, description)
86121
self.control_result: dict[str, Any] | None = None
122+
self._attr_unique_id: str = f"{coordinator.mac}-{block.description}"
87123
if self.coordinator.device.settings["rollers"][0]["positioning"]:
88124
self._attr_supported_features |= CoverEntityFeature.SET_POSITION
89125

@@ -148,22 +184,29 @@ def _update_callback(self) -> None:
148184
super()._update_callback()
149185

150186

151-
class RpcShellyCover(ShellyRpcEntity, CoverEntity):
187+
class RpcShellyCover(ShellyRpcAttributeEntity, CoverEntity):
152188
"""Entity that controls a cover on RPC based Shelly devices."""
153189

190+
entity_description: RpcCoverDescription
154191
_attr_device_class = CoverDeviceClass.SHUTTER
155192
_attr_supported_features: CoverEntityFeature = (
156193
CoverEntityFeature.OPEN | CoverEntityFeature.CLOSE | CoverEntityFeature.STOP
157194
)
158195

159-
def __init__(self, coordinator: ShellyRpcCoordinator, id_: int) -> None:
196+
def __init__(
197+
self,
198+
coordinator: ShellyRpcCoordinator,
199+
key: str,
200+
attribute: str,
201+
description: RpcCoverDescription,
202+
) -> None:
160203
"""Initialize rpc cover."""
161-
super().__init__(coordinator, f"cover:{id_}")
162-
self._id = id_
204+
super().__init__(coordinator, key, attribute, description)
205+
self._attr_unique_id: str = f"{coordinator.mac}-{key}"
163206
self._update_task: asyncio.Task | None = None
164207
if self.status["pos_control"]:
165208
self._attr_supported_features |= CoverEntityFeature.SET_POSITION
166-
if coordinator.device.config[f"cover:{id_}"].get("slat", {}).get("enable"):
209+
if coordinator.device.config[key].get("slat", {}).get("enable"):
167210
self._attr_supported_features |= (
168211
CoverEntityFeature.OPEN_TILT
169212
| CoverEntityFeature.CLOSE_TILT

0 commit comments

Comments
 (0)