Add light platform for switchbee integration (#78382)

* Added Light platform for switchbee integration

* added light to .coveragerc

* Applied code review feedback from other PR

* Fixes based on previous reviewes

* fixed small mistake

* added test coverage for light

* aligned code with other PR

* rebased

* fixes

* removed unecessary changes

* Update homeassistant/components/switchbee/light.py

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

* Update homeassistant/components/switchbee/light.py

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

* more fixes

* more fixes

* adjusting switch with the new change

* more fixes

* Update homeassistant/components/switchbee/light.py

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

* Update homeassistant/components/switchbee/light.py

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

* Update homeassistant/components/switchbee/light.py

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
This commit is contained in:
Jafar Atili 2022-09-28 17:30:33 +03:00 committed by GitHub
parent 24c26dc032
commit de3a1f444c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 179 additions and 28 deletions

View file

@ -0,0 +1,148 @@
"""Support for SwitchBee light."""
from __future__ import annotations
import logging
from typing import Any, cast
from switchbee.api import SwitchBeeDeviceOfflineError, SwitchBeeError
from switchbee.device import ApiStateCommand, DeviceType, SwitchBeeDimmer
from homeassistant.components.light import ATTR_BRIGHTNESS, ColorMode, LightEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DOMAIN
from .coordinator import SwitchBeeCoordinator
from .entity import SwitchBeeDeviceEntity
MAX_BRIGHTNESS = 255
_LOGGER = logging.getLogger(__name__)
def _hass_brightness_to_switchbee(value: int) -> int:
"""Convert hass brightness to SwitchBee."""
sb_brightness = int(100 * value / MAX_BRIGHTNESS)
# SwitchBee maximum brightness is 99
return sb_brightness if sb_brightness != 100 else 99
def _switchbee_brightness_to_hass(value: int) -> int:
"""Convert SwitchBee brightness to hass."""
if value == 99:
value = 100
return round(value * MAX_BRIGHTNESS / 100)
async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up SwitchBee light."""
coordinator = hass.data[DOMAIN][entry.entry_id]
async_add_entities(
SwitchBeeLightEntity(switchbee_device, coordinator)
for switchbee_device in coordinator.data.values()
if switchbee_device.type == DeviceType.Dimmer
)
class SwitchBeeLightEntity(SwitchBeeDeviceEntity[SwitchBeeDimmer], LightEntity):
"""Representation of a SwitchBee light."""
_attr_color_mode = ColorMode.BRIGHTNESS
_attr_supported_color_modes = {ColorMode.BRIGHTNESS}
def __init__(
self,
device: SwitchBeeDimmer,
coordinator: SwitchBeeCoordinator,
) -> None:
"""Initialize the SwitchBee light."""
super().__init__(device, coordinator)
self._attr_is_on = False
self._attr_brightness = 0
self._update_attrs_from_coordinator()
@callback
def _handle_coordinator_update(self) -> None:
"""Handle updated data from the coordinator."""
self._update_attrs_from_coordinator()
super()._handle_coordinator_update()
def _update_attrs_from_coordinator(self) -> None:
coordinator_device = cast(
SwitchBeeDimmer, self.coordinator.data[self._device.id]
)
brightness = coordinator_device.brightness
# module is offline
if brightness == -1:
# This specific call will refresh the state of the device in the CU
self.hass.async_create_task(self.async_refresh_state())
# if the device was online (now offline), log message and mark it as Unavailable
if self._is_online:
_LOGGER.warning(
"%s light is not responding, check the status in the SwitchBee mobile app",
self.name,
)
self._is_online = False
return
# check if the device was offline (now online) and bring it back
if not self._is_online:
_LOGGER.info(
"%s light is now responding",
self.name,
)
self._is_online = True
self._attr_is_on = bool(brightness != 0)
# 1-99 is the only valid SwitchBee brightness range
if 0 < brightness < 100:
self._attr_brightness = _switchbee_brightness_to_hass(brightness)
async def async_turn_on(self, **kwargs: Any) -> None:
"""Async function to set on to light."""
if ATTR_BRIGHTNESS in kwargs:
state: int | str = _hass_brightness_to_switchbee(kwargs[ATTR_BRIGHTNESS])
else:
state = ApiStateCommand.ON
if self.brightness:
state = _hass_brightness_to_switchbee(self.brightness)
try:
await self.coordinator.api.set_state(self._device.id, state)
except (SwitchBeeError, SwitchBeeDeviceOfflineError) as exp:
raise HomeAssistantError(
f"Failed to set {self.name} state {state}, {str(exp)}"
) from exp
if not isinstance(state, int):
# We just turned the light on, still don't know the last brightness known the Central Unit (yet)
# the brightness will be learned and updated in the next coordinator refresh
return
# update the coordinator data manually we already know the Central Unit brightness data for this light
cast(SwitchBeeDimmer, self.coordinator.data[self._device.id]).brightness = state
self.coordinator.async_set_updated_data(self.coordinator.data)
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn off SwitchBee light."""
try:
await self.coordinator.api.set_state(self._device.id, ApiStateCommand.OFF)
except (SwitchBeeError, SwitchBeeDeviceOfflineError) as exp:
raise HomeAssistantError(
f"Failed to turn off {self._attr_name}, {str(exp)}"
) from exp
# update the coordinator manually
cast(SwitchBeeDimmer, self.coordinator.data[self._device.id]).brightness = 0
self.coordinator.async_set_updated_data(self.coordinator.data)