PySwitchbot 0.62.2__tar.gz → 0.63.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-0.62.2 → pyswitchbot-0.63.0}/PKG-INFO +1 -1
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/PySwitchbot.egg-info/PKG-INFO +1 -1
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/PySwitchbot.egg-info/SOURCES.txt +3 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/setup.py +1 -1
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/adv_parser.py +14 -1
- pyswitchbot-0.63.0/switchbot/adv_parsers/hub3.py +56 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/const/__init__.py +1 -0
- pyswitchbot-0.63.0/switchbot/const/hub3.py +18 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/tests/test_adv_parser.py +100 -0
- pyswitchbot-0.63.0/tests/test_hub3.py +13 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/LICENSE +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/MANIFEST.in +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/PySwitchbot.egg-info/dependency_links.txt +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/PySwitchbot.egg-info/requires.txt +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/PySwitchbot.egg-info/top_level.txt +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/README.md +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/pyproject.toml +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/setup.cfg +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/__init__.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/adv_parsers/__init__.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/adv_parsers/air_purifier.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/adv_parsers/blind_tilt.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/adv_parsers/bot.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/adv_parsers/bulb.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/adv_parsers/ceiling_light.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/adv_parsers/contact.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/adv_parsers/curtain.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/adv_parsers/fan.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/adv_parsers/hub2.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/adv_parsers/hubmini_matter.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/adv_parsers/humidifier.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/adv_parsers/keypad.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/adv_parsers/leak.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/adv_parsers/light_strip.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/adv_parsers/lock.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/adv_parsers/meter.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/adv_parsers/motion.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/adv_parsers/plug.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/adv_parsers/relay_switch.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/adv_parsers/remote.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/adv_parsers/roller_shade.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/adv_parsers/vacuum.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/api_config.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/const/air_purifier.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/const/evaporative_humidifier.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/const/fan.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/const/hub2.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/const/lock.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/devices/__init__.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/devices/air_purifier.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/devices/base_cover.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/devices/base_light.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/devices/blind_tilt.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/devices/bot.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/devices/bulb.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/devices/ceiling_light.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/devices/contact.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/devices/curtain.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/devices/device.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/devices/evaporative_humidifier.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/devices/fan.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/devices/humidifier.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/devices/keypad.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/devices/light_strip.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/devices/lock.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/devices/meter.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/devices/motion.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/devices/plug.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/devices/relay_switch.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/devices/roller_shade.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/devices/vacuum.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/discovery.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/enum.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/helpers.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/switchbot/models.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/tests/test_air_purifier.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/tests/test_base_cover.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/tests/test_blind_tilt.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/tests/test_curtain.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/tests/test_evaporative_humidifier.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/tests/test_fan.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/tests/test_hub2.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/tests/test_relay_switch.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/tests/test_roller_shade.py +0 -0
- {pyswitchbot-0.62.2 → pyswitchbot-0.63.0}/tests/test_vacuum.py +0 -0
|
@@ -25,6 +25,7 @@ switchbot/adv_parsers/contact.py
|
|
|
25
25
|
switchbot/adv_parsers/curtain.py
|
|
26
26
|
switchbot/adv_parsers/fan.py
|
|
27
27
|
switchbot/adv_parsers/hub2.py
|
|
28
|
+
switchbot/adv_parsers/hub3.py
|
|
28
29
|
switchbot/adv_parsers/hubmini_matter.py
|
|
29
30
|
switchbot/adv_parsers/humidifier.py
|
|
30
31
|
switchbot/adv_parsers/keypad.py
|
|
@@ -43,6 +44,7 @@ switchbot/const/air_purifier.py
|
|
|
43
44
|
switchbot/const/evaporative_humidifier.py
|
|
44
45
|
switchbot/const/fan.py
|
|
45
46
|
switchbot/const/hub2.py
|
|
47
|
+
switchbot/const/hub3.py
|
|
46
48
|
switchbot/const/lock.py
|
|
47
49
|
switchbot/devices/__init__.py
|
|
48
50
|
switchbot/devices/air_purifier.py
|
|
@@ -75,6 +77,7 @@ tests/test_curtain.py
|
|
|
75
77
|
tests/test_evaporative_humidifier.py
|
|
76
78
|
tests/test_fan.py
|
|
77
79
|
tests/test_hub2.py
|
|
80
|
+
tests/test_hub3.py
|
|
78
81
|
tests/test_relay_switch.py
|
|
79
82
|
tests/test_roller_shade.py
|
|
80
83
|
tests/test_vacuum.py
|
|
@@ -19,6 +19,7 @@ from .adv_parsers.contact import process_wocontact
|
|
|
19
19
|
from .adv_parsers.curtain import process_wocurtain
|
|
20
20
|
from .adv_parsers.fan import process_fan
|
|
21
21
|
from .adv_parsers.hub2 import process_wohub2
|
|
22
|
+
from .adv_parsers.hub3 import process_hub3
|
|
22
23
|
from .adv_parsers.hubmini_matter import process_hubmini_matter
|
|
23
24
|
from .adv_parsers.humidifier import process_evaporative_humidifier, process_wohumidifier
|
|
24
25
|
from .adv_parsers.keypad import process_wokeypad
|
|
@@ -57,7 +58,7 @@ class SwitchbotSupportedType(TypedDict):
|
|
|
57
58
|
manufacturer_data_length: int | None
|
|
58
59
|
|
|
59
60
|
|
|
60
|
-
SUPPORTED_TYPES: dict[str, SwitchbotSupportedType] = {
|
|
61
|
+
SUPPORTED_TYPES: dict[str | bytes, SwitchbotSupportedType] = {
|
|
61
62
|
"d": {
|
|
62
63
|
"modelName": SwitchbotModel.CONTACT_SENSOR,
|
|
63
64
|
"modelFriendlyName": "Contact Sensor",
|
|
@@ -293,6 +294,12 @@ SUPPORTED_TYPES: dict[str, SwitchbotSupportedType] = {
|
|
|
293
294
|
"func": process_air_purifier,
|
|
294
295
|
"manufacturer_id": 2409,
|
|
295
296
|
},
|
|
297
|
+
b"\x00\x10\xb9\x40": {
|
|
298
|
+
"modelName": SwitchbotModel.HUB3,
|
|
299
|
+
"modelFriendlyName": "Hub3",
|
|
300
|
+
"func": process_hub3,
|
|
301
|
+
"manufacturer_id": 2409,
|
|
302
|
+
},
|
|
296
303
|
}
|
|
297
304
|
|
|
298
305
|
_SWITCHBOT_MODEL_TO_CHAR = {
|
|
@@ -371,6 +378,12 @@ def _parse_data(
|
|
|
371
378
|
if model_data.get("manufacturer_data_length") == len(_mfr_data):
|
|
372
379
|
_model = model_chr
|
|
373
380
|
break
|
|
381
|
+
if (
|
|
382
|
+
_service_data
|
|
383
|
+
and len(_service_data) > 5
|
|
384
|
+
and _service_data[-4:] in SUPPORTED_TYPES
|
|
385
|
+
):
|
|
386
|
+
_model = _service_data[-4:]
|
|
374
387
|
|
|
375
388
|
if not _model:
|
|
376
389
|
return None
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""Air Purifier adv parser."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from ..const.hub3 import LIGHT_INTENSITY_MAP
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def process_hub3(data: bytes | None, mfr_data: bytes | None) -> dict[str, Any]:
|
|
11
|
+
"""Process hub3 sensor manufacturer data."""
|
|
12
|
+
if mfr_data is None:
|
|
13
|
+
return {}
|
|
14
|
+
device_data = mfr_data[6:]
|
|
15
|
+
|
|
16
|
+
seq_num = device_data[0]
|
|
17
|
+
network_state = (device_data[6] & 0b11000000) >> 6
|
|
18
|
+
sensor_inserted = not bool(device_data[6] & 0b00100000)
|
|
19
|
+
light_level = device_data[6] & 0b00001111
|
|
20
|
+
illuminance = calculate_light_intensity(light_level)
|
|
21
|
+
temperature_alarm = bool(device_data[7] & 0b11000000)
|
|
22
|
+
humidity_alarm = bool(device_data[7] & 0b00110000)
|
|
23
|
+
|
|
24
|
+
temp_data = device_data[7:10]
|
|
25
|
+
_temp_sign = 1 if temp_data[1] & 0b10000000 else -1
|
|
26
|
+
_temp_c = _temp_sign * (
|
|
27
|
+
(temp_data[1] & 0b01111111) + ((temp_data[0] & 0b00001111) / 10)
|
|
28
|
+
)
|
|
29
|
+
_temp_f = round(((_temp_c * 9 / 5) + 32), 1)
|
|
30
|
+
humidity = temp_data[2] & 0b01111111
|
|
31
|
+
motion_detected = bool(device_data[10] & 0b10000000)
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
"sequence_number": seq_num,
|
|
35
|
+
"network_state": network_state,
|
|
36
|
+
"sensor_inserted": sensor_inserted,
|
|
37
|
+
"lightLevel": light_level,
|
|
38
|
+
"illuminance": illuminance,
|
|
39
|
+
"temperature_alarm": temperature_alarm,
|
|
40
|
+
"humidity_alarm": humidity_alarm,
|
|
41
|
+
"temp": {"c": _temp_c, "f": _temp_f},
|
|
42
|
+
"temperature": _temp_c,
|
|
43
|
+
"humidity": humidity,
|
|
44
|
+
"motion_detected": motion_detected,
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def calculate_light_intensity(light_level: int) -> int:
|
|
49
|
+
"""
|
|
50
|
+
Convert Hub 3 light level (1-10) to actual light intensity value
|
|
51
|
+
Args:
|
|
52
|
+
light_level: Integer from 1-10
|
|
53
|
+
Returns:
|
|
54
|
+
Corresponding light intensity value or 0 if invalid input
|
|
55
|
+
"""
|
|
56
|
+
return LIGHT_INTENSITY_MAP.get(max(0, min(light_level, 10)), 0)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Mapping of light levels to lux measurement values for SwitchBot Hub 3.
|
|
3
|
+
|
|
4
|
+
Source: After-sales consultation, line chart data provided by switchbot developers
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
LIGHT_INTENSITY_MAP = {
|
|
8
|
+
1: 0,
|
|
9
|
+
2: 50,
|
|
10
|
+
3: 90,
|
|
11
|
+
4: 205,
|
|
12
|
+
5: 317,
|
|
13
|
+
6: 510,
|
|
14
|
+
7: 610,
|
|
15
|
+
8: 707,
|
|
16
|
+
9: 801,
|
|
17
|
+
10: 1023,
|
|
18
|
+
}
|
|
@@ -2842,3 +2842,103 @@ def test_air_purifier_with_empty_data() -> None:
|
|
|
2842
2842
|
rssi=-97,
|
|
2843
2843
|
active=True,
|
|
2844
2844
|
)
|
|
2845
|
+
|
|
2846
|
+
|
|
2847
|
+
def test_hub3_active() -> None:
|
|
2848
|
+
"""Test parsing hub3 with active data."""
|
|
2849
|
+
ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
2850
|
+
adv_data = generate_advertisement_data(
|
|
2851
|
+
manufacturer_data={2409: b"\xb0\xe9\xfen^)\x00\xffh&\xd6d\x83\x03\x994\x80"},
|
|
2852
|
+
service_data={
|
|
2853
|
+
"0000fd3d-0000-1000-8000-00805f9b34fb": b"\x00\x00d\x00\x10\xb9@"
|
|
2854
|
+
},
|
|
2855
|
+
rssi=-97,
|
|
2856
|
+
)
|
|
2857
|
+
result = parse_advertisement_data(ble_device, adv_data)
|
|
2858
|
+
assert result == SwitchBotAdvertisement(
|
|
2859
|
+
address="aa:bb:cc:dd:ee:ff",
|
|
2860
|
+
data={
|
|
2861
|
+
"rawAdvData": b"\x00\x00d\x00\x10\xb9@",
|
|
2862
|
+
"data": {
|
|
2863
|
+
"sequence_number": 0,
|
|
2864
|
+
"network_state": 2,
|
|
2865
|
+
"sensor_inserted": True,
|
|
2866
|
+
"lightLevel": 3,
|
|
2867
|
+
"illuminance": 90,
|
|
2868
|
+
"temperature_alarm": False,
|
|
2869
|
+
"humidity_alarm": False,
|
|
2870
|
+
"temp": {"c": 25.3, "f": 77.5},
|
|
2871
|
+
"temperature": 25.3,
|
|
2872
|
+
"humidity": 52,
|
|
2873
|
+
"motion_detected": True,
|
|
2874
|
+
},
|
|
2875
|
+
"isEncrypted": False,
|
|
2876
|
+
"model": b"\x00\x10\xb9@",
|
|
2877
|
+
"modelFriendlyName": "Hub3",
|
|
2878
|
+
"modelName": SwitchbotModel.HUB3,
|
|
2879
|
+
},
|
|
2880
|
+
device=ble_device,
|
|
2881
|
+
rssi=-97,
|
|
2882
|
+
active=True,
|
|
2883
|
+
)
|
|
2884
|
+
|
|
2885
|
+
|
|
2886
|
+
def test_hub3_passive() -> None:
|
|
2887
|
+
"""Test parsing hub3 with passive data."""
|
|
2888
|
+
ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
2889
|
+
adv_data = generate_advertisement_data(
|
|
2890
|
+
manufacturer_data={2409: b"\xb0\xe9\xfen^)\x00\xffh&\xd6d\x83\x03\x994\x80"},
|
|
2891
|
+
rssi=-97,
|
|
2892
|
+
)
|
|
2893
|
+
result = parse_advertisement_data(ble_device, adv_data, SwitchbotModel.HUB3)
|
|
2894
|
+
assert result == SwitchBotAdvertisement(
|
|
2895
|
+
address="aa:bb:cc:dd:ee:ff",
|
|
2896
|
+
data={
|
|
2897
|
+
"rawAdvData": None,
|
|
2898
|
+
"data": {
|
|
2899
|
+
"sequence_number": 0,
|
|
2900
|
+
"network_state": 2,
|
|
2901
|
+
"sensor_inserted": True,
|
|
2902
|
+
"lightLevel": 3,
|
|
2903
|
+
"illuminance": 90,
|
|
2904
|
+
"temperature_alarm": False,
|
|
2905
|
+
"humidity_alarm": False,
|
|
2906
|
+
"temp": {"c": 25.3, "f": 77.5},
|
|
2907
|
+
"temperature": 25.3,
|
|
2908
|
+
"humidity": 52,
|
|
2909
|
+
"motion_detected": True,
|
|
2910
|
+
},
|
|
2911
|
+
"isEncrypted": False,
|
|
2912
|
+
"model": b"\x00\x10\xb9@",
|
|
2913
|
+
"modelFriendlyName": "Hub3",
|
|
2914
|
+
"modelName": SwitchbotModel.HUB3,
|
|
2915
|
+
},
|
|
2916
|
+
device=ble_device,
|
|
2917
|
+
rssi=-97,
|
|
2918
|
+
active=False,
|
|
2919
|
+
)
|
|
2920
|
+
|
|
2921
|
+
|
|
2922
|
+
def test_hub3_with_empty_data() -> None:
|
|
2923
|
+
"""Test parsing hub3 with empty data."""
|
|
2924
|
+
ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
2925
|
+
adv_data = generate_advertisement_data(
|
|
2926
|
+
manufacturer_data={2409: None},
|
|
2927
|
+
service_data={
|
|
2928
|
+
"0000fd3d-0000-1000-8000-00805f9b34fb": b"\x00\x00d\x00\x10\xb9@"
|
|
2929
|
+
},
|
|
2930
|
+
rssi=-97,
|
|
2931
|
+
)
|
|
2932
|
+
result = parse_advertisement_data(ble_device, adv_data)
|
|
2933
|
+
assert result == SwitchBotAdvertisement(
|
|
2934
|
+
address="aa:bb:cc:dd:ee:ff",
|
|
2935
|
+
data={
|
|
2936
|
+
"rawAdvData": b"\x00\x00d\x00\x10\xb9@",
|
|
2937
|
+
"data": {},
|
|
2938
|
+
"isEncrypted": False,
|
|
2939
|
+
"model": b"\x00\x10\xb9@",
|
|
2940
|
+
},
|
|
2941
|
+
device=ble_device,
|
|
2942
|
+
rssi=-97,
|
|
2943
|
+
active=True,
|
|
2944
|
+
)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from switchbot.adv_parsers.hub3 import calculate_light_intensity
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def test_calculate_light_intensity():
|
|
5
|
+
"""Test calculating light intensity from Hub 3 light level."""
|
|
6
|
+
# Test valid inputs
|
|
7
|
+
assert calculate_light_intensity(1) == 0
|
|
8
|
+
assert calculate_light_intensity(2) == 50
|
|
9
|
+
assert calculate_light_intensity(5) == 317
|
|
10
|
+
assert calculate_light_intensity(10) == 1023
|
|
11
|
+
|
|
12
|
+
# Test invalid inputs
|
|
13
|
+
assert calculate_light_intensity(0) == 0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|