Skip to content

Commit c7dc6a4

Browse files
zerzhangpre-commit-ci[bot]bdraco
authored
Add and optimize led series (#352)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: J. Nick Koston <[email protected]>
1 parent 2922bbd commit c7dc6a4

File tree

15 files changed

+1302
-127
lines changed

15 files changed

+1302
-127
lines changed

switchbot/__init__.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,14 @@
1111
from .adv_parser import SwitchbotSupportedType, parse_advertisement_data
1212
from .const import (
1313
AirPurifierMode,
14+
BulbColorMode,
15+
CeilingLightColorMode,
1416
FanMode,
1517
HumidifierAction,
1618
HumidifierMode,
1719
HumidifierWaterLevel,
1820
LockStatus,
21+
StripLightColorMode,
1922
SwitchbotAccountConnectionError,
2023
SwitchbotApiError,
2124
SwitchbotAuthenticationError,
@@ -28,11 +31,11 @@
2831
from .devices.bulb import SwitchbotBulb
2932
from .devices.ceiling_light import SwitchbotCeilingLight
3033
from .devices.curtain import SwitchbotCurtain
31-
from .devices.device import ColorMode, SwitchbotDevice, SwitchbotEncryptedDevice
34+
from .devices.device import SwitchbotDevice, SwitchbotEncryptedDevice
3235
from .devices.evaporative_humidifier import SwitchbotEvaporativeHumidifier
3336
from .devices.fan import SwitchbotFan
3437
from .devices.humidifier import SwitchbotHumidifier
35-
from .devices.light_strip import SwitchbotLightStrip
38+
from .devices.light_strip import SwitchbotLightStrip, SwitchbotStripLight3
3639
from .devices.lock import SwitchbotLock
3740
from .devices.plug import SwitchbotPlugMini
3841
from .devices.relay_switch import SwitchbotRelaySwitch, SwitchbotRelaySwitch2PM
@@ -43,13 +46,15 @@
4346

4447
__all__ = [
4548
"AirPurifierMode",
46-
"ColorMode",
49+
"BulbColorMode",
50+
"CeilingLightColorMode",
4751
"FanMode",
4852
"GetSwitchbotDevices",
4953
"HumidifierAction",
5054
"HumidifierMode",
5155
"HumidifierWaterLevel",
5256
"LockStatus",
57+
"StripLightColorMode",
5358
"SwitchBotAdvertisement",
5459
"Switchbot",
5560
"Switchbot",
@@ -76,6 +81,7 @@
7681
"SwitchbotRelaySwitch",
7782
"SwitchbotRelaySwitch2PM",
7883
"SwitchbotRollerShade",
84+
"SwitchbotStripLight3",
7985
"SwitchbotSupportedType",
8086
"SwitchbotSupportedType",
8187
"SwitchbotVacuum",

switchbot/adv_parser.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
from .adv_parsers.humidifier import process_evaporative_humidifier, process_wohumidifier
2525
from .adv_parsers.keypad import process_wokeypad
2626
from .adv_parsers.leak import process_leak
27-
from .adv_parsers.light_strip import process_wostrip
27+
from .adv_parsers.light_strip import process_light, process_wostrip
2828
from .adv_parsers.lock import process_lock2, process_wolock, process_wolock_pro
2929
from .adv_parsers.meter import process_wosensorth, process_wosensorth_c
3030
from .adv_parsers.motion import process_wopresence
@@ -325,6 +325,18 @@ class SwitchbotSupportedType(TypedDict):
325325
"func": process_relay_switch_2pm,
326326
"manufacturer_id": 2409,
327327
},
328+
b"\x00\x10\xd0\xb0": {
329+
"modelName": SwitchbotModel.FLOOR_LAMP,
330+
"modelFriendlyName": "Floor Lamp",
331+
"func": process_light,
332+
"manufacturer_id": 2409,
333+
},
334+
b"\x00\x10\xd0\xb1": {
335+
"modelName": SwitchbotModel.STRIP_LIGHT_3,
336+
"modelFriendlyName": "Strip Light 3",
337+
"func": process_light,
338+
"manufacturer_id": 2409,
339+
},
328340
}
329341

330342
_SWITCHBOT_MODEL_TO_CHAR = {

switchbot/adv_parsers/light_strip.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
from __future__ import annotations
44

5+
import struct
6+
57

68
def process_wostrip(
79
data: bytes | None, mfr_data: bytes | None
@@ -14,8 +16,17 @@ def process_wostrip(
1416
"isOn": bool(mfr_data[7] & 0b10000000),
1517
"brightness": mfr_data[7] & 0b01111111,
1618
"delay": bool(mfr_data[8] & 0b10000000),
17-
"preset": bool(mfr_data[8] & 0b00001000),
18-
"color_mode": mfr_data[8] & 0b00000111,
19-
"speed": mfr_data[9] & 0b01111111,
20-
"loop_index": mfr_data[10] & 0b11111110,
19+
"network_state": (mfr_data[8] & 0b01110000) >> 4,
20+
"color_mode": mfr_data[8] & 0b00001111,
2121
}
22+
23+
24+
def process_light(data: bytes | None, mfr_data: bytes | None) -> dict[str, bool | int]:
25+
"""Support for strip light 3 and floor lamp."""
26+
common_data = process_wostrip(data, mfr_data)
27+
if not common_data:
28+
return {}
29+
30+
light_data = {"cw": struct.unpack(">H", mfr_data[16:18])[0]}
31+
32+
return common_data | light_data

switchbot/const/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
HumidifierWaterLevel,
1111
)
1212
from .fan import FanMode
13+
from .light import BulbColorMode, CeilingLightColorMode, StripLightColorMode
1314

1415
# Preserve old LockStatus export for backwards compatibility
1516
from .lock import LockStatus
@@ -85,18 +86,23 @@ class SwitchbotModel(StrEnum):
8586
LOCK_LITE = "Lock Lite"
8687
GARAGE_DOOR_OPENER = "Garage Door Opener"
8788
RELAY_SWITCH_2PM = "Relay Switch 2PM"
89+
STRIP_LIGHT_3 = "Strip Light 3"
90+
FLOOR_LAMP = "Floor Lamp"
8891

8992

9093
__all__ = [
9194
"DEFAULT_RETRY_COUNT",
9295
"DEFAULT_RETRY_TIMEOUT",
9396
"DEFAULT_SCAN_TIMEOUT",
9497
"AirPurifierMode",
98+
"BulbColorMode",
99+
"CeilingLightColorMode",
95100
"FanMode",
96101
"HumidifierAction",
97102
"HumidifierMode",
98103
"HumidifierWaterLevel",
99104
"LockStatus",
105+
"StripLightColorMode",
100106
"SwitchbotAccountConnectionError",
101107
"SwitchbotApiError",
102108
"SwitchbotAuthenticationError",

switchbot/const/light.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from enum import Enum
2+
3+
4+
class StripLightColorMode(Enum):
5+
RGB = 2
6+
SCENE = 3
7+
MUSIC = 4
8+
CONTROLLER = 5
9+
COLOR_TEMP = 6
10+
UNKNOWN = 10
11+
12+
13+
class BulbColorMode(Enum):
14+
COLOR_TEMP = 1
15+
RGB = 2
16+
DYNAMIC = 3
17+
UNKNOWN = 10
18+
19+
20+
class CeilingLightColorMode(Enum):
21+
COLOR_TEMP = 0
22+
NIGHT = 1
23+
MUSIC = 4
24+
UNKNOWN = 10
25+
26+
27+
DEFAULT_COLOR_TEMP = 4001

switchbot/devices/base_light.py

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
from __future__ import annotations
22

33
import logging
4-
import time
54
from abc import abstractmethod
65
from typing import Any
76

87
from ..helpers import create_background_task
98
from ..models import SwitchBotAdvertisement
10-
from .device import ColorMode, SwitchbotDevice
9+
from .device import SwitchbotDevice
1110

1211
_LOGGER = logging.getLogger(__name__)
1312

@@ -43,9 +42,10 @@ def brightness(self) -> int | None:
4342
return self._get_adv_value("brightness") or 0
4443

4544
@property
46-
def color_mode(self) -> ColorMode:
45+
@abstractmethod
46+
def color_mode(self) -> Any:
4747
"""Return the current color mode."""
48-
return ColorMode(self._get_adv_value("color_mode") or 0)
48+
raise NotImplementedError("Subclasses must implement color mode")
4949

5050
@property
5151
def min_temp(self) -> int:
@@ -57,10 +57,19 @@ def max_temp(self) -> int:
5757
"""Return maximum color temp."""
5858
return 6500
5959

60+
@property
61+
def get_effect_list(self) -> list[str] | None:
62+
"""Return the list of supported effects."""
63+
return None
64+
6065
def is_on(self) -> bool | None:
6166
"""Return bulb state from cache."""
6267
return self._get_adv_value("isOn")
6368

69+
def get_effect(self):
70+
"""Return the current effect."""
71+
return self._get_adv_value("effect")
72+
6473
@abstractmethod
6574
async def turn_on(self) -> bool:
6675
"""Turn device on."""
@@ -81,13 +90,18 @@ async def set_color_temp(self, brightness: int, color_temp: int) -> bool:
8190
async def set_rgb(self, brightness: int, r: int, g: int, b: int) -> bool:
8291
"""Set rgb."""
8392

84-
def poll_needed(self, last_poll_time: float | None) -> bool:
85-
"""Return if poll is needed."""
86-
return False
87-
88-
async def update(self) -> None:
89-
"""Update device data."""
90-
self._last_full_update = time.monotonic()
93+
async def _send_multiple_commands(self, keys: list[str]) -> bool:
94+
"""
95+
Send multiple commands to device.
96+
97+
Since we current have no way to tell which command the device
98+
needs we send both.
99+
"""
100+
final_result = False
101+
for key in keys:
102+
result = await self._send_command(key)
103+
final_result |= self._check_command_result(result, 0, {1})
104+
return final_result
91105

92106

93107
class SwitchbotSequenceBaseLight(SwitchbotBaseLight):

0 commit comments

Comments
 (0)