From 7d471f9624be456c90d35dc3cacbf231acac4bac Mon Sep 17 00:00:00 2001 From: Retha Runolfsson <137745329+zerzhang@users.noreply.github.com> Date: Thu, 11 Sep 2025 02:52:47 +0800 Subject: [PATCH] Add rgbicww light for switchbot integration (#151129) --- .../components/switchbot/__init__.py | 4 ++ homeassistant/components/switchbot/const.py | 8 +++ homeassistant/components/switchbot/icons.json | 25 +++++++- .../components/switchbot/strings.json | 25 +++++++- tests/components/switchbot/__init__.py | 57 +++++++++++++++++++ tests/components/switchbot/test_light.py | 17 ++++-- 6 files changed, 130 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/switchbot/__init__.py b/homeassistant/components/switchbot/__init__.py index acf37fe916b..08df5dc50f0 100644 --- a/homeassistant/components/switchbot/__init__.py +++ b/homeassistant/components/switchbot/__init__.py @@ -95,6 +95,8 @@ PLATFORMS_BY_TYPE = { SupportedModels.EVAPORATIVE_HUMIDIFIER: [Platform.HUMIDIFIER, Platform.SENSOR], SupportedModels.FLOOR_LAMP.value: [Platform.LIGHT, Platform.SENSOR], SupportedModels.STRIP_LIGHT_3.value: [Platform.LIGHT, Platform.SENSOR], + SupportedModels.RGBICWW_FLOOR_LAMP.value: [Platform.LIGHT, Platform.SENSOR], + SupportedModels.RGBICWW_STRIP_LIGHT.value: [Platform.LIGHT, Platform.SENSOR], } CLASS_BY_DEVICE = { SupportedModels.CEILING_LIGHT.value: switchbot.SwitchbotCeilingLight, @@ -123,6 +125,8 @@ CLASS_BY_DEVICE = { SupportedModels.EVAPORATIVE_HUMIDIFIER: switchbot.SwitchbotEvaporativeHumidifier, SupportedModels.FLOOR_LAMP.value: switchbot.SwitchbotStripLight3, SupportedModels.STRIP_LIGHT_3.value: switchbot.SwitchbotStripLight3, + SupportedModels.RGBICWW_FLOOR_LAMP.value: switchbot.SwitchbotRgbicLight, + SupportedModels.RGBICWW_STRIP_LIGHT.value: switchbot.SwitchbotRgbicLight, } diff --git a/homeassistant/components/switchbot/const.py b/homeassistant/components/switchbot/const.py index c57b8d467cc..5cdb3d9dd4e 100644 --- a/homeassistant/components/switchbot/const.py +++ b/homeassistant/components/switchbot/const.py @@ -51,6 +51,8 @@ class SupportedModels(StrEnum): EVAPORATIVE_HUMIDIFIER = "evaporative_humidifier" FLOOR_LAMP = "floor_lamp" STRIP_LIGHT_3 = "strip_light_3" + RGBICWW_STRIP_LIGHT = "rgbicww_strip_light" + RGBICWW_FLOOR_LAMP = "rgbicww_floor_lamp" CONNECTABLE_SUPPORTED_MODEL_TYPES = { @@ -81,6 +83,8 @@ CONNECTABLE_SUPPORTED_MODEL_TYPES = { SwitchbotModel.EVAPORATIVE_HUMIDIFIER: SupportedModels.EVAPORATIVE_HUMIDIFIER, SwitchbotModel.FLOOR_LAMP: SupportedModels.FLOOR_LAMP, SwitchbotModel.STRIP_LIGHT_3: SupportedModels.STRIP_LIGHT_3, + SwitchbotModel.RGBICWW_STRIP_LIGHT: SupportedModels.RGBICWW_STRIP_LIGHT, + SwitchbotModel.RGBICWW_FLOOR_LAMP: SupportedModels.RGBICWW_FLOOR_LAMP, } NON_CONNECTABLE_SUPPORTED_MODEL_TYPES = { @@ -112,6 +116,8 @@ ENCRYPTED_MODELS = { SwitchbotModel.EVAPORATIVE_HUMIDIFIER, SwitchbotModel.FLOOR_LAMP, SwitchbotModel.STRIP_LIGHT_3, + SwitchbotModel.RGBICWW_STRIP_LIGHT, + SwitchbotModel.RGBICWW_FLOOR_LAMP, } ENCRYPTED_SWITCHBOT_MODEL_TO_CLASS: dict[ @@ -128,6 +134,8 @@ ENCRYPTED_SWITCHBOT_MODEL_TO_CLASS: dict[ SwitchbotModel.EVAPORATIVE_HUMIDIFIER: switchbot.SwitchbotEvaporativeHumidifier, SwitchbotModel.FLOOR_LAMP: switchbot.SwitchbotStripLight3, SwitchbotModel.STRIP_LIGHT_3: switchbot.SwitchbotStripLight3, + SwitchbotModel.RGBICWW_STRIP_LIGHT: switchbot.SwitchbotRgbicLight, + SwitchbotModel.RGBICWW_FLOOR_LAMP: switchbot.SwitchbotRgbicLight, } HASS_SENSOR_TYPE_TO_SWITCHBOT_MODEL = { diff --git a/homeassistant/components/switchbot/icons.json b/homeassistant/components/switchbot/icons.json index cf9217bf70b..b04c04188d1 100644 --- a/homeassistant/components/switchbot/icons.json +++ b/homeassistant/components/switchbot/icons.json @@ -99,7 +99,30 @@ "rose": "mdi:flower", "colorful": "mdi:looks", "flickering": "mdi:led-strip-variant", - "breathing": "mdi:heart-pulse" + "breathing": "mdi:heart-pulse", + "romance": "mdi:heart-outline", + "energy": "mdi:run", + "heartbeat": "mdi:heart-pulse", + "party": "mdi:party-popper", + "dynamic": "mdi:palette", + "mystery": "mdi:alien-outline", + "lightning": "mdi:flash-outline", + "rock": "mdi:guitar-electric", + "starlight": "mdi:creation", + "valentine_day": "mdi:emoticon-kiss-outline", + "dream": "mdi:sleep", + "alarm": "mdi:alarm-light", + "fireworks": "mdi:firework", + "waves": "mdi:waves", + "rainbow": "mdi:looks", + "game": "mdi:gamepad-variant-outline", + "meditation": "mdi:meditation", + "starlit_sky": "mdi:weather-night", + "sleep": "mdi:power-sleep", + "movie": "mdi:popcorn", + "sunrise": "mdi:weather-sunset-up", + "new_year": "mdi:glass-wine", + "cherry_blossom": "mdi:flower-outline" } } } diff --git a/homeassistant/components/switchbot/strings.json b/homeassistant/components/switchbot/strings.json index 35482016e90..961204ee88d 100644 --- a/homeassistant/components/switchbot/strings.json +++ b/homeassistant/components/switchbot/strings.json @@ -270,7 +270,30 @@ "rose": "Rose", "colorful": "Colorful", "flickering": "Flickering", - "breathing": "Breathing" + "breathing": "Breathing", + "romance": "Romance", + "energy": "Energy", + "heartbeat": "Heartbeat", + "party": "Party", + "dynamic": "Dynamic", + "mystery": "Mystery", + "lightning": "Lightning", + "rock": "Rock", + "starlight": "Starlight", + "valentine_day": "Valentine's Day", + "dream": "Dream", + "alarm": "Alarm", + "fireworks": "Fireworks", + "waves": "Waves", + "rainbow": "Rainbow", + "game": "Game", + "meditation": "Meditation", + "starlit_sky": "Starlit Sky", + "sleep": "Sleep", + "movie": "Movie", + "sunrise": "Sunrise", + "new_year": "New Year", + "cherry_blossom": "Cherry Blossom" } } } diff --git a/tests/components/switchbot/__init__.py b/tests/components/switchbot/__init__.py index d64ee2d7a73..184ec1a9ae3 100644 --- a/tests/components/switchbot/__init__.py +++ b/tests/components/switchbot/__init__.py @@ -999,3 +999,60 @@ FLOOR_LAMP_SERVICE_INFO = BluetoothServiceInfoBleak( connectable=True, tx_power=-127, ) + +RGBICWW_STRIP_LIGHT_SERVICE_INFO = BluetoothServiceInfoBleak( + name="RGBICWW Strip Light", + manufacturer_data={ + 2409: b'(7/L\x94\xb2\x0c\x9e"\x00\x11:\x00', + }, + service_data={ + "0000fd3d-0000-1000-8000-00805f9b34fb": b"\x00\x00\x00\x00\x10\xd0\xb3" + }, + service_uuids=["cba20d00-224d-11e6-9fb8-0002a5d5c51b"], + address="AA:BB:CC:DD:EE:FF", + rssi=-60, + source="local", + advertisement=generate_advertisement_data( + local_name="RGBICWW Strip Light", + manufacturer_data={ + 2409: b'(7/L\x94\xb2\x0c\x9e"\x00\x11:\x00', + }, + service_data={ + "0000fd3d-0000-1000-8000-00805f9b34fb": b"\x00\x00\x00\x00\x10\xd0\xb3" + }, + service_uuids=["cba20d00-224d-11e6-9fb8-0002a5d5c51b"], + ), + device=generate_ble_device("AA:BB:CC:DD:EE:FF", "RGBICWW Strip Light"), + time=0, + connectable=True, + tx_power=-127, +) + + +RGBICWW_FLOOR_LAMP_SERVICE_INFO = BluetoothServiceInfoBleak( + name="RGBICWW Floor Lamp", + manufacturer_data={ + 2409: b'\xdc\x06u\xa6\xfb\xb2y\x9e"\x00\x11\xb8\x00', + }, + service_data={ + "0000fd3d-0000-1000-8000-00805f9b34fb": b"\x00\x00\x00\x00\x10\xd0\xb4" + }, + service_uuids=["cba20d00-224d-11e6-9fb8-0002a5d5c51b"], + address="AA:BB:CC:DD:EE:FF", + rssi=-60, + source="local", + advertisement=generate_advertisement_data( + local_name="RGBICWW Floor Lamp", + manufacturer_data={ + 2409: b'\xdc\x06u\xa6\xfb\xb2y\x9e"\x00\x11\xb8\x00', + }, + service_data={ + "0000fd3d-0000-1000-8000-00805f9b34fb": b"\x00\x00\x00\x00\x10\xd0\xb4" + }, + service_uuids=["cba20d00-224d-11e6-9fb8-0002a5d5c51b"], + ), + device=generate_ble_device("AA:BB:CC:DD:EE:FF", "RGBICWW Floor Lamp"), + time=0, + connectable=True, + tx_power=-127, +) diff --git a/tests/components/switchbot/test_light.py b/tests/components/switchbot/test_light.py index 718d7aecf96..706597c6052 100644 --- a/tests/components/switchbot/test_light.py +++ b/tests/components/switchbot/test_light.py @@ -25,6 +25,8 @@ from . import ( BULB_SERVICE_INFO, CEILING_LIGHT_SERVICE_INFO, FLOOR_LAMP_SERVICE_INFO, + RGBICWW_FLOOR_LAMP_SERVICE_INFO, + RGBICWW_STRIP_LIGHT_SERVICE_INFO, STRIP_LIGHT_3_SERVICE_INFO, WOSTRIP_SERVICE_INFO, ) @@ -343,10 +345,16 @@ async def test_strip_light_services_exception( @pytest.mark.parametrize( - ("sensor_type", "service_info"), + ("sensor_type", "service_info", "dev_cls"), [ - ("strip_light_3", STRIP_LIGHT_3_SERVICE_INFO), - ("floor_lamp", FLOOR_LAMP_SERVICE_INFO), + ("strip_light_3", STRIP_LIGHT_3_SERVICE_INFO, "SwitchbotStripLight3"), + ("floor_lamp", FLOOR_LAMP_SERVICE_INFO, "SwitchbotStripLight3"), + ( + "rgbicww_strip_light", + RGBICWW_STRIP_LIGHT_SERVICE_INFO, + "SwitchbotRgbicLight", + ), + ("rgbicww_floor_lamp", RGBICWW_FLOOR_LAMP_SERVICE_INFO, "SwitchbotRgbicLight"), ], ) @pytest.mark.parametrize(*FLOOR_LAMP_PARAMETERS) @@ -355,6 +363,7 @@ async def test_floor_lamp_services( mock_entry_encrypted_factory: Callable[[str], MockConfigEntry], sensor_type: str, service_info: BluetoothServiceInfoBleak, + dev_cls: str, service: str, service_data: dict, mock_method: str, @@ -370,7 +379,7 @@ async def test_floor_lamp_services( mocked_instance = AsyncMock(return_value=True) with patch.multiple( - "homeassistant.components.switchbot.light.switchbot.SwitchbotStripLight3", + f"homeassistant.components.switchbot.light.switchbot.{dev_cls}", **{mock_method: mocked_instance}, update=AsyncMock(return_value=None), ):