Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions switchbot/adv_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from .adv_parsers.bot import process_wohand
from .adv_parsers.bulb import process_color_bulb
from .adv_parsers.ceiling_light import process_woceiling
from .adv_parsers.climate_panel import process_climate_panel
from .adv_parsers.contact import process_wocontact
from .adv_parsers.curtain import process_wocurtain
from .adv_parsers.fan import process_fan
Expand Down Expand Up @@ -370,6 +371,12 @@ class SwitchbotSupportedType(TypedDict):
"func": process_vacuum,
"manufacturer_id": 2409,
},
b"\x00\x10\xf3\xd8": {
"modelName": SwitchbotModel.CLIMATE_PANEL,
"modelFriendlyName": "Climate Panel",
"func": process_climate_panel,
"manufacturer_id": 2409,
},
}

_SWITCHBOT_MODEL_TO_CHAR = {
Expand Down Expand Up @@ -452,12 +459,12 @@ def _parse_data(
if model_data.get("manufacturer_data_length") == len(_mfr_data):
_model = model_chr
break
if (
_service_data
and len(_service_data) > 5
and _service_data[-4:] in SUPPORTED_TYPES
):
_model = _service_data[-4:]

if _service_data and len(_service_data) > 5:
for s in (_service_data[-4:], _service_data[-5:-1]):
if s in SUPPORTED_TYPES:
_model = s
break

if not _model:
return None
Expand Down
46 changes: 46 additions & 0 deletions switchbot/adv_parsers/climate_panel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"""Advertisement data parser for climate panel devices."""

import logging

_LOGGER = logging.getLogger(__name__)


def process_climate_panel(
data: bytes | None, mfr_data: bytes | None
) -> dict[str, bool | int | str]:
"""Process Climate Panel data."""
if mfr_data is None:
return {}

seq_number = mfr_data[6]
isOn = bool(mfr_data[7] & 0x80)
battery = mfr_data[7] & 0x7F
humidity_alarm = (mfr_data[8] >> 6) & 0x03
temp_alarm = (mfr_data[8] >> 4) & 0x03

temp_decimal = mfr_data[8] & 0x0F
temp_sign = 1 if (mfr_data[9] & 0x80) else -1
temp_int = mfr_data[9] & 0x7F
temperature = temp_sign * (temp_int + temp_decimal / 10)

humidity = mfr_data[10] & 0x7F

pir_state = bool(mfr_data[15] & 0x80)
is_light = ((mfr_data[15] >> 2) & 0x03) == 0x10

result = {
"sequence_number": seq_number,
"isOn": isOn,
"battery": battery,
"temperature": temperature,
"humidity": humidity,
"temp_alarm": temp_alarm,
"humidity_alarm": humidity_alarm,
"motion_detected": pir_state,
"is_light": is_light,
}

_LOGGER.debug(
"Processed climate panel mfr data: %s, result: %s", mfr_data.hex(), result
)
return result
1 change: 1 addition & 0 deletions switchbot/const/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ class SwitchbotModel(StrEnum):
RGBICWW_STRIP_LIGHT = "RGBICWW Strip Light"
RGBICWW_FLOOR_LAMP = "RGBICWW Floor Lamp"
K11_VACUUM = "K11+ Vacuum"
CLIMATE_PANEL = "Climate Panel"


__all__ = [
Expand Down
44 changes: 44 additions & 0 deletions tests/test_adv_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -3430,6 +3430,24 @@ def test_humidifer_with_empty_data() -> None:
"K11+ Vacuum",
SwitchbotModel.K11_VACUUM,
),
AdvTestCase(
b"\xb0\xe9\xfe\x8e\x98Oi_\x06\x9a,\x00\x00\x00\x00\xe4\x00\x08\x04\x00\x01\x00\x00",
b"\x00 _\x00\x10\xf3\xd8@",
{
"battery": 95,
"humidity": 44,
"sequence_number": 105,
"humidity_alarm": 0,
"isOn": False,
"is_light": False,
"motion_detected": True,
"temp_alarm": 0,
"temperature": 26.6,
},
b"\x00\x10\xf3\xd8",
"Climate Panel",
SwitchbotModel.CLIMATE_PANEL,
),
],
)
def test_adv_active(test_case: AdvTestCase) -> None:
Expand Down Expand Up @@ -3644,6 +3662,24 @@ def test_adv_active(test_case: AdvTestCase) -> None:
"K11+ Vacuum",
SwitchbotModel.K11_VACUUM,
),
AdvTestCase(
b"\xb0\xe9\xfe\x8e\x98Oi_\x06\x9a,\x00\x00\x00\x00\xe4\x00\x08\x04\x00\x01\x00\x00",
None,
{
"battery": 95,
"humidity": 44,
"sequence_number": 105,
"humidity_alarm": 0,
"isOn": False,
"is_light": False,
"motion_detected": True,
"temp_alarm": 0,
"temperature": 26.6,
},
b"\x00\x10\xf3\xd8",
"Climate Panel",
SwitchbotModel.CLIMATE_PANEL,
),
],
)
def test_adv_passive(test_case: AdvTestCase) -> None:
Expand Down Expand Up @@ -3809,6 +3845,14 @@ def test_adv_passive(test_case: AdvTestCase) -> None:
"K11+ Vacuum",
SwitchbotModel.K11_VACUUM,
),
AdvTestCase(
None,
b"\x00 _\x00\x10\xf3\xd8@",
{},
b"\x00\x10\xf3\xd8",
"Climate Panel",
SwitchbotModel.CLIMATE_PANEL,
),
],
)
def test_adv_with_empty_data(test_case: AdvTestCase) -> None:
Expand Down