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.
Files changed (59) hide show
  1. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/PKG-INFO +11 -2
  2. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/PySwitchbot.egg-info/PKG-INFO +11 -2
  3. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/PySwitchbot.egg-info/SOURCES.txt +1 -0
  4. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/setup.py +1 -1
  5. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parser.py +7 -0
  6. pyswitchbot-0.56.0/switchbot/adv_parsers/remote.py +24 -0
  7. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/const.py +1 -0
  8. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/relay_switch.py +10 -0
  9. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/tests/test_adv_parser.py +52 -0
  10. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/tests/test_relay_switch.py +15 -1
  11. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/LICENSE +0 -0
  12. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/MANIFEST.in +0 -0
  13. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/PySwitchbot.egg-info/dependency_links.txt +0 -0
  14. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/PySwitchbot.egg-info/requires.txt +0 -0
  15. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/PySwitchbot.egg-info/top_level.txt +0 -0
  16. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/README.md +0 -0
  17. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/setup.cfg +0 -0
  18. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/__init__.py +0 -0
  19. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/__init__.py +0 -0
  20. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/blind_tilt.py +0 -0
  21. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/bot.py +0 -0
  22. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/bulb.py +0 -0
  23. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/ceiling_light.py +0 -0
  24. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/contact.py +0 -0
  25. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/curtain.py +0 -0
  26. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/hub2.py +0 -0
  27. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/humidifier.py +0 -0
  28. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/keypad.py +0 -0
  29. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/leak.py +0 -0
  30. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/light_strip.py +0 -0
  31. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/lock.py +0 -0
  32. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/meter.py +0 -0
  33. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/motion.py +0 -0
  34. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/plug.py +0 -0
  35. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/adv_parsers/relay_switch.py +0 -0
  36. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/api_config.py +0 -0
  37. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/__init__.py +0 -0
  38. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/base_cover.py +0 -0
  39. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/base_light.py +0 -0
  40. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/blind_tilt.py +0 -0
  41. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/bot.py +0 -0
  42. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/bulb.py +0 -0
  43. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/ceiling_light.py +0 -0
  44. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/contact.py +0 -0
  45. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/curtain.py +0 -0
  46. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/device.py +0 -0
  47. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/humidifier.py +0 -0
  48. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/keypad.py +0 -0
  49. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/light_strip.py +0 -0
  50. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/lock.py +0 -0
  51. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/meter.py +0 -0
  52. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/motion.py +0 -0
  53. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/devices/plug.py +0 -0
  54. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/discovery.py +0 -0
  55. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/enum.py +0 -0
  56. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/switchbot/models.py +0 -0
  57. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/tests/test_base_cover.py +0 -0
  58. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/tests/test_blind_tilt.py +0 -0
  59. {pyswitchbot-0.55.3 → pyswitchbot-0.56.0}/tests/test_curtain.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: PySwitchbot
3
- Version: 0.55.3
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 [![Build Status](https://travis-ci.org/sblibs/pySwitchbot.svg?branch=master)](https://travis-ci.org/sblibs/pySwitchbot)
25
34
 
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: PySwitchbot
3
- Version: 0.55.3
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 [![Build Status](https://travis-ci.org/sblibs/pySwitchbot.svg?branch=master)](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
@@ -15,7 +15,7 @@ setup(
15
15
  "cryptography>=39.0.0",
16
16
  "pyOpenSSL>=23.0.0",
17
17
  ],
18
- version="0.55.3",
18
+ version="0.56.0",
19
19
  description="A library to communicate with Switchbot",
20
20
  long_description=long_description,
21
21
  long_description_content_type="text/markdown",
@@ -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
+ }
@@ -57,6 +57,7 @@ class SwitchbotModel(StrEnum):
57
57
  KEYPAD = "WoKeypad"
58
58
  RELAY_SWITCH_1PM = "Relay Switch 1PM"
59
59
  RELAY_SWITCH_1 = "Relay Switch 1"
60
+ REMOTE = "WoRemote"
60
61
 
61
62
 
62
63
  class LockStatus(Enum):
@@ -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 test_trun_off():
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