PySwitchbot 0.55.3__tar.gz → 0.56.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.55.3 → pyswitchbot-0.56.0}/PKG-INFO +11 -2
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/PySwitchbot.egg-info/PKG-INFO +11 -2
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/PySwitchbot.egg-info/SOURCES.txt +1 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/setup.py +1 -1
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parser.py +7 -0
- pyswitchbot-0.56.0/switchbot/adv_parsers/remote.py +24 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/const.py +1 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/relay_switch.py +10 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/tests/test_adv_parser.py +52 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/tests/test_relay_switch.py +15 -1
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/LICENSE +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/MANIFEST.in +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/PySwitchbot.egg-info/dependency_links.txt +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/PySwitchbot.egg-info/requires.txt +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/PySwitchbot.egg-info/top_level.txt +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/README.md +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/setup.cfg +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/__init__.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/__init__.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/blind_tilt.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/bot.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/bulb.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/ceiling_light.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/contact.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/curtain.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/hub2.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/humidifier.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/keypad.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/leak.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/light_strip.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/lock.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/meter.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/motion.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/plug.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/relay_switch.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/api_config.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/__init__.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/base_cover.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/base_light.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/blind_tilt.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/bot.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/bulb.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/ceiling_light.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/contact.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/curtain.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/device.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/humidifier.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/keypad.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/light_strip.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/lock.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/meter.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/motion.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/plug.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/discovery.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/enum.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/models.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/tests/test_base_cover.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/tests/test_blind_tilt.py +0 -0
- {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/tests/test_curtain.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: PySwitchbot
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.56.0
|
|
4
4
|
Summary: A library to communicate with Switchbot
|
|
5
5
|
Home-page: https://github.com/sblibs/pySwitchbot/
|
|
6
6
|
Author: Daniel Hjelseth Hoyer
|
|
@@ -20,6 +20,15 @@ Requires-Dist: bleak>=0.19.0
|
|
|
20
20
|
Requires-Dist: bleak-retry-connector>=3.4.0
|
|
21
21
|
Requires-Dist: cryptography>=39.0.0
|
|
22
22
|
Requires-Dist: pyOpenSSL>=23.0.0
|
|
23
|
+
Dynamic: author
|
|
24
|
+
Dynamic: classifier
|
|
25
|
+
Dynamic: description
|
|
26
|
+
Dynamic: description-content-type
|
|
27
|
+
Dynamic: home-page
|
|
28
|
+
Dynamic: license
|
|
29
|
+
Dynamic: requires-dist
|
|
30
|
+
Dynamic: requires-python
|
|
31
|
+
Dynamic: summary
|
|
23
32
|
|
|
24
33
|
# pySwitchbot [](https://travis-ci.org/sblibs/pySwitchbot)
|
|
25
34
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: PySwitchbot
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.56.0
|
|
4
4
|
Summary: A library to communicate with Switchbot
|
|
5
5
|
Home-page: https://github.com/sblibs/pySwitchbot/
|
|
6
6
|
Author: Daniel Hjelseth Hoyer
|
|
@@ -20,6 +20,15 @@ Requires-Dist: bleak>=0.19.0
|
|
|
20
20
|
Requires-Dist: bleak-retry-connector>=3.4.0
|
|
21
21
|
Requires-Dist: cryptography>=39.0.0
|
|
22
22
|
Requires-Dist: pyOpenSSL>=23.0.0
|
|
23
|
+
Dynamic: author
|
|
24
|
+
Dynamic: classifier
|
|
25
|
+
Dynamic: description
|
|
26
|
+
Dynamic: description-content-type
|
|
27
|
+
Dynamic: home-page
|
|
28
|
+
Dynamic: license
|
|
29
|
+
Dynamic: requires-dist
|
|
30
|
+
Dynamic: requires-python
|
|
31
|
+
Dynamic: summary
|
|
23
32
|
|
|
24
33
|
# pySwitchbot [](https://travis-ci.org/sblibs/pySwitchbot)
|
|
25
34
|
|
|
@@ -31,6 +31,7 @@ switchbot/adv_parsers/meter.py
|
|
|
31
31
|
switchbot/adv_parsers/motion.py
|
|
32
32
|
switchbot/adv_parsers/plug.py
|
|
33
33
|
switchbot/adv_parsers/relay_switch.py
|
|
34
|
+
switchbot/adv_parsers/remote.py
|
|
34
35
|
switchbot/devices/__init__.py
|
|
35
36
|
switchbot/devices/base_cover.py
|
|
36
37
|
switchbot/devices/base_light.py
|
|
@@ -29,6 +29,7 @@ from .adv_parsers.relay_switch import (
|
|
|
29
29
|
process_worelay_switch_1,
|
|
30
30
|
process_worelay_switch_1pm,
|
|
31
31
|
)
|
|
32
|
+
from .adv_parsers.remote import process_woremote
|
|
32
33
|
from .const import SwitchbotModel
|
|
33
34
|
from .models import SwitchBotAdvertisement
|
|
34
35
|
|
|
@@ -203,6 +204,12 @@ SUPPORTED_TYPES: dict[str, SwitchbotSupportedType] = {
|
|
|
203
204
|
"func": process_worelay_switch_1,
|
|
204
205
|
"manufacturer_id": 2409,
|
|
205
206
|
},
|
|
207
|
+
"b": {
|
|
208
|
+
"modelName": SwitchbotModel.REMOTE,
|
|
209
|
+
"modelFriendlyName": "Remote",
|
|
210
|
+
"func": process_woremote,
|
|
211
|
+
"manufacturer_id": 89,
|
|
212
|
+
},
|
|
206
213
|
}
|
|
207
214
|
|
|
208
215
|
_SWITCHBOT_MODEL_TO_CHAR = {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Remote adv parser."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
|
|
7
|
+
_LOGGER = logging.getLogger(__name__)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def process_woremote(
|
|
11
|
+
data: bytes | None, mfr_data: bytes | None
|
|
12
|
+
) -> dict[str, int | None]:
|
|
13
|
+
"""Process WoRemote adv data."""
|
|
14
|
+
|
|
15
|
+
if data is None:
|
|
16
|
+
return {
|
|
17
|
+
"battery": None,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
_LOGGER.debug("data: %s", data.hex())
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
"battery": data[2] & 0b01111111,
|
|
24
|
+
}
|
|
@@ -17,6 +17,7 @@ COMMAND_TURN_OFF = f"{COMMAND_HEADER}0f70010000"
|
|
|
17
17
|
COMMAND_TURN_ON = f"{COMMAND_HEADER}0f70010100"
|
|
18
18
|
COMMAND_TOGGLE = f"{COMMAND_HEADER}0f70010200"
|
|
19
19
|
COMMAND_GET_VOLTAGE_AND_CURRENT = f"{COMMAND_HEADER}0f7106000000"
|
|
20
|
+
COMMAND_GET_SWITCH_STATE = f"{COMMAND_HEADER}0f7101000000"
|
|
20
21
|
PASSIVE_POLL_INTERVAL = 10 * 60
|
|
21
22
|
|
|
22
23
|
|
|
@@ -87,6 +88,15 @@ class SwitchbotRelaySwitch(SwitchbotEncryptedDevice):
|
|
|
87
88
|
}
|
|
88
89
|
return None
|
|
89
90
|
|
|
91
|
+
async def get_basic_info(self) -> dict[str, Any] | None:
|
|
92
|
+
"""Get the current state of the switch."""
|
|
93
|
+
result = await self._send_command(COMMAND_GET_SWITCH_STATE)
|
|
94
|
+
if self._check_command_result(result, 0, {1}):
|
|
95
|
+
return {
|
|
96
|
+
"is_on": result[1] & 0x01 != 0,
|
|
97
|
+
}
|
|
98
|
+
return None
|
|
99
|
+
|
|
90
100
|
def poll_needed(self, seconds_since_last_poll: float | None) -> bool:
|
|
91
101
|
"""Return if device needs polling."""
|
|
92
102
|
if self._force_next_update:
|
|
@@ -1917,3 +1917,55 @@ def test_leak_real_data_from_ha():
|
|
|
1917
1917
|
rssi=-73,
|
|
1918
1918
|
active=True,
|
|
1919
1919
|
)
|
|
1920
|
+
|
|
1921
|
+
|
|
1922
|
+
def test_remote_active() -> None:
|
|
1923
|
+
ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
1924
|
+
adv_data = generate_advertisement_data(
|
|
1925
|
+
manufacturer_data={89: b"\xaa\xbb\xcc\xdd\xee\xff"},
|
|
1926
|
+
service_data={"00000d00-0000-1000-8000-00805f9b34fb": b"b V\x00"},
|
|
1927
|
+
service_uuids=["cba20d00-224d-11e6-9fb8-0002a5d5c51b"],
|
|
1928
|
+
rssi=-95,
|
|
1929
|
+
)
|
|
1930
|
+
result = parse_advertisement_data(ble_device, adv_data)
|
|
1931
|
+
assert result == SwitchBotAdvertisement(
|
|
1932
|
+
address="aa:bb:cc:dd:ee:ff",
|
|
1933
|
+
data={
|
|
1934
|
+
"data": {
|
|
1935
|
+
"battery": 86,
|
|
1936
|
+
},
|
|
1937
|
+
"isEncrypted": False,
|
|
1938
|
+
"model": "b",
|
|
1939
|
+
"modelFriendlyName": "Remote",
|
|
1940
|
+
"modelName": SwitchbotModel.REMOTE,
|
|
1941
|
+
"rawAdvData": b"b V\x00",
|
|
1942
|
+
},
|
|
1943
|
+
device=ble_device,
|
|
1944
|
+
rssi=-95,
|
|
1945
|
+
active=True,
|
|
1946
|
+
)
|
|
1947
|
+
|
|
1948
|
+
|
|
1949
|
+
def test_remote_passive() -> None:
|
|
1950
|
+
ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
|
|
1951
|
+
adv_data = generate_advertisement_data(
|
|
1952
|
+
manufacturer_data={89: b"\xaa\xbb\xcc\xdd\xee\xff"},
|
|
1953
|
+
rssi=-97,
|
|
1954
|
+
)
|
|
1955
|
+
result = parse_advertisement_data(ble_device, adv_data, SwitchbotModel.REMOTE)
|
|
1956
|
+
assert result == SwitchBotAdvertisement(
|
|
1957
|
+
address="aa:bb:cc:dd:ee:ff",
|
|
1958
|
+
data={
|
|
1959
|
+
"data": {
|
|
1960
|
+
"battery": None,
|
|
1961
|
+
},
|
|
1962
|
+
"isEncrypted": False,
|
|
1963
|
+
"model": "b",
|
|
1964
|
+
"modelFriendlyName": "Remote",
|
|
1965
|
+
"modelName": SwitchbotModel.REMOTE,
|
|
1966
|
+
"rawAdvData": None,
|
|
1967
|
+
},
|
|
1968
|
+
device=ble_device,
|
|
1969
|
+
rssi=-97,
|
|
1970
|
+
active=False,
|
|
1971
|
+
)
|
|
@@ -53,8 +53,22 @@ async def test_turn_on():
|
|
|
53
53
|
|
|
54
54
|
|
|
55
55
|
@pytest.mark.asyncio
|
|
56
|
-
async def
|
|
56
|
+
async def test_turn_off():
|
|
57
57
|
relay_switch_device = create_device_for_command_testing()
|
|
58
58
|
relay_switch_device._send_command = AsyncMock(return_value=b"\x01")
|
|
59
59
|
await relay_switch_device.turn_off()
|
|
60
60
|
assert relay_switch_device.is_on() is False
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@pytest.mark.asyncio
|
|
64
|
+
async def test_get_basic_info():
|
|
65
|
+
relay_switch_device = create_device_for_command_testing()
|
|
66
|
+
relay_switch_device._send_command = AsyncMock(return_value=b"\x01\x01")
|
|
67
|
+
info = await relay_switch_device.get_basic_info()
|
|
68
|
+
assert info["is_on"] is True
|
|
69
|
+
relay_switch_device._send_command = AsyncMock(return_value=b"\x01\x00")
|
|
70
|
+
info = await relay_switch_device.get_basic_info()
|
|
71
|
+
assert info["is_on"] is False
|
|
72
|
+
relay_switch_device._send_command = AsyncMock(return_value=b"\x00\x00")
|
|
73
|
+
info = await relay_switch_device.get_basic_info()
|
|
74
|
+
assert info is None
|
|
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
|