Files
core/homeassistant/components/switchbot/switch.py
2025-09-16 15:59:13 +02:00

129 lines
4.2 KiB
Python

"""Support for Switchbot bot."""
from __future__ import annotations
import logging
from typing import Any
import switchbot
from homeassistant.components.switch import SwitchDeviceClass, SwitchEntity
from homeassistant.const import STATE_ON
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.restore_state import RestoreEntity
from .const import DOMAIN
from .coordinator import SwitchbotConfigEntry, SwitchbotDataUpdateCoordinator
from .entity import SwitchbotSwitchedEntity, exception_handler
PARALLEL_UPDATES = 0
_LOGGER = logging.getLogger(__name__)
async def async_setup_entry(
hass: HomeAssistant,
entry: SwitchbotConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up Switchbot based on a config entry."""
coordinator = entry.runtime_data
if isinstance(coordinator.device, switchbot.SwitchbotRelaySwitch2PM):
entries = [
SwitchbotMultiChannelSwitch(coordinator, channel)
for channel in range(1, coordinator.device.channel + 1)
]
async_add_entities(entries)
else:
async_add_entities([SwitchBotSwitch(coordinator)])
class SwitchBotSwitch(SwitchbotSwitchedEntity, SwitchEntity, RestoreEntity):
"""Representation of a Switchbot switch."""
_attr_device_class = SwitchDeviceClass.SWITCH
_attr_translation_key = "bot"
_attr_name = None
_device: switchbot.Switchbot
def __init__(self, coordinator: SwitchbotDataUpdateCoordinator) -> None:
"""Initialize the Switchbot."""
super().__init__(coordinator)
self._attr_is_on = False
async def async_added_to_hass(self) -> None:
"""Run when entity about to be added."""
await super().async_added_to_hass()
if not (last_state := await self.async_get_last_state()):
return
self._attr_is_on = last_state.state == STATE_ON
self._last_run_success = last_state.attributes.get("last_run_success")
@property
def assumed_state(self) -> bool:
"""Return true if unable to access real state of entity."""
return not self._device.switch_mode()
@property
def is_on(self) -> bool | None:
"""Return true if device is on."""
if not self._device.switch_mode():
return self._attr_is_on
return self._device.is_on()
@property
def extra_state_attributes(self) -> dict[str, Any]:
"""Return the state attributes."""
return {
**super().extra_state_attributes,
"switch_mode": self._device.switch_mode(),
}
class SwitchbotMultiChannelSwitch(SwitchbotSwitchedEntity, SwitchEntity):
"""Representation of a Switchbot multi-channel switch."""
_attr_device_class = SwitchDeviceClass.SWITCH
_device: switchbot.Switchbot
_attr_name = None
def __init__(
self, coordinator: SwitchbotDataUpdateCoordinator, channel: int
) -> None:
"""Initialize the Switchbot."""
super().__init__(coordinator)
self._channel = channel
self._attr_unique_id = f"{coordinator.base_unique_id}-{channel}"
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, f"{coordinator.base_unique_id}-channel-{channel}")},
manufacturer="SwitchBot",
model_id="RelaySwitch2PM",
name=f"{coordinator.device_name} Channel {channel}",
)
@property
def is_on(self) -> bool | None:
"""Return true if device is on."""
return self._device.is_on(self._channel)
@exception_handler
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn device on."""
_LOGGER.debug(
"Turn Switchbot device on %s, channel %d", self._address, self._channel
)
await self._device.turn_on(self._channel)
self.async_write_ha_state()
@exception_handler
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn device off."""
_LOGGER.debug(
"Turn Switchbot device off %s, channel %d", self._address, self._channel
)
await self._device.turn_off(self._channel)
self.async_write_ha_state()