PySwitchbot 2.0.1__tar.gz → 2.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/PKG-INFO +1 -1
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/PySwitchbot.egg-info/PKG-INFO +1 -1
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/PySwitchbot.egg-info/SOURCES.txt +2 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/setup.py +1 -1
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/__init__.py +16 -1
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/adv_parser.py +81 -3
- pyswitchbot-2.2.0/switchbot/adv_parsers/_sensor_th.py +36 -0
- pyswitchbot-2.2.0/switchbot/adv_parsers/fan.py +55 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/adv_parsers/light_strip.py +15 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/adv_parsers/meter.py +3 -21
- pyswitchbot-2.2.0/switchbot/adv_parsers/weather_station.py +40 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/const/__init__.py +17 -1
- pyswitchbot-2.2.0/switchbot/const/fan.py +62 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/const/light.py +1 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/devices/air_purifier.py +1 -26
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/devices/art_frame.py +2 -26
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/devices/device.py +17 -3
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/devices/evaporative_humidifier.py +2 -27
- pyswitchbot-2.2.0/switchbot/devices/fan.py +226 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/devices/keypad_vision.py +1 -1
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/devices/light_strip.py +58 -49
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/devices/lock.py +37 -18
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/devices/relay_switch.py +4 -48
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/devices/roller_shade.py +55 -17
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/devices/smart_thermostat_radiator.py +1 -26
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/tests/test_adv_parser.py +310 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/tests/test_air_purifier.py +5 -23
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/tests/test_art_frame.py +3 -24
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/tests/test_encrypted_device.py +49 -4
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/tests/test_evaporative_humidifier.py +6 -23
- pyswitchbot-2.2.0/tests/test_fan.py +621 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/tests/test_lock.py +76 -21
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/tests/test_relay_switch.py +9 -30
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/tests/test_roller_shade.py +162 -2
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/tests/test_smart_thermostat_radiator.py +6 -24
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/tests/test_strip_light.py +119 -42
- pyswitchbot-2.0.1/switchbot/adv_parsers/fan.py +0 -33
- pyswitchbot-2.0.1/switchbot/const/fan.py +0 -14
- pyswitchbot-2.0.1/switchbot/devices/fan.py +0 -103
- pyswitchbot-2.0.1/tests/test_fan.py +0 -177
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/LICENSE +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/MANIFEST.in +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/PySwitchbot.egg-info/dependency_links.txt +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/PySwitchbot.egg-info/requires.txt +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/PySwitchbot.egg-info/top_level.txt +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/README.md +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/pyproject.toml +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/setup.cfg +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/adv_parsers/__init__.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/adv_parsers/air_purifier.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/adv_parsers/art_frame.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/adv_parsers/blind_tilt.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/adv_parsers/bot.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/adv_parsers/bulb.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/adv_parsers/ceiling_light.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/adv_parsers/climate_panel.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/adv_parsers/contact.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/adv_parsers/curtain.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/adv_parsers/hub2.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/adv_parsers/hub3.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/adv_parsers/hubmini_matter.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/adv_parsers/humidifier.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/adv_parsers/keypad.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/adv_parsers/keypad_vision.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/adv_parsers/leak.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/adv_parsers/lock.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/adv_parsers/motion.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/adv_parsers/plug.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/adv_parsers/presence_sensor.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/adv_parsers/relay_switch.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/adv_parsers/remote.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/adv_parsers/roller_shade.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/adv_parsers/smart_thermostat_radiator.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/adv_parsers/vacuum.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/api_config.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/const/air_purifier.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/const/climate.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/const/evaporative_humidifier.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/const/hub2.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/const/hub3.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/const/lock.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/const/presence_sensor.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/devices/__init__.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/devices/base_cover.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/devices/base_light.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/devices/blind_tilt.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/devices/bot.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/devices/bulb.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/devices/ceiling_light.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/devices/contact.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/devices/curtain.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/devices/humidifier.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/devices/keypad.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/devices/meter.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/devices/meter_pro.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/devices/motion.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/devices/plug.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/devices/vacuum.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/discovery.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/enum.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/helpers.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/models.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/switchbot/utils.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/tests/test_base_cover.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/tests/test_blind_tilt.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/tests/test_bulb.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/tests/test_ceiling_light.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/tests/test_colormode_imports.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/tests/test_curtain.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/tests/test_device.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/tests/test_discovery_callback.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/tests/test_helpers.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/tests/test_hub2.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/tests/test_hub3.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/tests/test_keypad_vision.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/tests/test_meter_pro.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/tests/test_utils.py +0 -0
- {pyswitchbot-2.0.1 → pyswitchbot-2.2.0}/tests/test_vacuum.py +0 -0
|
@@ -17,6 +17,7 @@ switchbot/helpers.py
|
|
|
17
17
|
switchbot/models.py
|
|
18
18
|
switchbot/utils.py
|
|
19
19
|
switchbot/adv_parsers/__init__.py
|
|
20
|
+
switchbot/adv_parsers/_sensor_th.py
|
|
20
21
|
switchbot/adv_parsers/air_purifier.py
|
|
21
22
|
switchbot/adv_parsers/art_frame.py
|
|
22
23
|
switchbot/adv_parsers/blind_tilt.py
|
|
@@ -45,6 +46,7 @@ switchbot/adv_parsers/remote.py
|
|
|
45
46
|
switchbot/adv_parsers/roller_shade.py
|
|
46
47
|
switchbot/adv_parsers/smart_thermostat_radiator.py
|
|
47
48
|
switchbot/adv_parsers/vacuum.py
|
|
49
|
+
switchbot/adv_parsers/weather_station.py
|
|
48
50
|
switchbot/const/__init__.py
|
|
49
51
|
switchbot/const/air_purifier.py
|
|
50
52
|
switchbot/const/climate.py
|
|
@@ -18,16 +18,20 @@ from .const import (
|
|
|
18
18
|
ClimateMode,
|
|
19
19
|
ColorMode,
|
|
20
20
|
FanMode,
|
|
21
|
+
HorizontalOscillationAngle,
|
|
21
22
|
HumidifierAction,
|
|
22
23
|
HumidifierMode,
|
|
23
24
|
HumidifierWaterLevel,
|
|
24
25
|
LockStatus,
|
|
26
|
+
NightLightState,
|
|
25
27
|
SmartThermostatRadiatorMode,
|
|
28
|
+
StandingFanMode,
|
|
26
29
|
StripLightColorMode,
|
|
27
30
|
SwitchbotAccountConnectionError,
|
|
28
31
|
SwitchbotApiError,
|
|
29
32
|
SwitchbotAuthenticationError,
|
|
30
33
|
SwitchbotModel,
|
|
34
|
+
VerticalOscillationAngle,
|
|
31
35
|
)
|
|
32
36
|
from .devices.air_purifier import SwitchbotAirPurifier
|
|
33
37
|
from .devices.art_frame import SwitchbotArtFrame
|
|
@@ -44,12 +48,15 @@ from .devices.device import (
|
|
|
44
48
|
fetch_cloud_devices,
|
|
45
49
|
)
|
|
46
50
|
from .devices.evaporative_humidifier import SwitchbotEvaporativeHumidifier
|
|
47
|
-
from .devices.fan import SwitchbotFan
|
|
51
|
+
from .devices.fan import SwitchbotFan, SwitchbotStandingFan
|
|
48
52
|
from .devices.humidifier import SwitchbotHumidifier
|
|
49
53
|
from .devices.keypad_vision import SwitchbotKeypadVision
|
|
50
54
|
from .devices.light_strip import (
|
|
55
|
+
SwitchbotCandleWarmerLamp,
|
|
51
56
|
SwitchbotLightStrip,
|
|
57
|
+
SwitchbotPermanentOutdoorLight,
|
|
52
58
|
SwitchbotRgbicLight,
|
|
59
|
+
SwitchbotRgbicNeonLight,
|
|
53
60
|
SwitchbotStripLight3,
|
|
54
61
|
)
|
|
55
62
|
from .devices.lock import SwitchbotLock
|
|
@@ -76,11 +83,14 @@ __all__ = [
|
|
|
76
83
|
"ColorMode",
|
|
77
84
|
"FanMode",
|
|
78
85
|
"GetSwitchbotDevices",
|
|
86
|
+
"HorizontalOscillationAngle",
|
|
79
87
|
"HumidifierAction",
|
|
80
88
|
"HumidifierMode",
|
|
81
89
|
"HumidifierWaterLevel",
|
|
82
90
|
"LockStatus",
|
|
91
|
+
"NightLightState",
|
|
83
92
|
"SmartThermostatRadiatorMode",
|
|
93
|
+
"StandingFanMode",
|
|
84
94
|
"StripLightColorMode",
|
|
85
95
|
"SwitchBotAdvertisement",
|
|
86
96
|
"Switchbot",
|
|
@@ -93,6 +103,7 @@ __all__ = [
|
|
|
93
103
|
"SwitchbotBaseLight",
|
|
94
104
|
"SwitchbotBlindTilt",
|
|
95
105
|
"SwitchbotBulb",
|
|
106
|
+
"SwitchbotCandleWarmerLamp",
|
|
96
107
|
"SwitchbotCeilingLight",
|
|
97
108
|
"SwitchbotCurtain",
|
|
98
109
|
"SwitchbotDevice",
|
|
@@ -108,17 +119,21 @@ __all__ = [
|
|
|
108
119
|
"SwitchbotModel",
|
|
109
120
|
"SwitchbotModel",
|
|
110
121
|
"SwitchbotOperationError",
|
|
122
|
+
"SwitchbotPermanentOutdoorLight",
|
|
111
123
|
"SwitchbotPlugMini",
|
|
112
124
|
"SwitchbotPlugMini",
|
|
113
125
|
"SwitchbotRelaySwitch",
|
|
114
126
|
"SwitchbotRelaySwitch2PM",
|
|
115
127
|
"SwitchbotRgbicLight",
|
|
128
|
+
"SwitchbotRgbicNeonLight",
|
|
116
129
|
"SwitchbotRollerShade",
|
|
117
130
|
"SwitchbotSmartThermostatRadiator",
|
|
131
|
+
"SwitchbotStandingFan",
|
|
118
132
|
"SwitchbotStripLight3",
|
|
119
133
|
"SwitchbotSupportedType",
|
|
120
134
|
"SwitchbotSupportedType",
|
|
121
135
|
"SwitchbotVacuum",
|
|
136
|
+
"VerticalOscillationAngle",
|
|
122
137
|
"close_stale_connections",
|
|
123
138
|
"close_stale_connections_by_address",
|
|
124
139
|
"fetch_cloud_devices",
|
|
@@ -20,7 +20,7 @@ from .adv_parsers.ceiling_light import process_woceiling
|
|
|
20
20
|
from .adv_parsers.climate_panel import process_climate_panel
|
|
21
21
|
from .adv_parsers.contact import process_wocontact
|
|
22
22
|
from .adv_parsers.curtain import process_wocurtain
|
|
23
|
-
from .adv_parsers.fan import process_fan
|
|
23
|
+
from .adv_parsers.fan import process_fan, process_standing_fan
|
|
24
24
|
from .adv_parsers.hub2 import process_wohub2
|
|
25
25
|
from .adv_parsers.hub3 import process_hub3
|
|
26
26
|
from .adv_parsers.hubmini_matter import process_hubmini_matter
|
|
@@ -28,7 +28,12 @@ from .adv_parsers.humidifier import process_evaporative_humidifier, process_wohu
|
|
|
28
28
|
from .adv_parsers.keypad import process_wokeypad
|
|
29
29
|
from .adv_parsers.keypad_vision import process_keypad_vision, process_keypad_vision_pro
|
|
30
30
|
from .adv_parsers.leak import process_leak
|
|
31
|
-
from .adv_parsers.light_strip import
|
|
31
|
+
from .adv_parsers.light_strip import (
|
|
32
|
+
process_candle_warmer_lamp,
|
|
33
|
+
process_light,
|
|
34
|
+
process_rgbic_light,
|
|
35
|
+
process_wostrip,
|
|
36
|
+
)
|
|
32
37
|
from .adv_parsers.lock import (
|
|
33
38
|
process_lock2,
|
|
34
39
|
process_locklite,
|
|
@@ -49,6 +54,7 @@ from .adv_parsers.remote import process_woremote
|
|
|
49
54
|
from .adv_parsers.roller_shade import process_worollershade
|
|
50
55
|
from .adv_parsers.smart_thermostat_radiator import process_smart_thermostat_radiator
|
|
51
56
|
from .adv_parsers.vacuum import process_vacuum, process_vacuum_k
|
|
57
|
+
from .adv_parsers.weather_station import process_weather_station
|
|
52
58
|
from .const import SwitchbotModel
|
|
53
59
|
from .models import SwitchBotAdvertisement
|
|
54
60
|
from .utils import format_mac_upper
|
|
@@ -69,7 +75,7 @@ class SwitchbotSupportedType(TypedDict):
|
|
|
69
75
|
|
|
70
76
|
modelName: SwitchbotModel
|
|
71
77
|
modelFriendlyName: str
|
|
72
|
-
func: Callable[[bytes, bytes | None], dict[str, bool | int]]
|
|
78
|
+
func: Callable[[bytes | None, bytes | None], dict[str, bool | int | str | None]]
|
|
73
79
|
manufacturer_id: int | None
|
|
74
80
|
manufacturer_data_length: int | None
|
|
75
81
|
|
|
@@ -611,6 +617,18 @@ SUPPORTED_TYPES: dict[str | bytes, SwitchbotSupportedType] = {
|
|
|
611
617
|
"func": process_light,
|
|
612
618
|
"manufacturer_id": 2409,
|
|
613
619
|
},
|
|
620
|
+
b"\x00\x11\x22\xb8": {
|
|
621
|
+
"modelName": SwitchbotModel.CANDLE_WARMER_LAMP,
|
|
622
|
+
"modelFriendlyName": "Candle Warmer Lamp",
|
|
623
|
+
"func": process_candle_warmer_lamp,
|
|
624
|
+
"manufacturer_id": 2409,
|
|
625
|
+
},
|
|
626
|
+
b"\x01\x11\x22\xb8": {
|
|
627
|
+
"modelName": SwitchbotModel.CANDLE_WARMER_LAMP,
|
|
628
|
+
"modelFriendlyName": "Candle Warmer Lamp",
|
|
629
|
+
"func": process_candle_warmer_lamp,
|
|
630
|
+
"manufacturer_id": 2409,
|
|
631
|
+
},
|
|
614
632
|
b"\x00\x10\xd0\xb1": {
|
|
615
633
|
"modelName": SwitchbotModel.STRIP_LIGHT_3,
|
|
616
634
|
"modelFriendlyName": "Strip Light 3",
|
|
@@ -659,6 +677,42 @@ SUPPORTED_TYPES: dict[str | bytes, SwitchbotSupportedType] = {
|
|
|
659
677
|
"func": process_rgbic_light,
|
|
660
678
|
"manufacturer_id": 2409,
|
|
661
679
|
},
|
|
680
|
+
b"\x00\x10\xd0\xb7": {
|
|
681
|
+
"modelName": SwitchbotModel.PERMANENT_OUTDOOR_LIGHT,
|
|
682
|
+
"modelFriendlyName": "Permanent Outdoor Light",
|
|
683
|
+
"func": process_rgbic_light,
|
|
684
|
+
"manufacturer_id": 2409,
|
|
685
|
+
},
|
|
686
|
+
b"\x01\x10\xd0\xb7": {
|
|
687
|
+
"modelName": SwitchbotModel.PERMANENT_OUTDOOR_LIGHT,
|
|
688
|
+
"modelFriendlyName": "Permanent Outdoor Light",
|
|
689
|
+
"func": process_rgbic_light,
|
|
690
|
+
"manufacturer_id": 2409,
|
|
691
|
+
},
|
|
692
|
+
b"\x00\x10\xd0\xb5": {
|
|
693
|
+
"modelName": SwitchbotModel.RGBIC_NEON_WIRE_ROPE_LIGHT,
|
|
694
|
+
"modelFriendlyName": "RGBIC Neon Wire Rope Light",
|
|
695
|
+
"func": process_wostrip,
|
|
696
|
+
"manufacturer_id": 2409,
|
|
697
|
+
},
|
|
698
|
+
b"\x00\x10\xd0\xb6": {
|
|
699
|
+
"modelName": SwitchbotModel.RGBIC_NEON_ROPE_LIGHT,
|
|
700
|
+
"modelFriendlyName": "RGBIC Neon Rope Light",
|
|
701
|
+
"func": process_wostrip,
|
|
702
|
+
"manufacturer_id": 2409,
|
|
703
|
+
},
|
|
704
|
+
b"\x01\x10\xd0\xb5": {
|
|
705
|
+
"modelName": SwitchbotModel.RGBIC_NEON_WIRE_ROPE_LIGHT,
|
|
706
|
+
"modelFriendlyName": "RGBIC Neon Wire Rope Light",
|
|
707
|
+
"func": process_wostrip,
|
|
708
|
+
"manufacturer_id": 2409,
|
|
709
|
+
},
|
|
710
|
+
b"\x01\x10\xd0\xb6": {
|
|
711
|
+
"modelName": SwitchbotModel.RGBIC_NEON_ROPE_LIGHT,
|
|
712
|
+
"modelFriendlyName": "RGBIC Neon Rope Light",
|
|
713
|
+
"func": process_wostrip,
|
|
714
|
+
"manufacturer_id": 2409,
|
|
715
|
+
},
|
|
662
716
|
b"\x00\x10\xfb\xa8": {
|
|
663
717
|
"modelName": SwitchbotModel.K11_VACUUM,
|
|
664
718
|
"modelFriendlyName": "K11+ Vacuum",
|
|
@@ -791,6 +845,30 @@ SUPPORTED_TYPES: dict[str | bytes, SwitchbotSupportedType] = {
|
|
|
791
845
|
"func": process_wolock_pro,
|
|
792
846
|
"manufacturer_id": 2409,
|
|
793
847
|
},
|
|
848
|
+
b"\x00\x11\x07\x60": {
|
|
849
|
+
"modelName": SwitchbotModel.STANDING_FAN,
|
|
850
|
+
"modelFriendlyName": "Standing Fan",
|
|
851
|
+
"func": process_standing_fan,
|
|
852
|
+
"manufacturer_id": 2409,
|
|
853
|
+
},
|
|
854
|
+
b"\x01\x11\x07\x60": {
|
|
855
|
+
"modelName": SwitchbotModel.STANDING_FAN,
|
|
856
|
+
"modelFriendlyName": "Standing Fan",
|
|
857
|
+
"func": process_standing_fan,
|
|
858
|
+
"manufacturer_id": 2409,
|
|
859
|
+
},
|
|
860
|
+
b"\x00\x10\x53\xb0": {
|
|
861
|
+
"modelName": SwitchbotModel.WEATHER_STATION,
|
|
862
|
+
"modelFriendlyName": "Weather Station",
|
|
863
|
+
"func": process_weather_station,
|
|
864
|
+
"manufacturer_id": 2409,
|
|
865
|
+
},
|
|
866
|
+
b"\x01\x10\x53\xb0": {
|
|
867
|
+
"modelName": SwitchbotModel.WEATHER_STATION,
|
|
868
|
+
"modelFriendlyName": "Weather Station",
|
|
869
|
+
"func": process_weather_station,
|
|
870
|
+
"manufacturer_id": 2409,
|
|
871
|
+
},
|
|
794
872
|
}
|
|
795
873
|
|
|
796
874
|
_SWITCHBOT_MODEL_TO_CHAR: defaultdict[SwitchbotModel, list[str | bytes]] = defaultdict(
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""Shared temperature/humidity decoding helpers for T/H sensors."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from ..helpers import celsius_to_fahrenheit
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def decode_temp_humidity(temp_data: bytes, battery: int | None) -> dict[str, Any]:
|
|
11
|
+
"""
|
|
12
|
+
Decode temperature/humidity/fahrenheit-flag from a 3-byte payload.
|
|
13
|
+
|
|
14
|
+
Layout (bytes after company ID, for SwitchBot T/H sensors):
|
|
15
|
+
byte 0: bits[3:0] = temperature decimal (0.1 °C units)
|
|
16
|
+
byte 1: bit[7] = temperature sign (1 = positive), bits[6:0] = integer °C
|
|
17
|
+
byte 2: bit[7] = fahrenheit-display flag, bits[6:0] = humidity %
|
|
18
|
+
"""
|
|
19
|
+
_temp_sign = 1 if temp_data[1] & 0b10000000 else -1
|
|
20
|
+
_temp_c = _temp_sign * (
|
|
21
|
+
(temp_data[1] & 0b01111111) + ((temp_data[0] & 0b00001111) / 10)
|
|
22
|
+
)
|
|
23
|
+
_temp_f = celsius_to_fahrenheit(_temp_c)
|
|
24
|
+
_temp_f = (_temp_f * 10) / 10
|
|
25
|
+
humidity = temp_data[2] & 0b01111111
|
|
26
|
+
|
|
27
|
+
if _temp_c == 0 and humidity == 0 and battery == 0:
|
|
28
|
+
return {}
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
"temp": {"c": _temp_c, "f": _temp_f},
|
|
32
|
+
"temperature": _temp_c,
|
|
33
|
+
"fahrenheit": bool(temp_data[2] & 0b10000000),
|
|
34
|
+
"humidity": humidity,
|
|
35
|
+
"battery": battery,
|
|
36
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""Fan adv parser."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from ..const.fan import FanMode, StandingFanMode
|
|
6
|
+
|
|
7
|
+
_FAN_MODE_MAP: dict[int, str] = {m.value: m.name.lower() for m in FanMode}
|
|
8
|
+
_STANDING_FAN_MODE_MAP: dict[int, str] = {
|
|
9
|
+
m.value: m.name.lower() for m in StandingFanMode
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _parse_fan(
|
|
14
|
+
mfr_data: bytes | None, mode_map: dict[int, str]
|
|
15
|
+
) -> dict[str, bool | int | str | None]:
|
|
16
|
+
"""Shared fan advertisement parse, parameterized on the mode map."""
|
|
17
|
+
if mfr_data is None:
|
|
18
|
+
return {}
|
|
19
|
+
|
|
20
|
+
device_data = mfr_data[6:]
|
|
21
|
+
|
|
22
|
+
_seq_num = device_data[0]
|
|
23
|
+
_isOn = bool(device_data[1] & 0b10000000)
|
|
24
|
+
_mode = (device_data[1] & 0b01110000) >> 4
|
|
25
|
+
_nightLight = (device_data[1] & 0b00001100) >> 2
|
|
26
|
+
_oscillate_left_and_right = bool(device_data[1] & 0b00000010)
|
|
27
|
+
_oscillate_up_and_down = bool(device_data[1] & 0b00000001)
|
|
28
|
+
_battery = device_data[2] & 0b01111111
|
|
29
|
+
_speed = device_data[3] & 0b01111111
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
"sequence_number": _seq_num,
|
|
33
|
+
"isOn": _isOn,
|
|
34
|
+
"mode": mode_map.get(_mode),
|
|
35
|
+
"nightLight": _nightLight,
|
|
36
|
+
"oscillating": _oscillate_left_and_right or _oscillate_up_and_down,
|
|
37
|
+
"oscillating_horizontal": _oscillate_left_and_right,
|
|
38
|
+
"oscillating_vertical": _oscillate_up_and_down,
|
|
39
|
+
"battery": _battery,
|
|
40
|
+
"speed": _speed,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def process_fan(
|
|
45
|
+
data: bytes | None, mfr_data: bytes | None
|
|
46
|
+
) -> dict[str, bool | int | str | None]:
|
|
47
|
+
"""Process Circulator Fan services data (modes 1-4)."""
|
|
48
|
+
return _parse_fan(mfr_data, _FAN_MODE_MAP)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def process_standing_fan(
|
|
52
|
+
data: bytes | None, mfr_data: bytes | None
|
|
53
|
+
) -> dict[str, bool | int | str | None]:
|
|
54
|
+
"""Process Standing Fan services data (modes 1-5; adds CUSTOM_NATURAL)."""
|
|
55
|
+
return _parse_fan(mfr_data, _STANDING_FAN_MODE_MAP)
|
|
@@ -21,6 +21,21 @@ def process_wostrip(
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
|
|
24
|
+
def process_candle_warmer_lamp(
|
|
25
|
+
data: bytes | None, mfr_data: bytes | None
|
|
26
|
+
) -> dict[str, bool | int]:
|
|
27
|
+
"""Process Candle Warmer Lamp services data."""
|
|
28
|
+
if mfr_data is None:
|
|
29
|
+
return {}
|
|
30
|
+
return {
|
|
31
|
+
"sequence_number": mfr_data[6],
|
|
32
|
+
"isOn": bool(mfr_data[7] & 0b10000000),
|
|
33
|
+
"brightness": mfr_data[7] & 0b01111111,
|
|
34
|
+
"delay": bool(mfr_data[8] & 0b10000000),
|
|
35
|
+
"network_state": (mfr_data[8] & 0b01110000) >> 4,
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
24
39
|
def process_light(
|
|
25
40
|
data: bytes | None, mfr_data: bytes | None, cw_offset: int = 16
|
|
26
41
|
) -> dict[str, bool | int]:
|
|
@@ -5,7 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
import struct
|
|
6
6
|
from typing import Any
|
|
7
7
|
|
|
8
|
-
from
|
|
8
|
+
from ._sensor_th import decode_temp_humidity
|
|
9
9
|
|
|
10
10
|
CO2_UNPACK = struct.Struct(">H").unpack_from
|
|
11
11
|
|
|
@@ -13,7 +13,7 @@ CO2_UNPACK = struct.Struct(">H").unpack_from
|
|
|
13
13
|
def process_wosensorth(data: bytes | None, mfr_data: bytes | None) -> dict[str, Any]:
|
|
14
14
|
"""Process woSensorTH/Temp sensor services data."""
|
|
15
15
|
temp_data: bytes | None = None
|
|
16
|
-
battery:
|
|
16
|
+
battery: int | None = None
|
|
17
17
|
|
|
18
18
|
if mfr_data:
|
|
19
19
|
temp_data = mfr_data[8:11]
|
|
@@ -26,25 +26,7 @@ def process_wosensorth(data: bytes | None, mfr_data: bytes | None) -> dict[str,
|
|
|
26
26
|
if not temp_data:
|
|
27
27
|
return {}
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
_temp_c = _temp_sign * (
|
|
31
|
-
(temp_data[1] & 0b01111111) + ((temp_data[0] & 0b00001111) / 10)
|
|
32
|
-
)
|
|
33
|
-
_temp_f = celsius_to_fahrenheit(_temp_c)
|
|
34
|
-
_temp_f = (_temp_f * 10) / 10
|
|
35
|
-
humidity = temp_data[2] & 0b01111111
|
|
36
|
-
|
|
37
|
-
if _temp_c == 0 and humidity == 0 and battery == 0:
|
|
38
|
-
return {}
|
|
39
|
-
|
|
40
|
-
return {
|
|
41
|
-
# Data should be flat, but we keep the original structure for now
|
|
42
|
-
"temp": {"c": _temp_c, "f": _temp_f},
|
|
43
|
-
"temperature": _temp_c,
|
|
44
|
-
"fahrenheit": bool(temp_data[2] & 0b10000000),
|
|
45
|
-
"humidity": humidity,
|
|
46
|
-
"battery": battery,
|
|
47
|
-
}
|
|
29
|
+
return decode_temp_humidity(temp_data, battery)
|
|
48
30
|
|
|
49
31
|
|
|
50
32
|
def process_wosensorth_c(data: bytes | None, mfr_data: bytes | None) -> dict[str, Any]:
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""Weather Station parser."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from ._sensor_th import decode_temp_humidity
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def process_weather_station(
|
|
11
|
+
data: bytes | None, mfr_data: bytes | None
|
|
12
|
+
) -> dict[str, Any]:
|
|
13
|
+
"""
|
|
14
|
+
Process Weather Station advertisement data.
|
|
15
|
+
|
|
16
|
+
Manufacturer data layout (mfr_id=2409, after company ID stripped by bleak):
|
|
17
|
+
Byte 0-5: MAC address
|
|
18
|
+
Byte 6: Sequence number
|
|
19
|
+
Byte 7: Battery (bit7=charging, bit6-0=level%)
|
|
20
|
+
Byte 8: Temp alarm(bit7-6), Humidity alarm(bit5-4), Temp decimal(bit3-0)
|
|
21
|
+
Byte 9: Temp sign(bit7: 0=neg,1=pos), Temp integer(bit6-0)
|
|
22
|
+
Byte 10: Fahrenheit flag(bit7), Humidity(bit6-0)
|
|
23
|
+
"""
|
|
24
|
+
temp_data: bytes | None = None
|
|
25
|
+
battery: int | None = None
|
|
26
|
+
|
|
27
|
+
if mfr_data and len(mfr_data) >= 11:
|
|
28
|
+
temp_data = mfr_data[8:11]
|
|
29
|
+
battery = mfr_data[7] & 0b01111111
|
|
30
|
+
|
|
31
|
+
if data and len(data) >= 6:
|
|
32
|
+
if not temp_data:
|
|
33
|
+
temp_data = data[3:6]
|
|
34
|
+
if battery is None:
|
|
35
|
+
battery = data[2] & 0b01111111
|
|
36
|
+
|
|
37
|
+
if not temp_data:
|
|
38
|
+
return {}
|
|
39
|
+
|
|
40
|
+
return decode_temp_humidity(temp_data, battery)
|
|
@@ -10,7 +10,13 @@ from .evaporative_humidifier import (
|
|
|
10
10
|
HumidifierMode,
|
|
11
11
|
HumidifierWaterLevel,
|
|
12
12
|
)
|
|
13
|
-
from .fan import
|
|
13
|
+
from .fan import (
|
|
14
|
+
FanMode,
|
|
15
|
+
HorizontalOscillationAngle,
|
|
16
|
+
NightLightState,
|
|
17
|
+
StandingFanMode,
|
|
18
|
+
VerticalOscillationAngle,
|
|
19
|
+
)
|
|
14
20
|
from .light import (
|
|
15
21
|
BulbColorMode,
|
|
16
22
|
CeilingLightColorMode,
|
|
@@ -80,6 +86,7 @@ class SwitchbotModel(StrEnum):
|
|
|
80
86
|
ROLLER_SHADE = "Roller Shade"
|
|
81
87
|
HUBMINI_MATTER = "HubMini Matter"
|
|
82
88
|
CIRCULATOR_FAN = "Circulator Fan"
|
|
89
|
+
STANDING_FAN = "Standing Fan"
|
|
83
90
|
K20_VACUUM = "K20 Vacuum"
|
|
84
91
|
S10_VACUUM = "S10 Vacuum"
|
|
85
92
|
K10_VACUUM = "K10+ Vacuum"
|
|
@@ -96,9 +103,13 @@ class SwitchbotModel(StrEnum):
|
|
|
96
103
|
RELAY_SWITCH_2PM = "Relay Switch 2PM"
|
|
97
104
|
STRIP_LIGHT_3 = "Strip Light 3"
|
|
98
105
|
FLOOR_LAMP = "Floor Lamp"
|
|
106
|
+
CANDLE_WARMER_LAMP = "Candle Warmer Lamp"
|
|
99
107
|
PLUG_MINI_EU = "Plug Mini (EU)"
|
|
100
108
|
RGBICWW_STRIP_LIGHT = "RGBICWW Strip Light"
|
|
101
109
|
RGBICWW_FLOOR_LAMP = "RGBICWW Floor Lamp"
|
|
110
|
+
PERMANENT_OUTDOOR_LIGHT = "Permanent Outdoor Light"
|
|
111
|
+
RGBIC_NEON_ROPE_LIGHT = "RGBIC Neon Rope Light"
|
|
112
|
+
RGBIC_NEON_WIRE_ROPE_LIGHT = "RGBIC Neon Wire Rope Light"
|
|
102
113
|
K11_VACUUM = "K11+ Vacuum"
|
|
103
114
|
CLIMATE_PANEL = "Climate Panel"
|
|
104
115
|
SMART_THERMOSTAT_RADIATOR = "Smart Thermostat Radiator"
|
|
@@ -110,6 +121,7 @@ class SwitchbotModel(StrEnum):
|
|
|
110
121
|
LOCK_VISION_PRO = "Lock Vision Pro"
|
|
111
122
|
LOCK_VISION = "Lock Vision"
|
|
112
123
|
LOCK_PRO_WIFI = "Lock Pro Wifi"
|
|
124
|
+
WEATHER_STATION = "Weather Station"
|
|
113
125
|
|
|
114
126
|
|
|
115
127
|
__all__ = [
|
|
@@ -124,14 +136,18 @@ __all__ = [
|
|
|
124
136
|
"ClimateMode",
|
|
125
137
|
"ColorMode",
|
|
126
138
|
"FanMode",
|
|
139
|
+
"HorizontalOscillationAngle",
|
|
127
140
|
"HumidifierAction",
|
|
128
141
|
"HumidifierMode",
|
|
129
142
|
"HumidifierWaterLevel",
|
|
130
143
|
"LockStatus",
|
|
144
|
+
"NightLightState",
|
|
131
145
|
"SmartThermostatRadiatorMode",
|
|
146
|
+
"StandingFanMode",
|
|
132
147
|
"StripLightColorMode",
|
|
133
148
|
"SwitchbotAccountConnectionError",
|
|
134
149
|
"SwitchbotApiError",
|
|
135
150
|
"SwitchbotAuthenticationError",
|
|
136
151
|
"SwitchbotModel",
|
|
152
|
+
"VerticalOscillationAngle",
|
|
137
153
|
]
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from enum import Enum
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class FanMode(Enum):
|
|
7
|
+
NORMAL = 1
|
|
8
|
+
NATURAL = 2
|
|
9
|
+
SLEEP = 3
|
|
10
|
+
BABY = 4
|
|
11
|
+
|
|
12
|
+
@classmethod
|
|
13
|
+
def get_modes(cls) -> list[str]:
|
|
14
|
+
return [mode.name.lower() for mode in cls]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class StandingFanMode(Enum):
|
|
18
|
+
NORMAL = 1
|
|
19
|
+
NATURAL = 2
|
|
20
|
+
SLEEP = 3
|
|
21
|
+
BABY = 4
|
|
22
|
+
CUSTOM_NATURAL = 5
|
|
23
|
+
|
|
24
|
+
@classmethod
|
|
25
|
+
def get_modes(cls) -> list[str]:
|
|
26
|
+
return [mode.name.lower() for mode in cls]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class NightLightState(Enum):
|
|
30
|
+
"""Standing Fan night-light command values."""
|
|
31
|
+
|
|
32
|
+
LEVEL_1 = 1
|
|
33
|
+
LEVEL_2 = 2
|
|
34
|
+
OFF = 3
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class HorizontalOscillationAngle(Enum):
|
|
38
|
+
"""
|
|
39
|
+
Horizontal oscillation angle command values.
|
|
40
|
+
|
|
41
|
+
For the horizontal axis the device byte is the same as the
|
|
42
|
+
user-facing angle in degrees.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
ANGLE_30 = 30
|
|
46
|
+
ANGLE_60 = 60
|
|
47
|
+
ANGLE_90 = 90
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class VerticalOscillationAngle(Enum):
|
|
51
|
+
"""
|
|
52
|
+
Vertical oscillation angle command values.
|
|
53
|
+
|
|
54
|
+
The Standing Fan uses a different byte encoding on the vertical axis
|
|
55
|
+
than on the horizontal one. Byte 0x5A (decimal 90) is interpreted as
|
|
56
|
+
an axis halt, so 90° maps to byte 0x5F (95). 30° and 60° match their
|
|
57
|
+
degree values.
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
ANGLE_30 = 30
|
|
61
|
+
ANGLE_60 = 60
|
|
62
|
+
ANGLE_90 = 95
|
|
@@ -5,8 +5,6 @@ from __future__ import annotations
|
|
|
5
5
|
import logging
|
|
6
6
|
from typing import Any, ClassVar
|
|
7
7
|
|
|
8
|
-
from bleak.backends.device import BLEDevice
|
|
9
|
-
|
|
10
8
|
from ..adv_parsers.air_purifier import get_air_purifier_mode
|
|
11
9
|
from ..const import SwitchbotModel
|
|
12
10
|
from ..const.air_purifier import AirPurifierMode, AirQualityLevel
|
|
@@ -40,6 +38,7 @@ READ_LED_STATUS_COMMAND = "570f4d07"
|
|
|
40
38
|
class SwitchbotAirPurifier(SwitchbotSequenceBaseLight, SwitchbotEncryptedDevice):
|
|
41
39
|
"""Representation of a Switchbot Air Purifier."""
|
|
42
40
|
|
|
41
|
+
_model = SwitchbotModel.AIR_PURIFIER_US
|
|
43
42
|
_turn_on_command = f"{COMMAND_HEAD}010100"
|
|
44
43
|
_turn_off_command = f"{COMMAND_HEAD}010000"
|
|
45
44
|
_open_child_lock_command = f"{COMMAND_HEAD}0301"
|
|
@@ -78,30 +77,6 @@ class SwitchbotAirPurifier(SwitchbotSequenceBaseLight, SwitchbotEncryptedDevice)
|
|
|
78
77
|
}
|
|
79
78
|
)
|
|
80
79
|
|
|
81
|
-
def __init__(
|
|
82
|
-
self,
|
|
83
|
-
device: BLEDevice,
|
|
84
|
-
key_id: str,
|
|
85
|
-
encryption_key: str,
|
|
86
|
-
interface: int = 0,
|
|
87
|
-
model: SwitchbotModel = SwitchbotModel.AIR_PURIFIER_US,
|
|
88
|
-
**kwargs: Any,
|
|
89
|
-
) -> None:
|
|
90
|
-
super().__init__(device, key_id, encryption_key, model, interface, **kwargs)
|
|
91
|
-
|
|
92
|
-
@classmethod
|
|
93
|
-
async def verify_encryption_key(
|
|
94
|
-
cls,
|
|
95
|
-
device: BLEDevice,
|
|
96
|
-
key_id: str,
|
|
97
|
-
encryption_key: str,
|
|
98
|
-
model: SwitchbotModel = SwitchbotModel.AIR_PURIFIER_US,
|
|
99
|
-
**kwargs: Any,
|
|
100
|
-
) -> bool:
|
|
101
|
-
return await super().verify_encryption_key(
|
|
102
|
-
device, key_id, encryption_key, model, **kwargs
|
|
103
|
-
)
|
|
104
|
-
|
|
105
80
|
@property
|
|
106
81
|
def color_modes(self) -> set[ColorMode]:
|
|
107
82
|
"""Return the supported color modes."""
|
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
import logging
|
|
4
4
|
from typing import Any
|
|
5
5
|
|
|
6
|
-
from bleak.backends.device import BLEDevice
|
|
7
|
-
|
|
8
6
|
from ..const import SwitchbotModel
|
|
9
7
|
from .device import (
|
|
10
8
|
SwitchbotEncryptedDevice,
|
|
@@ -20,30 +18,8 @@ COMMAND_SET_IMAGE = "570F7A02{}"
|
|
|
20
18
|
class SwitchbotArtFrame(SwitchbotSequenceDevice, SwitchbotEncryptedDevice):
|
|
21
19
|
"""Representation of a Switchbot Art Frame."""
|
|
22
20
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
device: BLEDevice,
|
|
26
|
-
key_id: str,
|
|
27
|
-
encryption_key: str,
|
|
28
|
-
interface: int = 0,
|
|
29
|
-
model: SwitchbotModel = SwitchbotModel.ART_FRAME,
|
|
30
|
-
**kwargs: Any,
|
|
31
|
-
) -> None:
|
|
32
|
-
super().__init__(device, key_id, encryption_key, model, interface, **kwargs)
|
|
33
|
-
self.response_flag = True
|
|
34
|
-
|
|
35
|
-
@classmethod
|
|
36
|
-
async def verify_encryption_key(
|
|
37
|
-
cls,
|
|
38
|
-
device: BLEDevice,
|
|
39
|
-
key_id: str,
|
|
40
|
-
encryption_key: str,
|
|
41
|
-
model: SwitchbotModel = SwitchbotModel.ART_FRAME,
|
|
42
|
-
**kwargs: Any,
|
|
43
|
-
) -> bool:
|
|
44
|
-
return await super().verify_encryption_key(
|
|
45
|
-
device, key_id, encryption_key, model, **kwargs
|
|
46
|
-
)
|
|
21
|
+
_model = SwitchbotModel.ART_FRAME
|
|
22
|
+
response_flag: bool = True
|
|
47
23
|
|
|
48
24
|
async def get_basic_info(self) -> dict[str, Any] | None:
|
|
49
25
|
"""Get device basic settings."""
|