Skip to content

Commit 1d8c105

Browse files
authored
Add humidifier (#97)
1 parent 0b992fc commit 1d8c105

File tree

6 files changed

+94
-4
lines changed

6 files changed

+94
-4
lines changed

switchbot/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from .devices.ceiling_light import SwitchbotCeilingLight
1010
from .devices.curtain import SwitchbotCurtain
1111
from .devices.device import ColorMode, SwitchbotDevice
12+
from .devices.humidifer import SwitchbotHumidifier
1213
from .devices.light_strip import SwitchbotLightStrip
1314
from .devices.plug import SwitchbotPlugMini
1415
from .discovery import GetSwitchbotDevices
@@ -25,6 +26,7 @@
2526
"SwitchbotDevice",
2627
"SwitchbotCurtain",
2728
"SwitchbotLightStrip",
29+
"SwitchbotHumidifier",
2830
"Switchbot",
2931
"SwitchbotPlugMini",
3032
"SwitchbotSupportedType",

switchbot/adv_parser.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@
88
from bleak.backends.device import BLEDevice
99
from bleak.backends.scanner import AdvertisementData
1010

11-
from switchbot.adv_parsers.ceiling_light import process_woceiling
12-
1311
from .adv_parsers.bot import process_wohand
1412
from .adv_parsers.bulb import process_color_bulb
13+
from .adv_parsers.ceiling_light import process_woceiling
1514
from .adv_parsers.contact import process_wocontact
1615
from .adv_parsers.curtain import process_wocurtain
16+
from .adv_parsers.humidifier import process_wohumidifier
1717
from .adv_parsers.light_strip import process_wostrip
1818
from .adv_parsers.meter import process_wosensorth
1919
from .adv_parsers.motion import process_wopresence
@@ -83,6 +83,11 @@ class SwitchbotSupportedType(TypedDict):
8383
"modelFriendlyName": "Ceiling Light",
8484
"func": process_woceiling,
8585
},
86+
"e": {
87+
"modelName": SwitchbotModel.HUMIDIFIER,
88+
"modelFriendlyName": "Humidifier",
89+
"func": process_wohumidifier,
90+
},
8691
}
8792

8893

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""Humidifier adv parser."""
2+
from __future__ import annotations
3+
4+
import logging
5+
6+
_LOGGER = logging.getLogger(__name__)
7+
8+
# mfr_data: 943cc68d3d2e
9+
# data: 650000cd802b6300
10+
# data: 650000cd802b6300
11+
# data: 658000c9802b6300
12+
13+
# Low: 658000c5222b6300
14+
# Med: 658000c5432b6300
15+
# High: 658000c5642b6300
16+
def process_wohumidifier(data: bytes, mfr_data: bytes | None) -> dict[str, bool | int]:
17+
"""Process WoHumi services data."""
18+
assert mfr_data is not None
19+
_LOGGER.debug("mfr_data: %s", mfr_data.hex())
20+
_LOGGER.debug("data: %s", data.hex())
21+
22+
return {
23+
"isOn": bool(data[1]),
24+
"level": data[4],
25+
"switchMode": True,
26+
}

switchbot/const.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ class SwitchbotModel(StrEnum):
1212

1313
BOT = "WoHand"
1414
CURTAIN = "WoCurtain"
15+
HUMIDIFIER = "WoHumi"
1516
PLUG_MINI = "WoPlug"
1617
CONTACT_SENSOR = "WoContact"
1718
LIGHT_STRIP = "WoStrip"

switchbot/devices/ceiling_light.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66
from .base_light import SwitchbotBaseLight
77
from .device import REQ_HEADER, ColorMode
88

9-
CEILING_LIGHT_COMMMAND_HEADER = "5401"
9+
CEILING_LIGHT_COMMAND_HEADER = "5401"
1010
CEILING_LIGHT_REQUEST = f"{REQ_HEADER}5501"
1111

12-
CEILING_LIGHT_COMMAND = f"{REQ_HEADER}{CEILING_LIGHT_COMMMAND_HEADER}"
12+
CEILING_LIGHT_COMMAND = f"{REQ_HEADER}{CEILING_LIGHT_COMMAND_HEADER}"
1313
CEILING_LIGHT_ON_KEY = f"{CEILING_LIGHT_COMMAND}01FF01FFFF"
1414
CEILING_LIGHT_OFF_KEY = f"{CEILING_LIGHT_COMMAND}02FF01FFFF"
1515
CW_BRIGHTNESS_KEY = f"{CEILING_LIGHT_COMMAND}010001"

switchbot/devices/humidifier.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
"""Library to handle connection with Switchbot."""
2+
from __future__ import annotations
3+
4+
from .device import REQ_HEADER, SwitchbotDevice
5+
6+
HUMIDIFIER_COMMAND_HEADER = "4381"
7+
HUMIDIFIER_REQUEST = f"{REQ_HEADER}4481"
8+
HUMIDIFIER_COMMAND = f"{REQ_HEADER}{HUMIDIFIER_COMMAND_HEADER}"
9+
HUMIDIFIER_OFF_KEY = f"{HUMIDIFIER_COMMAND}010080FFFFFFFF"
10+
HUMIDIFIER_ON_KEY = f"{HUMIDIFIER_COMMAND}010180FFFFFFFF"
11+
##
12+
# OFF 570F 4381 0100 80FF FFFF FF
13+
# ON 570F 4381 0101 80FF FFFF FF
14+
# AUTO 570F 4381 0101 80FF FFFF FF
15+
# 1. 570F 4381 0101 22FF FFFF FF
16+
# 2. 570F 4381 0101 43FF FFFF FF
17+
# 3 . 570F 4381 0101 64FF FFFF FF
18+
19+
20+
class SwitchbotHumidifier(SwitchbotDevice):
21+
"""Representation of a Switchbot humidifier."""
22+
23+
async def update(self, interface: int | None = None) -> None:
24+
"""Update state of device."""
25+
await self.get_device_data(retry=self._retry_count, interface=interface)
26+
27+
async def turn_on(self) -> bool:
28+
"""Turn device on."""
29+
result = await self._send_command(HUMIDIFIER_ON_KEY)
30+
ret = self._check_command_result(result, 0, {0x01})
31+
self._override_adv_data = {"isOn": True}
32+
self._fire_callbacks()
33+
return ret
34+
35+
async def turn_off(self) -> bool:
36+
"""Turn device off."""
37+
result = await self._send_command(HUMIDIFIER_OFF_KEY)
38+
ret = self._check_command_result(result, 0, {0x01})
39+
self._override_adv_data = {"isOn": False}
40+
self._fire_callbacks()
41+
return ret
42+
43+
async def set_level(self, level: int) -> bool:
44+
"""Set level."""
45+
assert 1 <= level <= 100, "Level must be between 1 and 100"
46+
result = await self._send_command(
47+
f"{HUMIDIFIER_COMMAND}0101{level:02X}FFFFFFFF"
48+
)
49+
ret = self._check_command_result(result, 0, {0x01})
50+
self._override_adv_data = {"isOn": False, "level": level}
51+
self._fire_callbacks()
52+
return ret
53+
54+
def is_on(self) -> bool | None:
55+
"""Return switch state from cache."""
56+
return self._get_adv_value("isOn")

0 commit comments

Comments
 (0)