Skip to content

Commit fa141f7

Browse files
authored
Restore ColorMode methods for backwards compat (#356)
1 parent b81396a commit fa141f7

File tree

11 files changed

+166
-26
lines changed

11 files changed

+166
-26
lines changed

switchbot/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
AirPurifierMode,
1414
BulbColorMode,
1515
CeilingLightColorMode,
16+
ColorMode,
1617
FanMode,
1718
HumidifierAction,
1819
HumidifierMode,
@@ -48,6 +49,7 @@
4849
"AirPurifierMode",
4950
"BulbColorMode",
5051
"CeilingLightColorMode",
52+
"ColorMode",
5153
"FanMode",
5254
"GetSwitchbotDevices",
5355
"HumidifierAction",

switchbot/const/__init__.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@
1010
HumidifierWaterLevel,
1111
)
1212
from .fan import FanMode
13-
from .light import BulbColorMode, CeilingLightColorMode, StripLightColorMode
13+
from .light import (
14+
BulbColorMode,
15+
CeilingLightColorMode,
16+
ColorMode,
17+
StripLightColorMode,
18+
)
1419

1520
# Preserve old LockStatus export for backwards compatibility
1621
from .lock import LockStatus
@@ -97,6 +102,7 @@ class SwitchbotModel(StrEnum):
97102
"AirPurifierMode",
98103
"BulbColorMode",
99104
"CeilingLightColorMode",
105+
"ColorMode",
100106
"FanMode",
101107
"HumidifierAction",
102108
"HumidifierMode",

switchbot/const/light.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
from enum import Enum
22

33

4+
class ColorMode(Enum):
5+
OFF = 0
6+
COLOR_TEMP = 1
7+
RGB = 2
8+
EFFECT = 3
9+
10+
411
class StripLightColorMode(Enum):
512
RGB = 2
613
SCENE = 3

switchbot/devices/bulb.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import logging
44
from typing import Any
55

6-
from ..const.light import BulbColorMode
6+
from ..const.light import BulbColorMode, ColorMode
77
from .base_light import SwitchbotSequenceBaseLight
88
from .device import REQ_HEADER, SwitchbotOperationError, update_after_operation
99

@@ -32,19 +32,28 @@
3232
"Breathing": "570F4701010302",
3333
}
3434

35+
# Private mapping from device-specific color modes to original ColorMode enum
36+
_BULB_COLOR_MODE_MAP = {
37+
BulbColorMode.COLOR_TEMP: ColorMode.COLOR_TEMP,
38+
BulbColorMode.RGB: ColorMode.RGB,
39+
BulbColorMode.DYNAMIC: ColorMode.EFFECT,
40+
BulbColorMode.UNKNOWN: ColorMode.OFF,
41+
}
42+
3543

3644
class SwitchbotBulb(SwitchbotSequenceBaseLight):
3745
"""Representation of a Switchbot bulb."""
3846

3947
@property
40-
def color_modes(self) -> set[BulbColorMode]:
48+
def color_modes(self) -> set[ColorMode]:
4149
"""Return the supported color modes."""
42-
return {BulbColorMode.RGB, BulbColorMode.COLOR_TEMP}
50+
return {ColorMode.RGB, ColorMode.COLOR_TEMP}
4351

4452
@property
45-
def color_mode(self) -> BulbColorMode:
53+
def color_mode(self) -> ColorMode:
4654
"""Return the current color mode."""
47-
return BulbColorMode(self._get_adv_value("color_mode") or 10)
55+
device_mode = BulbColorMode(self._get_adv_value("color_mode") or 10)
56+
return _BULB_COLOR_MODE_MAP.get(device_mode, ColorMode.OFF)
4857

4958
@property
5059
def get_effect_list(self) -> list[str]:

switchbot/devices/ceiling_light.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@
33
import logging
44
from typing import Any
55

6-
from ..const.light import DEFAULT_COLOR_TEMP, CeilingLightColorMode
6+
from ..const.light import (
7+
DEFAULT_COLOR_TEMP,
8+
CeilingLightColorMode,
9+
ColorMode,
10+
)
711
from .base_light import SwitchbotSequenceBaseLight
812
from .device import REQ_HEADER, update_after_operation
913

@@ -21,19 +25,28 @@
2125

2226
_LOGGER = logging.getLogger(__name__)
2327

28+
# Private mapping from device-specific color modes to original ColorMode enum
29+
_CEILING_LIGHT_COLOR_MODE_MAP = {
30+
CeilingLightColorMode.COLOR_TEMP: ColorMode.COLOR_TEMP,
31+
CeilingLightColorMode.NIGHT: ColorMode.COLOR_TEMP,
32+
CeilingLightColorMode.MUSIC: ColorMode.EFFECT,
33+
CeilingLightColorMode.UNKNOWN: ColorMode.OFF,
34+
}
35+
2436

2537
class SwitchbotCeilingLight(SwitchbotSequenceBaseLight):
2638
"""Representation of a Switchbot ceiling light."""
2739

2840
@property
29-
def color_modes(self) -> set[CeilingLightColorMode]:
41+
def color_modes(self) -> set[ColorMode]:
3042
"""Return the supported color modes."""
31-
return {CeilingLightColorMode.COLOR_TEMP}
43+
return {ColorMode.COLOR_TEMP}
3244

3345
@property
34-
def color_mode(self) -> CeilingLightColorMode:
46+
def color_mode(self) -> ColorMode:
3547
"""Return the current color mode."""
36-
return CeilingLightColorMode(self._get_adv_value("color_mode") or 10)
48+
device_mode = CeilingLightColorMode(self._get_adv_value("color_mode") or 10)
49+
return _CEILING_LIGHT_COLOR_MODE_MAP.get(device_mode, ColorMode.OFF)
3750

3851
@update_after_operation
3952
async def turn_on(self) -> bool:

switchbot/devices/device.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from ..const import (
2929
DEFAULT_RETRY_COUNT,
3030
DEFAULT_SCAN_TIMEOUT,
31+
ColorMode, # noqa: F401
3132
SwitchbotAccountConnectionError,
3233
SwitchbotApiError,
3334
SwitchbotAuthenticationError,

switchbot/devices/light_strip.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from bleak.backends.device import BLEDevice
77

88
from ..const import SwitchbotModel
9-
from ..const.light import StripLightColorMode
9+
from ..const.light import ColorMode, StripLightColorMode
1010
from .base_light import SwitchbotSequenceBaseLight
1111
from .device import (
1212
REQ_HEADER,
@@ -109,19 +109,30 @@
109109
],
110110
}
111111

112+
# Private mapping from device-specific color modes to original ColorMode enum
113+
_STRIP_LIGHT_COLOR_MODE_MAP = {
114+
StripLightColorMode.RGB: ColorMode.RGB,
115+
StripLightColorMode.SCENE: ColorMode.EFFECT,
116+
StripLightColorMode.MUSIC: ColorMode.EFFECT,
117+
StripLightColorMode.CONTROLLER: ColorMode.EFFECT,
118+
StripLightColorMode.COLOR_TEMP: ColorMode.COLOR_TEMP,
119+
StripLightColorMode.UNKNOWN: ColorMode.OFF,
120+
}
121+
112122

113123
class SwitchbotLightStrip(SwitchbotSequenceBaseLight):
114124
"""Representation of a Switchbot light strip."""
115125

116126
@property
117-
def color_modes(self) -> set[StripLightColorMode]:
127+
def color_modes(self) -> set[ColorMode]:
118128
"""Return the supported color modes."""
119-
return {StripLightColorMode.RGB}
129+
return {ColorMode.RGB}
120130

121131
@property
122-
def color_mode(self) -> StripLightColorMode:
132+
def color_mode(self) -> ColorMode:
123133
"""Return the current color mode."""
124-
return StripLightColorMode(self._get_adv_value("color_mode") or 10)
134+
device_mode = StripLightColorMode(self._get_adv_value("color_mode") or 10)
135+
return _STRIP_LIGHT_COLOR_MODE_MAP.get(device_mode, ColorMode.OFF)
125136

126137
@property
127138
def get_effect_list(self) -> list[str]:
@@ -233,9 +244,9 @@ async def verify_encryption_key(
233244
)
234245

235246
@property
236-
def color_modes(self) -> set[StripLightColorMode]:
247+
def color_modes(self) -> set[ColorMode]:
237248
"""Return the supported color modes."""
238-
return {StripLightColorMode.RGB, StripLightColorMode.COLOR_TEMP}
249+
return {ColorMode.RGB, ColorMode.COLOR_TEMP}
239250

240251
@update_after_operation
241252
async def set_color_temp(self, brightness: int, color_temp: int) -> bool:

tests/test_bulb.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from bleak.backends.device import BLEDevice
55

66
from switchbot import SwitchBotAdvertisement, SwitchbotModel
7+
from switchbot.const.light import ColorMode
78
from switchbot.devices import bulb
89
from switchbot.devices.device import SwitchbotOperationError
910

@@ -62,8 +63,8 @@ async def test_default_info():
6263

6364
assert device.is_on() is True
6465
assert device.on is True
65-
assert device.color_mode == bulb.BulbColorMode.RGB
66-
assert device.color_modes == {bulb.BulbColorMode.RGB, bulb.BulbColorMode.COLOR_TEMP}
66+
assert device.color_mode == ColorMode.RGB
67+
assert device.color_modes == {ColorMode.RGB, ColorMode.COLOR_TEMP}
6768
assert device.rgb == (30, 0, 0)
6869
assert device.color_temp == 3200
6970
assert device.brightness == 1

tests/test_ceiling_light.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from bleak.backends.device import BLEDevice
55

66
from switchbot import SwitchBotAdvertisement, SwitchbotModel
7+
from switchbot.const.light import ColorMode
78
from switchbot.devices import ceiling_light
89

910
from .test_adv_parser import generate_ble_device
@@ -58,8 +59,8 @@ async def test_default_info():
5859

5960
assert device.is_on() is False
6061
assert device.on is False
61-
assert device.color_mode == ceiling_light.CeilingLightColorMode.NIGHT
62-
assert device.color_modes == {ceiling_light.CeilingLightColorMode.COLOR_TEMP}
62+
assert device.color_mode == ColorMode.COLOR_TEMP
63+
assert device.color_modes == {ColorMode.COLOR_TEMP}
6364
assert device.color_temp == 3200
6465
assert device.brightness == 1
6566
assert device.min_temp == 2700

tests/test_colormode_imports.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
"""Test ColorMode imports for backward compatibility."""
2+
3+
4+
def test_colormode_import_from_main_module():
5+
"""Test that ColorMode can be imported from the main switchbot module."""
6+
from switchbot import ColorMode
7+
8+
# Verify it's the enum we expect
9+
assert hasattr(ColorMode, "OFF")
10+
assert hasattr(ColorMode, "COLOR_TEMP")
11+
assert hasattr(ColorMode, "RGB")
12+
assert hasattr(ColorMode, "EFFECT")
13+
14+
# Verify the values
15+
assert ColorMode.OFF.value == 0
16+
assert ColorMode.COLOR_TEMP.value == 1
17+
assert ColorMode.RGB.value == 2
18+
assert ColorMode.EFFECT.value == 3
19+
20+
21+
def test_colormode_import_from_device_module():
22+
"""Test that ColorMode can be imported from switchbot.devices.device for backward compatibility."""
23+
from switchbot.devices.device import ColorMode
24+
25+
# Verify it's the enum we expect
26+
assert hasattr(ColorMode, "OFF")
27+
assert hasattr(ColorMode, "COLOR_TEMP")
28+
assert hasattr(ColorMode, "RGB")
29+
assert hasattr(ColorMode, "EFFECT")
30+
31+
# Verify the values
32+
assert ColorMode.OFF.value == 0
33+
assert ColorMode.COLOR_TEMP.value == 1
34+
assert ColorMode.RGB.value == 2
35+
assert ColorMode.EFFECT.value == 3
36+
37+
38+
def test_colormode_import_from_const():
39+
"""Test that ColorMode can be imported from switchbot.const."""
40+
from switchbot.const import ColorMode
41+
42+
# Verify it's the enum we expect
43+
assert hasattr(ColorMode, "OFF")
44+
assert hasattr(ColorMode, "COLOR_TEMP")
45+
assert hasattr(ColorMode, "RGB")
46+
assert hasattr(ColorMode, "EFFECT")
47+
48+
# Verify the values
49+
assert ColorMode.OFF.value == 0
50+
assert ColorMode.COLOR_TEMP.value == 1
51+
assert ColorMode.RGB.value == 2
52+
assert ColorMode.EFFECT.value == 3
53+
54+
55+
def test_colormode_import_from_const_light():
56+
"""Test that ColorMode can be imported from switchbot.const.light."""
57+
from switchbot.const.light import ColorMode
58+
59+
# Verify it's the enum we expect
60+
assert hasattr(ColorMode, "OFF")
61+
assert hasattr(ColorMode, "COLOR_TEMP")
62+
assert hasattr(ColorMode, "RGB")
63+
assert hasattr(ColorMode, "EFFECT")
64+
65+
# Verify the values
66+
assert ColorMode.OFF.value == 0
67+
assert ColorMode.COLOR_TEMP.value == 1
68+
assert ColorMode.RGB.value == 2
69+
assert ColorMode.EFFECT.value == 3
70+
71+
72+
def test_all_colormode_imports_are_same_object():
73+
"""Test that all ColorMode imports reference the same enum object."""
74+
from switchbot import ColorMode as ColorMode1
75+
from switchbot.const import ColorMode as ColorMode3
76+
from switchbot.const.light import ColorMode as ColorMode4
77+
from switchbot.devices.device import ColorMode as ColorMode2
78+
79+
# They should all be the exact same object
80+
assert ColorMode1 is ColorMode2
81+
assert ColorMode2 is ColorMode3
82+
assert ColorMode3 is ColorMode4
83+
84+
# And their members should be the same
85+
assert ColorMode1.OFF is ColorMode2.OFF
86+
assert ColorMode1.COLOR_TEMP is ColorMode3.COLOR_TEMP
87+
assert ColorMode1.RGB is ColorMode4.RGB
88+
assert ColorMode1.EFFECT is ColorMode2.EFFECT

0 commit comments

Comments
 (0)