PySwitchbot 0.48.2__tar.gz → 0.50.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.48.2 → pyswitchbot-0.50.0}/PKG-INFO +1 -1
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/PySwitchbot.egg-info/PKG-INFO +1 -1
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/setup.py +1 -1
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/adv_parser.py +13 -1
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/adv_parsers/meter.py +39 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/const.py +2 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/tests/test_adv_parser.py +125 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/LICENSE +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/MANIFEST.in +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/PySwitchbot.egg-info/SOURCES.txt +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/PySwitchbot.egg-info/dependency_links.txt +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/PySwitchbot.egg-info/requires.txt +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/PySwitchbot.egg-info/top_level.txt +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/README.md +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/setup.cfg +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/__init__.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/adv_parsers/__init__.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/adv_parsers/blind_tilt.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/adv_parsers/bot.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/adv_parsers/bulb.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/adv_parsers/ceiling_light.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/adv_parsers/contact.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/adv_parsers/curtain.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/adv_parsers/hub2.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/adv_parsers/humidifier.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/adv_parsers/light_strip.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/adv_parsers/lock.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/adv_parsers/motion.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/adv_parsers/plug.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/api_config.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/devices/__init__.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/devices/base_cover.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/devices/base_light.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/devices/blind_tilt.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/devices/bot.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/devices/bulb.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/devices/ceiling_light.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/devices/contact.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/devices/curtain.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/devices/device.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/devices/humidifier.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/devices/light_strip.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/devices/lock.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/devices/meter.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/devices/motion.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/devices/plug.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/discovery.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/enum.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/switchbot/models.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/tests/test_base_cover.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/tests/test_blind_tilt.py +0 -0
- {pyswitchbot-0.48.2 → pyswitchbot-0.50.0}/tests/test_curtain.py +0 -0
|
@@ -20,7 +20,7 @@ from .adv_parsers.hub2 import process_wohub2
|
|
|
20
20
|
from .adv_parsers.humidifier import process_wohumidifier
|
|
21
21
|
from .adv_parsers.light_strip import process_wostrip
|
|
22
22
|
from .adv_parsers.lock import process_wolock, process_wolock_pro
|
|
23
|
-
from .adv_parsers.meter import process_wosensorth
|
|
23
|
+
from .adv_parsers.meter import process_wosensorth, process_wosensorth_c
|
|
24
24
|
from .adv_parsers.motion import process_wopresence
|
|
25
25
|
from .adv_parsers.plug import process_woplugmini
|
|
26
26
|
from .const import SwitchbotModel
|
|
@@ -101,6 +101,18 @@ SUPPORTED_TYPES: dict[str, SwitchbotSupportedType] = {
|
|
|
101
101
|
"func": process_wosensorth,
|
|
102
102
|
"manufacturer_id": 2409,
|
|
103
103
|
},
|
|
104
|
+
"4": {
|
|
105
|
+
"modelName": SwitchbotModel.METER_PRO,
|
|
106
|
+
"modelFriendlyName": "Meter",
|
|
107
|
+
"func": process_wosensorth,
|
|
108
|
+
"manufacturer_id": 2409,
|
|
109
|
+
},
|
|
110
|
+
"5": {
|
|
111
|
+
"modelName": SwitchbotModel.METER_PRO_C,
|
|
112
|
+
"modelFriendlyName": "Meter",
|
|
113
|
+
"func": process_wosensorth_c,
|
|
114
|
+
"manufacturer_id": 2409,
|
|
115
|
+
},
|
|
104
116
|
"v": {
|
|
105
117
|
"modelName": SwitchbotModel.HUB2,
|
|
106
118
|
"modelFriendlyName": "Hub 2",
|
|
@@ -41,3 +41,42 @@ def process_wosensorth(data: bytes | None, mfr_data: bytes | None) -> dict[str,
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
return _wosensorth_data
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def process_wosensorth_c(data: bytes | None, mfr_data: bytes | None) -> dict[str, Any]:
|
|
47
|
+
"""Process woSensorTH/Temp sensor services data with CO2."""
|
|
48
|
+
temp_data = None
|
|
49
|
+
battery = None
|
|
50
|
+
|
|
51
|
+
if mfr_data:
|
|
52
|
+
temp_data = mfr_data[8:11]
|
|
53
|
+
|
|
54
|
+
if data:
|
|
55
|
+
if not temp_data:
|
|
56
|
+
temp_data = data[3:6]
|
|
57
|
+
battery = data[2] & 0b01111111
|
|
58
|
+
|
|
59
|
+
if not temp_data:
|
|
60
|
+
return {}
|
|
61
|
+
|
|
62
|
+
_temp_sign = 1 if temp_data[1] & 0b10000000 else -1
|
|
63
|
+
_temp_c = _temp_sign * (
|
|
64
|
+
(temp_data[1] & 0b01111111) + ((temp_data[0] & 0b00001111) / 10)
|
|
65
|
+
)
|
|
66
|
+
_temp_f = (_temp_c * 9 / 5) + 32
|
|
67
|
+
_temp_f = (_temp_f * 10) / 10
|
|
68
|
+
humidity = temp_data[2] & 0b01111111
|
|
69
|
+
|
|
70
|
+
if _temp_c == 0 and humidity == 0 and battery == 0:
|
|
71
|
+
return {}
|
|
72
|
+
|
|
73
|
+
_wosensorth_data = {
|
|
74
|
+
# Data should be flat, but we keep the original structure for now
|
|
75
|
+
"temp": {"c": _temp_c, "f": _temp_f},
|
|
76
|
+
"temperature": _temp_c,
|
|
77
|
+
"fahrenheit": bool(temp_data[2] & 0b10000000),
|
|
78
|
+
"humidity": humidity,
|
|
79
|
+
"battery": battery,
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return _wosensorth_data
|
|
@@ -1560,3 +1560,128 @@ def test_parsing_lock_passive_old_firmware():
|
|
|
1560
1560
|
rssi=-67,
|
|
1561
1561
|
active=False,
|
|
1562
1562
|
)
|
|
1563
|
+
|
|
1564
|
+
|
|
1565
|
+
def test_meter_pro_active() -> None:
|
|
1566
|
+
ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
1567
|
+
adv_data = generate_advertisement_data(
|
|
1568
|
+
manufacturer_data={2409: b"\xb0\xe9\xfeR\xdd\x84\x06d\x08\x97,\x00\x05"},
|
|
1569
|
+
service_data={"0000fd3d-0000-1000-8000-00805f9b34fb": b"4\x00d"},
|
|
1570
|
+
rssi=-67,
|
|
1571
|
+
)
|
|
1572
|
+
result = parse_advertisement_data(ble_device, adv_data)
|
|
1573
|
+
assert result == SwitchBotAdvertisement(
|
|
1574
|
+
address="aa:bb:cc:dd:ee:ff",
|
|
1575
|
+
data={
|
|
1576
|
+
"data": {
|
|
1577
|
+
"battery": 100,
|
|
1578
|
+
"fahrenheit": False,
|
|
1579
|
+
"humidity": 44,
|
|
1580
|
+
"temp": {"c": 23.8, "f": 74.84},
|
|
1581
|
+
"temperature": 23.8,
|
|
1582
|
+
},
|
|
1583
|
+
"isEncrypted": False,
|
|
1584
|
+
"model": "4",
|
|
1585
|
+
"modelFriendlyName": "Meter",
|
|
1586
|
+
"modelName": SwitchbotModel.METER_PRO,
|
|
1587
|
+
"rawAdvData": b"4\x00d",
|
|
1588
|
+
},
|
|
1589
|
+
device=ble_device,
|
|
1590
|
+
rssi=-67,
|
|
1591
|
+
active=True,
|
|
1592
|
+
)
|
|
1593
|
+
|
|
1594
|
+
|
|
1595
|
+
def test_meter_pro_passive() -> None:
|
|
1596
|
+
ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
1597
|
+
adv_data = generate_advertisement_data(
|
|
1598
|
+
manufacturer_data={2409: b"\xb0\xe9\xfeR\xdd\x84\x06d\x08\x97,\x00\x05"},
|
|
1599
|
+
rssi=-67,
|
|
1600
|
+
)
|
|
1601
|
+
result = parse_advertisement_data(ble_device, adv_data, SwitchbotModel.METER_PRO)
|
|
1602
|
+
import pprint
|
|
1603
|
+
|
|
1604
|
+
pprint.pprint(result)
|
|
1605
|
+
assert result == SwitchBotAdvertisement(
|
|
1606
|
+
address="aa:bb:cc:dd:ee:ff",
|
|
1607
|
+
data={
|
|
1608
|
+
"data": {
|
|
1609
|
+
"battery": None,
|
|
1610
|
+
"fahrenheit": False,
|
|
1611
|
+
"humidity": 44,
|
|
1612
|
+
"temp": {"c": 23.8, "f": 74.84},
|
|
1613
|
+
"temperature": 23.8,
|
|
1614
|
+
},
|
|
1615
|
+
"isEncrypted": False,
|
|
1616
|
+
"model": "4",
|
|
1617
|
+
"modelFriendlyName": "Meter",
|
|
1618
|
+
"modelName": SwitchbotModel.METER_PRO,
|
|
1619
|
+
"rawAdvData": None,
|
|
1620
|
+
},
|
|
1621
|
+
device=ble_device,
|
|
1622
|
+
rssi=-67,
|
|
1623
|
+
active=False,
|
|
1624
|
+
)
|
|
1625
|
+
|
|
1626
|
+
|
|
1627
|
+
def test_meter_pro_c_active() -> None:
|
|
1628
|
+
ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
1629
|
+
adv_data = generate_advertisement_data(
|
|
1630
|
+
manufacturer_data={
|
|
1631
|
+
2409: b"\xb0\xe9\xfeT2\x15\xb7\xe4\x07\x9b\xa4\x007\x02\xd5\x00"
|
|
1632
|
+
},
|
|
1633
|
+
service_data={"0000fd3d-0000-1000-8000-00805f9b34fb": b"5\x00d"},
|
|
1634
|
+
rssi=-67,
|
|
1635
|
+
)
|
|
1636
|
+
result = parse_advertisement_data(ble_device, adv_data)
|
|
1637
|
+
assert result == SwitchBotAdvertisement(
|
|
1638
|
+
address="aa:bb:cc:dd:ee:ff",
|
|
1639
|
+
data={
|
|
1640
|
+
"data": {
|
|
1641
|
+
"battery": 100,
|
|
1642
|
+
"fahrenheit": True,
|
|
1643
|
+
"humidity": 36,
|
|
1644
|
+
"temp": {"c": 27.7, "f": 81.86},
|
|
1645
|
+
"temperature": 27.7,
|
|
1646
|
+
},
|
|
1647
|
+
"isEncrypted": False,
|
|
1648
|
+
"model": "5",
|
|
1649
|
+
"modelFriendlyName": "Meter",
|
|
1650
|
+
"modelName": SwitchbotModel.METER_PRO_C,
|
|
1651
|
+
"rawAdvData": b"5\x00d",
|
|
1652
|
+
},
|
|
1653
|
+
device=ble_device,
|
|
1654
|
+
rssi=-67,
|
|
1655
|
+
active=True,
|
|
1656
|
+
)
|
|
1657
|
+
|
|
1658
|
+
|
|
1659
|
+
def test_meter_pro_c_passive() -> None:
|
|
1660
|
+
ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
1661
|
+
adv_data = generate_advertisement_data(
|
|
1662
|
+
manufacturer_data={
|
|
1663
|
+
2409: b"\xb0\xe9\xfeT2\x15\xb7\xe4\x07\x9b\xa4\x007\x02\xd5\x00"
|
|
1664
|
+
},
|
|
1665
|
+
rssi=-67,
|
|
1666
|
+
)
|
|
1667
|
+
result = parse_advertisement_data(ble_device, adv_data, SwitchbotModel.METER_PRO_C)
|
|
1668
|
+
assert result == SwitchBotAdvertisement(
|
|
1669
|
+
address="aa:bb:cc:dd:ee:ff",
|
|
1670
|
+
data={
|
|
1671
|
+
"data": {
|
|
1672
|
+
"battery": None,
|
|
1673
|
+
"fahrenheit": True,
|
|
1674
|
+
"humidity": 36,
|
|
1675
|
+
"temp": {"c": 27.7, "f": 81.86},
|
|
1676
|
+
"temperature": 27.7,
|
|
1677
|
+
},
|
|
1678
|
+
"isEncrypted": False,
|
|
1679
|
+
"model": "5",
|
|
1680
|
+
"modelFriendlyName": "Meter",
|
|
1681
|
+
"modelName": SwitchbotModel.METER_PRO_C,
|
|
1682
|
+
"rawAdvData": None,
|
|
1683
|
+
},
|
|
1684
|
+
device=ble_device,
|
|
1685
|
+
rssi=-67,
|
|
1686
|
+
active=False,
|
|
1687
|
+
)
|
|
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
|