mirror of
https://github.com/home-assistant/core.git
synced 2026-04-28 18:12:37 +02:00
Add support for SwitchBot Ceiling Lights (#159072)
This commit is contained in:
@@ -276,6 +276,8 @@ async def make_device_data(
|
||||
"Color Bulb",
|
||||
"RGBICWW Floor Lamp",
|
||||
"RGBICWW Strip Light",
|
||||
"Ceiling Light",
|
||||
"Ceiling Light Pro",
|
||||
]:
|
||||
coordinator = await coordinator_for_device(
|
||||
hass, entry, api, device, coordinators_by_id
|
||||
|
||||
@@ -4,6 +4,7 @@ import asyncio
|
||||
from typing import Any
|
||||
|
||||
from switchbot_api import (
|
||||
CeilingLightCommands,
|
||||
CommonCommands,
|
||||
Device,
|
||||
Remote,
|
||||
@@ -53,6 +54,16 @@ class SwitchBotCloudLight(SwitchBotCloudEntity, LightEntity):
|
||||
|
||||
_attr_color_mode = ColorMode.UNKNOWN
|
||||
|
||||
def _get_default_color_mode(self) -> ColorMode:
|
||||
"""Return the default color mode."""
|
||||
if not self.supported_color_modes:
|
||||
return ColorMode.UNKNOWN
|
||||
if ColorMode.RGB in self.supported_color_modes:
|
||||
return ColorMode.RGB
|
||||
if ColorMode.COLOR_TEMP in self.supported_color_modes:
|
||||
return ColorMode.COLOR_TEMP
|
||||
return ColorMode.UNKNOWN
|
||||
|
||||
def _set_attributes(self) -> None:
|
||||
"""Set attributes from coordinator data."""
|
||||
if self.coordinator.data is None:
|
||||
@@ -83,8 +94,9 @@ class SwitchBotCloudLight(SwitchBotCloudEntity, LightEntity):
|
||||
brightness: int | None = kwargs.get("brightness")
|
||||
rgb_color: tuple[int, int, int] | None = kwargs.get("rgb_color")
|
||||
color_temp_kelvin: int | None = kwargs.get("color_temp_kelvin")
|
||||
|
||||
if brightness is not None:
|
||||
self._attr_color_mode = ColorMode.RGB
|
||||
self._attr_color_mode = self._get_default_color_mode()
|
||||
await self._send_brightness_command(brightness)
|
||||
elif rgb_color is not None:
|
||||
self._attr_color_mode = ColorMode.RGB
|
||||
@@ -93,7 +105,7 @@ class SwitchBotCloudLight(SwitchBotCloudEntity, LightEntity):
|
||||
self._attr_color_mode = ColorMode.COLOR_TEMP
|
||||
await self._send_color_temperature_command(color_temp_kelvin)
|
||||
else:
|
||||
self._attr_color_mode = ColorMode.RGB
|
||||
self._attr_color_mode = self._get_default_color_mode()
|
||||
await self.send_api_command(CommonCommands.ON)
|
||||
await asyncio.sleep(AFTER_COMMAND_REFRESH)
|
||||
await self.coordinator.async_request_refresh()
|
||||
@@ -149,11 +161,36 @@ class SwitchBotCloudRGBWWLight(SwitchBotCloudLight):
|
||||
)
|
||||
|
||||
|
||||
class SwitchBotCloudCeilingLight(SwitchBotCloudLight):
|
||||
"""Representation of SwitchBot Ceiling Light."""
|
||||
|
||||
_attr_max_color_temp_kelvin = 6500
|
||||
_attr_min_color_temp_kelvin = 2700
|
||||
|
||||
_attr_supported_color_modes = {ColorMode.COLOR_TEMP}
|
||||
|
||||
async def _send_brightness_command(self, brightness: int) -> None:
|
||||
"""Send a brightness command."""
|
||||
await self.send_api_command(
|
||||
CeilingLightCommands.SET_BRIGHTNESS,
|
||||
parameters=str(value_map_brightness(brightness)),
|
||||
)
|
||||
|
||||
async def _send_color_temperature_command(self, color_temp_kelvin: int) -> None:
|
||||
"""Send a color temperature command."""
|
||||
await self.send_api_command(
|
||||
CeilingLightCommands.SET_COLOR_TEMPERATURE,
|
||||
parameters=str(color_temp_kelvin),
|
||||
)
|
||||
|
||||
|
||||
@callback
|
||||
def _async_make_entity(
|
||||
api: SwitchBotAPI, device: Device | Remote, coordinator: SwitchBotCoordinator
|
||||
) -> SwitchBotCloudStripLight | SwitchBotCloudRGBWWLight:
|
||||
) -> SwitchBotCloudStripLight | SwitchBotCloudRGBWWLight | SwitchBotCloudCeilingLight:
|
||||
"""Make a SwitchBotCloudLight."""
|
||||
if device.device_type == "Strip Light":
|
||||
return SwitchBotCloudStripLight(api, device, coordinator)
|
||||
if device.device_type in ["Ceiling Light", "Ceiling Light Pro"]:
|
||||
return SwitchBotCloudCeilingLight(api, device, coordinator)
|
||||
return SwitchBotCloudRGBWWLight(api, device, coordinator)
|
||||
|
||||
@@ -2,9 +2,14 @@
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
from switchbot_api import Device, SwitchBotAPI
|
||||
import pytest
|
||||
from switchbot_api import CeilingLightCommands, CommonCommands, Device, SwitchBotAPI
|
||||
|
||||
from homeassistant.components.light import DOMAIN as LIGHT_DOMAIN
|
||||
from homeassistant.components.light import (
|
||||
ATTR_COLOR_MODE,
|
||||
DOMAIN as LIGHT_DOMAIN,
|
||||
ColorMode,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
@@ -298,3 +303,122 @@ async def test_rgbww_light_turn_on(
|
||||
mock_send_command.assert_called()
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state is STATE_ON
|
||||
|
||||
|
||||
@pytest.mark.parametrize("device_type", ["Ceiling Light", "Ceiling Light Pro"])
|
||||
async def test_ceiling_light_turn_on(
|
||||
hass: HomeAssistant, mock_list_devices, mock_get_status, device_type
|
||||
) -> None:
|
||||
"""Test ceiling light turn on."""
|
||||
mock_list_devices.return_value = [
|
||||
Device(
|
||||
version="V1.0",
|
||||
deviceId="light-id-1",
|
||||
deviceName="light-1",
|
||||
deviceType=device_type,
|
||||
hubDeviceId="test-hub-id",
|
||||
),
|
||||
]
|
||||
mock_get_status.side_effect = [
|
||||
{"power": "off", "brightness": 1, "colorTemperature": 4567},
|
||||
{"power": "on", "brightness": 10, "colorTemperature": 5555},
|
||||
{"power": "on", "brightness": 10, "colorTemperature": 5555},
|
||||
{"power": "on", "brightness": 10, "colorTemperature": 5555},
|
||||
{"power": "on", "brightness": 10, "colorTemperature": 5555},
|
||||
]
|
||||
entry = await configure_integration(hass)
|
||||
assert entry.state is ConfigEntryState.LOADED
|
||||
entity_id = "light.light_1"
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state is STATE_OFF
|
||||
|
||||
# Test turn on with brightness
|
||||
with patch.object(SwitchBotAPI, "send_command") as mock_send_command:
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: entity_id, "brightness": 99},
|
||||
blocking=True,
|
||||
)
|
||||
mock_send_command.assert_called_with(
|
||||
"light-id-1",
|
||||
CeilingLightCommands.SET_BRIGHTNESS,
|
||||
"command",
|
||||
"38",
|
||||
)
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state is STATE_ON
|
||||
assert state.attributes[ATTR_COLOR_MODE] == ColorMode.COLOR_TEMP
|
||||
|
||||
# Test turn on with color temp
|
||||
with patch.object(SwitchBotAPI, "send_command") as mock_send_command:
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: entity_id, "color_temp_kelvin": 3333},
|
||||
blocking=True,
|
||||
)
|
||||
mock_send_command.assert_called_with(
|
||||
"light-id-1",
|
||||
CeilingLightCommands.SET_COLOR_TEMPERATURE,
|
||||
"command",
|
||||
"3333",
|
||||
)
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state is STATE_ON
|
||||
|
||||
# Test turn on without arguments
|
||||
with patch.object(SwitchBotAPI, "send_command") as mock_send_command:
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: entity_id},
|
||||
blocking=True,
|
||||
)
|
||||
mock_send_command.assert_called_with(
|
||||
"light-id-1",
|
||||
CommonCommands.ON,
|
||||
"command",
|
||||
"default",
|
||||
)
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state is STATE_ON
|
||||
assert state.attributes[ATTR_COLOR_MODE] == ColorMode.COLOR_TEMP
|
||||
|
||||
|
||||
@pytest.mark.parametrize("device_type", ["Ceiling Light", "Ceiling Light Pro"])
|
||||
async def test_ceiling_light_turn_off(
|
||||
hass: HomeAssistant, mock_list_devices, mock_get_status, device_type
|
||||
) -> None:
|
||||
"""Test ceiling light turn off."""
|
||||
mock_list_devices.return_value = [
|
||||
Device(
|
||||
version="V1.0",
|
||||
deviceId="light-id-1",
|
||||
deviceName="light-1",
|
||||
deviceType=device_type,
|
||||
hubDeviceId="test-hub-id",
|
||||
),
|
||||
]
|
||||
mock_get_status.side_effect = [
|
||||
{"power": "on", "brightness": 1, "colorTemperature": 4567},
|
||||
{"power": "off", "brightness": 1, "colorTemperature": 4567},
|
||||
]
|
||||
entry = await configure_integration(hass)
|
||||
assert entry.state is ConfigEntryState.LOADED
|
||||
entity_id = "light.light_1"
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state is STATE_ON
|
||||
|
||||
with patch.object(SwitchBotAPI, "send_command") as mock_send_command:
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: entity_id}, blocking=True
|
||||
)
|
||||
mock_send_command.assert_called_with(
|
||||
"light-id-1",
|
||||
CommonCommands.OFF,
|
||||
"command",
|
||||
"default",
|
||||
)
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state is STATE_OFF
|
||||
|
||||
Reference in New Issue
Block a user