mirror of
https://github.com/home-assistant/core.git
synced 2025-11-10 11:29:46 +00:00
232 lines
8.6 KiB
Python
232 lines
8.6 KiB
Python
"""Support for the Switchbot BlindTilt, Curtain, Curtain3, RollerShade as Cover."""
|
|
|
|
import asyncio
|
|
from typing import Any
|
|
|
|
from switchbot_api import (
|
|
BlindTiltCommands,
|
|
CommonCommands,
|
|
CurtainCommands,
|
|
Device,
|
|
Remote,
|
|
RollerShadeCommands,
|
|
SwitchBotAPI,
|
|
)
|
|
|
|
from homeassistant.components.cover import (
|
|
CoverDeviceClass,
|
|
CoverEntity,
|
|
CoverEntityFeature,
|
|
)
|
|
from homeassistant.config_entries import ConfigEntry
|
|
from homeassistant.core import HomeAssistant, callback
|
|
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
|
|
|
from . import SwitchbotCloudData, SwitchBotCoordinator
|
|
from .const import COVER_ENTITY_AFTER_COMMAND_REFRESH, DOMAIN
|
|
from .entity import SwitchBotCloudEntity
|
|
|
|
|
|
async def async_setup_entry(
|
|
hass: HomeAssistant,
|
|
config: ConfigEntry,
|
|
async_add_entities: AddConfigEntryEntitiesCallback,
|
|
) -> None:
|
|
"""Set up SwitchBot Cloud entry."""
|
|
data: SwitchbotCloudData = hass.data[DOMAIN][config.entry_id]
|
|
async_add_entities(
|
|
_async_make_entity(data.api, device, coordinator)
|
|
for device, coordinator in data.devices.covers
|
|
)
|
|
|
|
|
|
class SwitchBotCloudCover(SwitchBotCloudEntity, CoverEntity):
|
|
"""Representation of a SwitchBot Cover."""
|
|
|
|
_attr_name = None
|
|
_attr_is_closed: bool | None = None
|
|
|
|
def _set_attributes(self) -> None:
|
|
if self.coordinator.data is None:
|
|
return
|
|
position: int | None = self.coordinator.data.get("slidePosition")
|
|
if position is None:
|
|
return
|
|
self._attr_current_cover_position = 100 - position
|
|
self._attr_current_cover_tilt_position = 100 - position
|
|
self._attr_is_closed = position == 100
|
|
|
|
|
|
class SwitchBotCloudCoverCurtain(SwitchBotCloudCover):
|
|
"""Representation of a SwitchBot Curtain & Curtain3."""
|
|
|
|
_attr_device_class = CoverDeviceClass.CURTAIN
|
|
_attr_supported_features: CoverEntityFeature = (
|
|
CoverEntityFeature.OPEN
|
|
| CoverEntityFeature.CLOSE
|
|
| CoverEntityFeature.STOP
|
|
| CoverEntityFeature.SET_POSITION
|
|
)
|
|
|
|
async def async_open_cover(self, **kwargs: Any) -> None:
|
|
"""Open the cover."""
|
|
await self.send_api_command(CommonCommands.ON)
|
|
await asyncio.sleep(COVER_ENTITY_AFTER_COMMAND_REFRESH)
|
|
await self.coordinator.async_request_refresh()
|
|
|
|
async def async_close_cover(self, **kwargs: Any) -> None:
|
|
"""Close the cover."""
|
|
await self.send_api_command(CommonCommands.OFF)
|
|
await asyncio.sleep(COVER_ENTITY_AFTER_COMMAND_REFRESH)
|
|
await self.coordinator.async_request_refresh()
|
|
|
|
async def async_set_cover_position(self, **kwargs: Any) -> None:
|
|
"""Move the cover to a specific position."""
|
|
position: int | None = kwargs.get("position")
|
|
if position is not None:
|
|
await self.send_api_command(
|
|
CurtainCommands.SET_POSITION,
|
|
parameters=f"{0},ff,{100 - position}",
|
|
)
|
|
await asyncio.sleep(COVER_ENTITY_AFTER_COMMAND_REFRESH)
|
|
await self.coordinator.async_request_refresh()
|
|
|
|
async def async_stop_cover(self, **kwargs: Any) -> None:
|
|
"""Stop the cover."""
|
|
await self.send_api_command(CurtainCommands.PAUSE)
|
|
await self.coordinator.async_request_refresh()
|
|
|
|
|
|
class SwitchBotCloudCoverRollerShade(SwitchBotCloudCover):
|
|
"""Representation of a SwitchBot RollerShade."""
|
|
|
|
_attr_device_class = CoverDeviceClass.SHADE
|
|
_attr_supported_features: CoverEntityFeature = (
|
|
CoverEntityFeature.SET_POSITION
|
|
| CoverEntityFeature.OPEN
|
|
| CoverEntityFeature.CLOSE
|
|
)
|
|
|
|
async def async_open_cover(self, **kwargs: Any) -> None:
|
|
"""Open the cover."""
|
|
await self.send_api_command(RollerShadeCommands.SET_POSITION, parameters=0)
|
|
await asyncio.sleep(COVER_ENTITY_AFTER_COMMAND_REFRESH)
|
|
await self.coordinator.async_request_refresh()
|
|
|
|
async def async_close_cover(self, **kwargs: Any) -> None:
|
|
"""Close the cover."""
|
|
await self.send_api_command(RollerShadeCommands.SET_POSITION, parameters=100)
|
|
await asyncio.sleep(COVER_ENTITY_AFTER_COMMAND_REFRESH)
|
|
await self.coordinator.async_request_refresh()
|
|
|
|
async def async_set_cover_position(self, **kwargs: Any) -> None:
|
|
"""Move the cover to a specific position."""
|
|
position: int | None = kwargs.get("position")
|
|
if position is not None:
|
|
await self.send_api_command(
|
|
RollerShadeCommands.SET_POSITION, parameters=(100 - position)
|
|
)
|
|
await asyncio.sleep(COVER_ENTITY_AFTER_COMMAND_REFRESH)
|
|
await self.coordinator.async_request_refresh()
|
|
|
|
|
|
class SwitchBotCloudCoverBlindTilt(SwitchBotCloudCover):
|
|
"""Representation of a SwitchBot Blind Tilt."""
|
|
|
|
_attr_direction: str | None = None
|
|
_attr_device_class = CoverDeviceClass.BLIND
|
|
_attr_supported_features: CoverEntityFeature = (
|
|
CoverEntityFeature.SET_TILT_POSITION
|
|
| CoverEntityFeature.OPEN_TILT
|
|
| CoverEntityFeature.CLOSE_TILT
|
|
)
|
|
|
|
def _set_attributes(self) -> None:
|
|
if self.coordinator.data is None:
|
|
return
|
|
position: int | None = self.coordinator.data.get("slidePosition")
|
|
if position is None:
|
|
return
|
|
self._attr_is_closed = position in [0, 100]
|
|
if position > 50:
|
|
percent = 100 - ((position - 50) * 2)
|
|
else:
|
|
percent = 100 - (50 - position) * 2
|
|
self._attr_current_cover_position = percent
|
|
self._attr_current_cover_tilt_position = percent
|
|
direction = self.coordinator.data.get("direction")
|
|
self._attr_direction = direction.lower() if direction else None
|
|
|
|
async def async_set_cover_tilt_position(self, **kwargs: Any) -> None:
|
|
"""Move the cover to a specific position."""
|
|
percent: int | None = kwargs.get("tilt_position")
|
|
if percent is not None:
|
|
await self.send_api_command(
|
|
BlindTiltCommands.SET_POSITION,
|
|
parameters=f"{self._attr_direction};{percent}",
|
|
)
|
|
await asyncio.sleep(COVER_ENTITY_AFTER_COMMAND_REFRESH)
|
|
await self.coordinator.async_request_refresh()
|
|
|
|
async def async_open_cover_tilt(self, **kwargs: Any) -> None:
|
|
"""Open the cover."""
|
|
await self.send_api_command(BlindTiltCommands.FULLY_OPEN)
|
|
await asyncio.sleep(COVER_ENTITY_AFTER_COMMAND_REFRESH)
|
|
await self.coordinator.async_request_refresh()
|
|
|
|
async def async_close_cover_tilt(self, **kwargs: Any) -> None:
|
|
"""Close the cover."""
|
|
if self._attr_direction is not None:
|
|
if "up" in self._attr_direction:
|
|
await self.send_api_command(BlindTiltCommands.CLOSE_UP)
|
|
else:
|
|
await self.send_api_command(BlindTiltCommands.CLOSE_DOWN)
|
|
await asyncio.sleep(COVER_ENTITY_AFTER_COMMAND_REFRESH)
|
|
await self.coordinator.async_request_refresh()
|
|
|
|
|
|
class SwitchBotCloudCoverGarageDoorOpener(SwitchBotCloudCover):
|
|
"""Representation of a SwitchBot Garage Door Opener."""
|
|
|
|
_attr_device_class = CoverDeviceClass.GARAGE
|
|
_attr_supported_features: CoverEntityFeature = (
|
|
CoverEntityFeature.OPEN | CoverEntityFeature.CLOSE
|
|
)
|
|
|
|
def _set_attributes(self) -> None:
|
|
if self.coordinator.data is None:
|
|
return
|
|
door_status: int | None = self.coordinator.data.get("doorStatus")
|
|
self._attr_is_closed = None if door_status is None else door_status == 1
|
|
|
|
async def async_open_cover(self, **kwargs: Any) -> None:
|
|
"""Open the cover."""
|
|
await self.send_api_command(CommonCommands.ON)
|
|
await asyncio.sleep(COVER_ENTITY_AFTER_COMMAND_REFRESH)
|
|
await self.coordinator.async_request_refresh()
|
|
|
|
async def async_close_cover(self, **kwargs: Any) -> None:
|
|
"""Close the cover."""
|
|
await self.send_api_command(CommonCommands.OFF)
|
|
await asyncio.sleep(COVER_ENTITY_AFTER_COMMAND_REFRESH)
|
|
await self.coordinator.async_request_refresh()
|
|
|
|
|
|
@callback
|
|
def _async_make_entity(
|
|
api: SwitchBotAPI, device: Device | Remote, coordinator: SwitchBotCoordinator
|
|
) -> (
|
|
SwitchBotCloudCoverBlindTilt
|
|
| SwitchBotCloudCoverRollerShade
|
|
| SwitchBotCloudCoverCurtain
|
|
| SwitchBotCloudCoverGarageDoorOpener
|
|
):
|
|
"""Make a SwitchBotCloudCover device."""
|
|
if device.device_type == "Blind Tilt":
|
|
return SwitchBotCloudCoverBlindTilt(api, device, coordinator)
|
|
if device.device_type == "Roller Shade":
|
|
return SwitchBotCloudCoverRollerShade(api, device, coordinator)
|
|
if device.device_type == "Garage Door Opener":
|
|
return SwitchBotCloudCoverGarageDoorOpener(api, device, coordinator)
|
|
return SwitchBotCloudCoverCurtain(api, device, coordinator)
|