Skip to content

Commit 2f654e6

Browse files
zerzhangpre-commit-ci[bot]bdraco
authored
Optimize evaporative humidifier test (#346)
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 59fb967 commit 2f654e6

File tree

13 files changed

+684
-225
lines changed

13 files changed

+684
-225
lines changed

switchbot/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
from .const import (
1313
AirPurifierMode,
1414
FanMode,
15+
HumidifierAction,
16+
HumidifierMode,
17+
HumidifierWaterLevel,
1518
LockStatus,
1619
SwitchbotAccountConnectionError,
1720
SwitchbotApiError,
@@ -43,6 +46,9 @@
4346
"ColorMode",
4447
"FanMode",
4548
"GetSwitchbotDevices",
49+
"HumidifierAction",
50+
"HumidifierMode",
51+
"HumidifierWaterLevel",
4652
"LockStatus",
4753
"SwitchBotAdvertisement",
4854
"Switchbot",

switchbot/adv_parsers/hub2.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from typing import Any
66

77
from ..const.hub2 import LIGHT_INTENSITY_MAP
8+
from ..helpers import celsius_to_fahrenheit
89

910

1011
def process_wohub2(data: bytes | None, mfr_data: bytes | None) -> dict[str, Any]:
@@ -22,7 +23,7 @@ def process_wohub2(data: bytes | None, mfr_data: bytes | None) -> dict[str, Any]
2223
_temp_c = _temp_sign * (
2324
(temp_data[1] & 0b01111111) + ((temp_data[0] & 0b00001111) / 10)
2425
)
25-
_temp_f = (_temp_c * 9 / 5) + 32
26+
_temp_f = celsius_to_fahrenheit(_temp_c)
2627
_temp_f = (_temp_f * 10) / 10
2728
humidity = temp_data[2] & 0b01111111
2829
light_level = status & 0b11111

switchbot/adv_parsers/hub3.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from typing import Any
66

77
from ..const.hub3 import LIGHT_INTENSITY_MAP
8+
from ..helpers import celsius_to_fahrenheit
89

910

1011
def process_hub3(data: bytes | None, mfr_data: bytes | None) -> dict[str, Any]:
@@ -26,7 +27,7 @@ def process_hub3(data: bytes | None, mfr_data: bytes | None) -> dict[str, Any]:
2627
_temp_c = _temp_sign * (
2728
(temp_data[1] & 0b01111111) + ((temp_data[0] & 0b00001111) / 10)
2829
)
29-
_temp_f = round(((_temp_c * 9 / 5) + 32), 1)
30+
_temp_f = round(celsius_to_fahrenheit(_temp_c), 1)
3031
humidity = temp_data[2] & 0b01111111
3132
motion_detected = bool(device_data[10] & 0b10000000)
3233

switchbot/adv_parsers/hubmini_matter.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
from typing import Any
66

7+
from ..helpers import celsius_to_fahrenheit
8+
79

810
def process_hubmini_matter(
911
data: bytes | None, mfr_data: bytes | None
@@ -21,7 +23,7 @@ def process_hubmini_matter(
2123
_temp_c = _temp_sign * (
2224
(temp_data[1] & 0b01111111) + ((temp_data[0] & 0b00001111) / 10)
2325
)
24-
_temp_f = (_temp_c * 9 / 5) + 32
26+
_temp_f = celsius_to_fahrenheit(_temp_c)
2527
_temp_f = (_temp_f * 10) / 10
2628
humidity = temp_data[2] & 0b01111111
2729

switchbot/adv_parsers/humidifier.py

Lines changed: 53 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,10 @@
66
from datetime import timedelta
77

88
from ..const.evaporative_humidifier import (
9-
OVER_HUMIDIFY_PROTECTION_MODES,
10-
TARGET_HUMIDITY_MODES,
119
HumidifierMode,
1210
HumidifierWaterLevel,
1311
)
12+
from ..helpers import celsius_to_fahrenheit
1413

1514
_LOGGER = logging.getLogger(__name__)
1615

@@ -23,6 +22,26 @@
2322
# Low: 658000c5222b6300
2423
# Med: 658000c5432b6300
2524
# High: 658000c5642b6300
25+
26+
27+
def calculate_temperature_and_humidity(
28+
data: bytes, is_meter_binded: bool = True
29+
) -> tuple[float | None, float | None, int | None]:
30+
"""Calculate temperature and humidity based on the given flag."""
31+
if len(data) < 3 or not is_meter_binded:
32+
return None, None, None
33+
34+
humidity = data[0] & 0b01111111
35+
if humidity > 100:
36+
return None, None, None
37+
38+
_temp_sign = 1 if data[1] & 0b10000000 else -1
39+
_temp_c = _temp_sign * ((data[1] & 0b01111111) + ((data[2] >> 4) / 10))
40+
_temp_f = celsius_to_fahrenheit(_temp_c)
41+
42+
return _temp_c, _temp_f, humidity
43+
44+
2645
def process_wohumidifier(
2746
data: bytes | None, mfr_data: bytes | None
2847
) -> dict[str, bool | int]:
@@ -46,48 +65,43 @@ def process_evaporative_humidifier(
4665
) -> dict[str, bool | int]:
4766
"""Process WoHumi services data."""
4867
if mfr_data is None:
49-
return {
50-
"isOn": None,
51-
"mode": None,
52-
"target_humidity": None,
53-
"child_lock": None,
54-
"over_humidify_protection": None,
55-
"tank_removed": None,
56-
"tilted_alert": None,
57-
"filter_missing": None,
58-
"humidity": None,
59-
"temperature": None,
60-
"filter_run_time": None,
61-
"filter_alert": None,
62-
"water_level": None,
63-
}
68+
return {}
6469

70+
seq_number = mfr_data[6]
6571
is_on = bool(mfr_data[7] & 0b10000000)
6672
mode = HumidifierMode(mfr_data[7] & 0b00001111)
67-
filter_run_time = timedelta(hours=int.from_bytes(mfr_data[12:14], byteorder="big"))
68-
has_humidity = bool(mfr_data[9] & 0b10000000)
69-
has_temperature = bool(mfr_data[10] & 0b10000000)
70-
is_tank_removed = bool(mfr_data[8] & 0b00000100)
73+
over_humidify_protection = bool(mfr_data[8] & 0b10000000)
74+
child_lock = bool(mfr_data[8] & 0b00100000)
75+
tank_removed = bool(mfr_data[8] & 0b00000100)
76+
tilted_alert = bool(mfr_data[8] & 0b00000010)
77+
filter_missing = bool(mfr_data[8] & 0b00000001)
78+
is_meter_binded = bool(mfr_data[9] & 0b10000000)
79+
80+
_temp_c, _temp_f, humidity = calculate_temperature_and_humidity(
81+
mfr_data[9:12], is_meter_binded
82+
)
83+
84+
water_level = HumidifierWaterLevel(mfr_data[11] & 0b00000011).name.lower()
85+
filter_run_time = timedelta(
86+
hours=int.from_bytes(mfr_data[12:14], byteorder="big") & 0xFFF
87+
)
88+
target_humidity = mfr_data[16] & 0b01111111
89+
7190
return {
91+
"seq_number": seq_number,
7292
"isOn": is_on,
73-
"mode": mode if is_on else None,
74-
"target_humidity": (mfr_data[16] & 0b01111111)
75-
if is_on and mode in TARGET_HUMIDITY_MODES
76-
else None,
77-
"child_lock": bool(mfr_data[8] & 0b00100000),
78-
"over_humidify_protection": bool(mfr_data[8] & 0b10000000)
79-
if is_on and mode in OVER_HUMIDIFY_PROTECTION_MODES
80-
else None,
81-
"tank_removed": is_tank_removed,
82-
"tilted_alert": bool(mfr_data[8] & 0b00000010),
83-
"filter_missing": bool(mfr_data[8] & 0b00000001),
84-
"humidity": (mfr_data[9] & 0b01111111) if has_humidity else None,
85-
"temperature": float(mfr_data[10] & 0b01111111) + float(mfr_data[11] >> 4) / 10
86-
if has_temperature
87-
else None,
93+
"mode": mode,
94+
"over_humidify_protection": over_humidify_protection,
95+
"child_lock": child_lock,
96+
"tank_removed": tank_removed,
97+
"tilted_alert": tilted_alert,
98+
"filter_missing": filter_missing,
99+
"is_meter_binded": is_meter_binded,
100+
"humidity": humidity,
101+
"temperature": _temp_c,
102+
"temp": {"c": _temp_c, "f": _temp_f},
103+
"water_level": water_level,
88104
"filter_run_time": filter_run_time,
89105
"filter_alert": filter_run_time.days >= 10,
90-
"water_level": HumidifierWaterLevel(mfr_data[11] & 0b00000011)
91-
if not is_tank_removed
92-
else None,
106+
"target_humidity": target_humidity,
93107
}

switchbot/adv_parsers/meter.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import struct
66
from typing import Any
77

8+
from ..helpers import celsius_to_fahrenheit
9+
810
CO2_UNPACK = struct.Struct(">H").unpack_from
911

1012

@@ -28,7 +30,7 @@ def process_wosensorth(data: bytes | None, mfr_data: bytes | None) -> dict[str,
2830
_temp_c = _temp_sign * (
2931
(temp_data[1] & 0b01111111) + ((temp_data[0] & 0b00001111) / 10)
3032
)
31-
_temp_f = (_temp_c * 9 / 5) + 32
33+
_temp_f = celsius_to_fahrenheit(_temp_c)
3234
_temp_f = (_temp_f * 10) / 10
3335
humidity = temp_data[2] & 0b01111111
3436

switchbot/const/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44

55
from ..enum import StrEnum
66
from .air_purifier import AirPurifierMode
7+
from .evaporative_humidifier import (
8+
HumidifierAction,
9+
HumidifierMode,
10+
HumidifierWaterLevel,
11+
)
712
from .fan import FanMode
813

914
# Preserve old LockStatus export for backwards compatibility
@@ -86,6 +91,9 @@ class SwitchbotModel(StrEnum):
8691
"DEFAULT_SCAN_TIMEOUT",
8792
"AirPurifierMode",
8893
"FanMode",
94+
"HumidifierAction",
95+
"HumidifierMode",
96+
"HumidifierWaterLevel",
8997
"LockStatus",
9098
"SwitchbotAccountConnectionError",
9199
"SwitchbotApiError",

switchbot/const/evaporative_humidifier.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,27 @@ class HumidifierMode(Enum):
1313
AUTO = 7
1414
DRYING_FILTER = 8
1515

16+
@classmethod
17+
def get_modes(cls) -> list[str]:
18+
return [mode.name.lower() for mode in cls]
19+
1620

1721
class HumidifierWaterLevel(Enum):
1822
EMPTY = 0
1923
LOW = 1
2024
MEDIUM = 2
2125
HIGH = 3
2226

27+
@classmethod
28+
def get_levels(cls) -> list[str]:
29+
return [level.name.lower() for level in cls]
30+
31+
32+
class HumidifierAction(Enum):
33+
OFF = 0
34+
HUMIDIFYING = 1
35+
DRYING = 2
36+
2337

2438
OVER_HUMIDIFY_PROTECTION_MODES = {
2539
HumidifierMode.QUIET,

switchbot/devices/device.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -583,11 +583,11 @@ async def get_device_data(
583583

584584
return self._sb_adv_data
585585

586-
async def _get_basic_info(self) -> bytes | None:
586+
async def _get_basic_info(
587+
self, cmd: str = DEVICE_GET_BASIC_SETTINGS_KEY
588+
) -> bytes | None:
587589
"""Return basic info of device."""
588-
_data = await self._send_command(
589-
key=DEVICE_GET_BASIC_SETTINGS_KEY, retry=self._retry_count
590-
)
590+
_data = await self._send_command(key=cmd, retry=self._retry_count)
591591

592592
if _data in (b"\x07", b"\x00"):
593593
_LOGGER.error("Unsuccessful, please try again")

0 commit comments

Comments
 (0)