PySwitchbot 0.58.0__tar.gz → 0.60.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 (78) hide show
  1. pyswitchbot-0.60.0/PKG-INFO +135 -0
  2. pyswitchbot-0.60.0/PySwitchbot.egg-info/PKG-INFO +135 -0
  3. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/PySwitchbot.egg-info/SOURCES.txt +9 -1
  4. pyswitchbot-0.60.0/README.md +102 -0
  5. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/setup.py +1 -1
  6. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/__init__.py +6 -0
  7. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/adv_parser.py +21 -0
  8. pyswitchbot-0.60.0/switchbot/adv_parsers/fan.py +33 -0
  9. pyswitchbot-0.60.0/switchbot/adv_parsers/hubmini_matter.py +37 -0
  10. pyswitchbot-0.60.0/switchbot/adv_parsers/roller_shade.py +29 -0
  11. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/const/__init__.py +4 -0
  12. pyswitchbot-0.60.0/switchbot/const/fan.py +14 -0
  13. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/devices/base_cover.py +2 -0
  14. pyswitchbot-0.60.0/switchbot/devices/fan.py +116 -0
  15. pyswitchbot-0.60.0/switchbot/devices/roller_shade.py +129 -0
  16. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/discovery.py +8 -1
  17. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/tests/test_adv_parser.py +226 -0
  18. pyswitchbot-0.60.0/tests/test_fan.py +172 -0
  19. pyswitchbot-0.60.0/tests/test_roller_shade.py +223 -0
  20. pyswitchbot-0.58.0/PKG-INFO +0 -70
  21. pyswitchbot-0.58.0/PySwitchbot.egg-info/PKG-INFO +0 -70
  22. pyswitchbot-0.58.0/README.md +0 -37
  23. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/LICENSE +0 -0
  24. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/MANIFEST.in +0 -0
  25. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/PySwitchbot.egg-info/dependency_links.txt +0 -0
  26. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/PySwitchbot.egg-info/requires.txt +0 -0
  27. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/PySwitchbot.egg-info/top_level.txt +0 -0
  28. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/pyproject.toml +0 -0
  29. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/setup.cfg +0 -0
  30. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/adv_parsers/__init__.py +0 -0
  31. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/adv_parsers/blind_tilt.py +0 -0
  32. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/adv_parsers/bot.py +0 -0
  33. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/adv_parsers/bulb.py +0 -0
  34. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/adv_parsers/ceiling_light.py +0 -0
  35. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/adv_parsers/contact.py +0 -0
  36. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/adv_parsers/curtain.py +0 -0
  37. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/adv_parsers/hub2.py +0 -0
  38. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/adv_parsers/humidifier.py +0 -0
  39. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/adv_parsers/keypad.py +0 -0
  40. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/adv_parsers/leak.py +0 -0
  41. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/adv_parsers/light_strip.py +0 -0
  42. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/adv_parsers/lock.py +0 -0
  43. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/adv_parsers/meter.py +0 -0
  44. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/adv_parsers/motion.py +0 -0
  45. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/adv_parsers/plug.py +0 -0
  46. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/adv_parsers/relay_switch.py +0 -0
  47. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/adv_parsers/remote.py +0 -0
  48. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/api_config.py +0 -0
  49. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/const/evaporative_humidifier.py +0 -0
  50. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/const/hub2.py +0 -0
  51. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/const/lock.py +0 -0
  52. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/devices/__init__.py +0 -0
  53. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/devices/base_light.py +0 -0
  54. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/devices/blind_tilt.py +0 -0
  55. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/devices/bot.py +0 -0
  56. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/devices/bulb.py +0 -0
  57. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/devices/ceiling_light.py +0 -0
  58. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/devices/contact.py +0 -0
  59. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/devices/curtain.py +0 -0
  60. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/devices/device.py +0 -0
  61. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/devices/evaporative_humidifier.py +0 -0
  62. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/devices/humidifier.py +0 -0
  63. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/devices/keypad.py +0 -0
  64. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/devices/light_strip.py +0 -0
  65. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/devices/lock.py +0 -0
  66. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/devices/meter.py +0 -0
  67. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/devices/motion.py +0 -0
  68. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/devices/plug.py +0 -0
  69. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/devices/relay_switch.py +0 -0
  70. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/enum.py +0 -0
  71. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/helpers.py +0 -0
  72. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/switchbot/models.py +0 -0
  73. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/tests/test_base_cover.py +0 -0
  74. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/tests/test_blind_tilt.py +0 -0
  75. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/tests/test_curtain.py +0 -0
  76. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/tests/test_evaporative_humidifier.py +0 -0
  77. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/tests/test_hub2.py +0 -0
  78. {pyswitchbot-0.58.0 → pyswitchbot-0.60.0}/tests/test_relay_switch.py +0 -0
@@ -0,0 +1,135 @@
1
+ Metadata-Version: 2.4
2
+ Name: PySwitchbot
3
+ Version: 0.60.0
4
+ Summary: A library to communicate with Switchbot
5
+ Home-page: https://github.com/sblibs/pySwitchbot/
6
+ Author: Daniel Hjelseth Hoyer
7
+ License: MIT
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Environment :: Other Environment
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python
13
+ Classifier: Topic :: Home Automation
14
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
15
+ Requires-Python: >=3.11
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Requires-Dist: aiohttp>=3.9.5
19
+ Requires-Dist: bleak>=0.19.0
20
+ Requires-Dist: bleak-retry-connector>=3.4.0
21
+ Requires-Dist: cryptography>=39.0.0
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: license-file
30
+ Dynamic: requires-dist
31
+ Dynamic: requires-python
32
+ Dynamic: summary
33
+
34
+ # pySwitchbot [![Build Status](https://travis-ci.org/sblibs/pySwitchbot.svg?branch=master)](https://travis-ci.org/sblibs/pySwitchbot)
35
+
36
+ Library to control Switchbot IoT devices https://www.switch-bot.com/bot
37
+
38
+ ## Obtaining encryption key for Switchbot Locks
39
+
40
+ Using the script `scripts/get_encryption_key.py` you can manually obtain locks encryption key.
41
+
42
+ Usage:
43
+
44
+ ```shell
45
+ $ python3 get_encryption_key.py MAC USERNAME
46
+ Key ID: XX
47
+ Encryption key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
48
+ ```
49
+
50
+ Where `MAC` is MAC address of the lock and `USERNAME` is your SwitchBot account username, after that script will ask for your password.
51
+ If authentication succeeds then script should output your key id and encryption key.
52
+
53
+ ## Examples:
54
+
55
+ #### WoLock (Lock-Pro)
56
+
57
+ Unlock:
58
+
59
+ ```python
60
+ import asyncio
61
+ from switchbot.discovery import GetSwitchbotDevices
62
+ from switchbot.devices import lock
63
+ from switchbot.const import SwitchbotModel
64
+
65
+ BLE_MAC="XX:XX:XX:XX:XX:XX" # The MAC of your lock
66
+ KEY_ID="XX" # The key-ID of your encryption-key for your lock
67
+ ENC_KEY="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" # The encryption-key with key-ID "XX"
68
+ LOCK_MODEL=SwitchbotModel.LOCK_PRO # Your lock model (here we use the Lock-Pro)
69
+
70
+
71
+ async def main():
72
+ wolock = await GetSwitchbotDevices().get_locks()
73
+ await lock.SwitchbotLock(
74
+ wolock[BLE_MAC].device, KEY_ID, ENCRYPTION_KEY, model=LOCK_MODEL
75
+ ).unlock()
76
+
77
+
78
+ asyncio.run(main())
79
+ ```
80
+
81
+ Lock:
82
+
83
+ ```python
84
+ import asyncio
85
+ from switchbot.discovery import GetSwitchbotDevices
86
+ from switchbot.devices import lock
87
+ from switchbot.const import SwitchbotModel
88
+
89
+ BLE_MAC="XX:XX:XX:XX:XX:XX" # The MAC of your lock
90
+ KEY_ID="XX" # The key-ID of your encryption-key for your lock
91
+ ENC_KEY="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" # The encryption-key with key-ID "XX"
92
+ LOCK_MODEL=SwitchbotModel.LOCK_PRO # Your lock model (here we use the Lock-Pro)
93
+
94
+
95
+ async def main():
96
+ wolock = await GetSwitchbotDevices().get_locks()
97
+ await lock.SwitchbotLock(
98
+ wolock[BLE_MAC].device, KEY_ID, ENCRYPTION_KEY, model=LOCK_MODEL
99
+ ).lock()
100
+
101
+
102
+ asyncio.run(main())
103
+ ```
104
+
105
+ #### WoCurtain (Curtain 3)
106
+
107
+ ```python
108
+ import asyncio
109
+ from pprint import pprint
110
+ from switchbot import GetSwitchbotDevices
111
+ from switchbot.devices import curtain
112
+
113
+
114
+ async def main():
115
+ # get the BLE advertisement data of all switchbot devices in the vicinity
116
+ advertisement_data = await GetSwitchbotDevices().discover()
117
+
118
+ for i in advertisement_data.values():
119
+ pprint(i)
120
+ print() # print newline so that devices' data is separated visually
121
+
122
+ # find your device's BLE address by inspecting the above printed debug logs, example below
123
+ ble_address = "9915077C-C6FD-5FF6-27D3-45087898790B"
124
+ # get the BLE device (via its address) and construct a curtain device
125
+ ble_device = advertisement_data[ble_address].device
126
+ curtain_device = curtain.SwitchbotCurtain(ble_device, reverse_mode=False)
127
+
128
+ pprint(await curtain_device.get_device_data())
129
+ pprint(await curtain_device.get_basic_info())
130
+ await curtain_device.set_position(100)
131
+
132
+
133
+ if __name__ == "__main__":
134
+ asyncio.run(main())
135
+ ```
@@ -0,0 +1,135 @@
1
+ Metadata-Version: 2.4
2
+ Name: PySwitchbot
3
+ Version: 0.60.0
4
+ Summary: A library to communicate with Switchbot
5
+ Home-page: https://github.com/sblibs/pySwitchbot/
6
+ Author: Daniel Hjelseth Hoyer
7
+ License: MIT
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Environment :: Other Environment
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python
13
+ Classifier: Topic :: Home Automation
14
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
15
+ Requires-Python: >=3.11
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Requires-Dist: aiohttp>=3.9.5
19
+ Requires-Dist: bleak>=0.19.0
20
+ Requires-Dist: bleak-retry-connector>=3.4.0
21
+ Requires-Dist: cryptography>=39.0.0
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: license-file
30
+ Dynamic: requires-dist
31
+ Dynamic: requires-python
32
+ Dynamic: summary
33
+
34
+ # pySwitchbot [![Build Status](https://travis-ci.org/sblibs/pySwitchbot.svg?branch=master)](https://travis-ci.org/sblibs/pySwitchbot)
35
+
36
+ Library to control Switchbot IoT devices https://www.switch-bot.com/bot
37
+
38
+ ## Obtaining encryption key for Switchbot Locks
39
+
40
+ Using the script `scripts/get_encryption_key.py` you can manually obtain locks encryption key.
41
+
42
+ Usage:
43
+
44
+ ```shell
45
+ $ python3 get_encryption_key.py MAC USERNAME
46
+ Key ID: XX
47
+ Encryption key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
48
+ ```
49
+
50
+ Where `MAC` is MAC address of the lock and `USERNAME` is your SwitchBot account username, after that script will ask for your password.
51
+ If authentication succeeds then script should output your key id and encryption key.
52
+
53
+ ## Examples:
54
+
55
+ #### WoLock (Lock-Pro)
56
+
57
+ Unlock:
58
+
59
+ ```python
60
+ import asyncio
61
+ from switchbot.discovery import GetSwitchbotDevices
62
+ from switchbot.devices import lock
63
+ from switchbot.const import SwitchbotModel
64
+
65
+ BLE_MAC="XX:XX:XX:XX:XX:XX" # The MAC of your lock
66
+ KEY_ID="XX" # The key-ID of your encryption-key for your lock
67
+ ENC_KEY="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" # The encryption-key with key-ID "XX"
68
+ LOCK_MODEL=SwitchbotModel.LOCK_PRO # Your lock model (here we use the Lock-Pro)
69
+
70
+
71
+ async def main():
72
+ wolock = await GetSwitchbotDevices().get_locks()
73
+ await lock.SwitchbotLock(
74
+ wolock[BLE_MAC].device, KEY_ID, ENCRYPTION_KEY, model=LOCK_MODEL
75
+ ).unlock()
76
+
77
+
78
+ asyncio.run(main())
79
+ ```
80
+
81
+ Lock:
82
+
83
+ ```python
84
+ import asyncio
85
+ from switchbot.discovery import GetSwitchbotDevices
86
+ from switchbot.devices import lock
87
+ from switchbot.const import SwitchbotModel
88
+
89
+ BLE_MAC="XX:XX:XX:XX:XX:XX" # The MAC of your lock
90
+ KEY_ID="XX" # The key-ID of your encryption-key for your lock
91
+ ENC_KEY="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" # The encryption-key with key-ID "XX"
92
+ LOCK_MODEL=SwitchbotModel.LOCK_PRO # Your lock model (here we use the Lock-Pro)
93
+
94
+
95
+ async def main():
96
+ wolock = await GetSwitchbotDevices().get_locks()
97
+ await lock.SwitchbotLock(
98
+ wolock[BLE_MAC].device, KEY_ID, ENCRYPTION_KEY, model=LOCK_MODEL
99
+ ).lock()
100
+
101
+
102
+ asyncio.run(main())
103
+ ```
104
+
105
+ #### WoCurtain (Curtain 3)
106
+
107
+ ```python
108
+ import asyncio
109
+ from pprint import pprint
110
+ from switchbot import GetSwitchbotDevices
111
+ from switchbot.devices import curtain
112
+
113
+
114
+ async def main():
115
+ # get the BLE advertisement data of all switchbot devices in the vicinity
116
+ advertisement_data = await GetSwitchbotDevices().discover()
117
+
118
+ for i in advertisement_data.values():
119
+ pprint(i)
120
+ print() # print newline so that devices' data is separated visually
121
+
122
+ # find your device's BLE address by inspecting the above printed debug logs, example below
123
+ ble_address = "9915077C-C6FD-5FF6-27D3-45087898790B"
124
+ # get the BLE device (via its address) and construct a curtain device
125
+ ble_device = advertisement_data[ble_address].device
126
+ curtain_device = curtain.SwitchbotCurtain(ble_device, reverse_mode=False)
127
+
128
+ pprint(await curtain_device.get_device_data())
129
+ pprint(await curtain_device.get_basic_info())
130
+ await curtain_device.set_position(100)
131
+
132
+
133
+ if __name__ == "__main__":
134
+ asyncio.run(main())
135
+ ```
@@ -22,7 +22,9 @@ switchbot/adv_parsers/bulb.py
22
22
  switchbot/adv_parsers/ceiling_light.py
23
23
  switchbot/adv_parsers/contact.py
24
24
  switchbot/adv_parsers/curtain.py
25
+ switchbot/adv_parsers/fan.py
25
26
  switchbot/adv_parsers/hub2.py
27
+ switchbot/adv_parsers/hubmini_matter.py
26
28
  switchbot/adv_parsers/humidifier.py
27
29
  switchbot/adv_parsers/keypad.py
28
30
  switchbot/adv_parsers/leak.py
@@ -33,8 +35,10 @@ switchbot/adv_parsers/motion.py
33
35
  switchbot/adv_parsers/plug.py
34
36
  switchbot/adv_parsers/relay_switch.py
35
37
  switchbot/adv_parsers/remote.py
38
+ switchbot/adv_parsers/roller_shade.py
36
39
  switchbot/const/__init__.py
37
40
  switchbot/const/evaporative_humidifier.py
41
+ switchbot/const/fan.py
38
42
  switchbot/const/hub2.py
39
43
  switchbot/const/lock.py
40
44
  switchbot/devices/__init__.py
@@ -48,6 +52,7 @@ switchbot/devices/contact.py
48
52
  switchbot/devices/curtain.py
49
53
  switchbot/devices/device.py
50
54
  switchbot/devices/evaporative_humidifier.py
55
+ switchbot/devices/fan.py
51
56
  switchbot/devices/humidifier.py
52
57
  switchbot/devices/keypad.py
53
58
  switchbot/devices/light_strip.py
@@ -56,10 +61,13 @@ switchbot/devices/meter.py
56
61
  switchbot/devices/motion.py
57
62
  switchbot/devices/plug.py
58
63
  switchbot/devices/relay_switch.py
64
+ switchbot/devices/roller_shade.py
59
65
  tests/test_adv_parser.py
60
66
  tests/test_base_cover.py
61
67
  tests/test_blind_tilt.py
62
68
  tests/test_curtain.py
63
69
  tests/test_evaporative_humidifier.py
70
+ tests/test_fan.py
64
71
  tests/test_hub2.py
65
- tests/test_relay_switch.py
72
+ tests/test_relay_switch.py
73
+ tests/test_roller_shade.py
@@ -0,0 +1,102 @@
1
+ # pySwitchbot [![Build Status](https://travis-ci.org/sblibs/pySwitchbot.svg?branch=master)](https://travis-ci.org/sblibs/pySwitchbot)
2
+
3
+ Library to control Switchbot IoT devices https://www.switch-bot.com/bot
4
+
5
+ ## Obtaining encryption key for Switchbot Locks
6
+
7
+ Using the script `scripts/get_encryption_key.py` you can manually obtain locks encryption key.
8
+
9
+ Usage:
10
+
11
+ ```shell
12
+ $ python3 get_encryption_key.py MAC USERNAME
13
+ Key ID: XX
14
+ Encryption key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
15
+ ```
16
+
17
+ Where `MAC` is MAC address of the lock and `USERNAME` is your SwitchBot account username, after that script will ask for your password.
18
+ If authentication succeeds then script should output your key id and encryption key.
19
+
20
+ ## Examples:
21
+
22
+ #### WoLock (Lock-Pro)
23
+
24
+ Unlock:
25
+
26
+ ```python
27
+ import asyncio
28
+ from switchbot.discovery import GetSwitchbotDevices
29
+ from switchbot.devices import lock
30
+ from switchbot.const import SwitchbotModel
31
+
32
+ BLE_MAC="XX:XX:XX:XX:XX:XX" # The MAC of your lock
33
+ KEY_ID="XX" # The key-ID of your encryption-key for your lock
34
+ ENC_KEY="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" # The encryption-key with key-ID "XX"
35
+ LOCK_MODEL=SwitchbotModel.LOCK_PRO # Your lock model (here we use the Lock-Pro)
36
+
37
+
38
+ async def main():
39
+ wolock = await GetSwitchbotDevices().get_locks()
40
+ await lock.SwitchbotLock(
41
+ wolock[BLE_MAC].device, KEY_ID, ENCRYPTION_KEY, model=LOCK_MODEL
42
+ ).unlock()
43
+
44
+
45
+ asyncio.run(main())
46
+ ```
47
+
48
+ Lock:
49
+
50
+ ```python
51
+ import asyncio
52
+ from switchbot.discovery import GetSwitchbotDevices
53
+ from switchbot.devices import lock
54
+ from switchbot.const import SwitchbotModel
55
+
56
+ BLE_MAC="XX:XX:XX:XX:XX:XX" # The MAC of your lock
57
+ KEY_ID="XX" # The key-ID of your encryption-key for your lock
58
+ ENC_KEY="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" # The encryption-key with key-ID "XX"
59
+ LOCK_MODEL=SwitchbotModel.LOCK_PRO # Your lock model (here we use the Lock-Pro)
60
+
61
+
62
+ async def main():
63
+ wolock = await GetSwitchbotDevices().get_locks()
64
+ await lock.SwitchbotLock(
65
+ wolock[BLE_MAC].device, KEY_ID, ENCRYPTION_KEY, model=LOCK_MODEL
66
+ ).lock()
67
+
68
+
69
+ asyncio.run(main())
70
+ ```
71
+
72
+ #### WoCurtain (Curtain 3)
73
+
74
+ ```python
75
+ import asyncio
76
+ from pprint import pprint
77
+ from switchbot import GetSwitchbotDevices
78
+ from switchbot.devices import curtain
79
+
80
+
81
+ async def main():
82
+ # get the BLE advertisement data of all switchbot devices in the vicinity
83
+ advertisement_data = await GetSwitchbotDevices().discover()
84
+
85
+ for i in advertisement_data.values():
86
+ pprint(i)
87
+ print() # print newline so that devices' data is separated visually
88
+
89
+ # find your device's BLE address by inspecting the above printed debug logs, example below
90
+ ble_address = "9915077C-C6FD-5FF6-27D3-45087898790B"
91
+ # get the BLE device (via its address) and construct a curtain device
92
+ ble_device = advertisement_data[ble_address].device
93
+ curtain_device = curtain.SwitchbotCurtain(ble_device, reverse_mode=False)
94
+
95
+ pprint(await curtain_device.get_device_data())
96
+ pprint(await curtain_device.get_basic_info())
97
+ await curtain_device.set_position(100)
98
+
99
+
100
+ if __name__ == "__main__":
101
+ asyncio.run(main())
102
+ ```
@@ -20,7 +20,7 @@ setup(
20
20
  "cryptography>=39.0.0",
21
21
  "pyOpenSSL>=23.0.0",
22
22
  ],
23
- version="0.58.0",
23
+ version="0.60.0",
24
24
  description="A library to communicate with Switchbot",
25
25
  long_description=long_description,
26
26
  long_description_content_type="text/markdown",
@@ -10,6 +10,7 @@ from bleak_retry_connector import (
10
10
 
11
11
  from .adv_parser import SwitchbotSupportedType, parse_advertisement_data
12
12
  from .const import (
13
+ FanMode,
13
14
  LockStatus,
14
15
  SwitchbotAccountConnectionError,
15
16
  SwitchbotApiError,
@@ -24,16 +25,19 @@ from .devices.ceiling_light import SwitchbotCeilingLight
24
25
  from .devices.curtain import SwitchbotCurtain
25
26
  from .devices.device import ColorMode, SwitchbotDevice, SwitchbotEncryptedDevice
26
27
  from .devices.evaporative_humidifier import SwitchbotEvaporativeHumidifier
28
+ from .devices.fan import SwitchbotFan
27
29
  from .devices.humidifier import SwitchbotHumidifier
28
30
  from .devices.light_strip import SwitchbotLightStrip
29
31
  from .devices.lock import SwitchbotLock
30
32
  from .devices.plug import SwitchbotPlugMini
31
33
  from .devices.relay_switch import SwitchbotRelaySwitch
34
+ from .devices.roller_shade import SwitchbotRollerShade
32
35
  from .discovery import GetSwitchbotDevices
33
36
  from .models import SwitchBotAdvertisement
34
37
 
35
38
  __all__ = [
36
39
  "ColorMode",
40
+ "FanMode",
37
41
  "GetSwitchbotDevices",
38
42
  "LockStatus",
39
43
  "SwitchBotAdvertisement",
@@ -50,6 +54,7 @@ __all__ = [
50
54
  "SwitchbotDevice",
51
55
  "SwitchbotEncryptedDevice",
52
56
  "SwitchbotEvaporativeHumidifier",
57
+ "SwitchbotFan",
53
58
  "SwitchbotHumidifier",
54
59
  "SwitchbotLightStrip",
55
60
  "SwitchbotLock",
@@ -58,6 +63,7 @@ __all__ = [
58
63
  "SwitchbotPlugMini",
59
64
  "SwitchbotPlugMini",
60
65
  "SwitchbotRelaySwitch",
66
+ "SwitchbotRollerShade",
61
67
  "SwitchbotSupportedType",
62
68
  "SwitchbotSupportedType",
63
69
  "close_stale_connections",
@@ -16,7 +16,9 @@ from .adv_parsers.bulb import process_color_bulb
16
16
  from .adv_parsers.ceiling_light import process_woceiling
17
17
  from .adv_parsers.contact import process_wocontact
18
18
  from .adv_parsers.curtain import process_wocurtain
19
+ from .adv_parsers.fan import process_fan
19
20
  from .adv_parsers.hub2 import process_wohub2
21
+ from .adv_parsers.hubmini_matter import process_hubmini_matter
20
22
  from .adv_parsers.humidifier import process_evaporative_humidifier, process_wohumidifier
21
23
  from .adv_parsers.keypad import process_wokeypad
22
24
  from .adv_parsers.leak import process_leak
@@ -30,6 +32,7 @@ from .adv_parsers.relay_switch import (
30
32
  process_worelay_switch_1pm,
31
33
  )
32
34
  from .adv_parsers.remote import process_woremote
35
+ from .adv_parsers.roller_shade import process_worollershade
33
36
  from .const import SwitchbotModel
34
37
  from .models import SwitchBotAdvertisement
35
38
 
@@ -216,6 +219,24 @@ SUPPORTED_TYPES: dict[str, SwitchbotSupportedType] = {
216
219
  "func": process_woremote,
217
220
  "manufacturer_id": 89,
218
221
  },
222
+ ",": {
223
+ "modelName": SwitchbotModel.ROLLER_SHADE,
224
+ "modelFriendlyName": "Roller Shade",
225
+ "func": process_worollershade,
226
+ "manufacturer_id": 2409,
227
+ },
228
+ "%": {
229
+ "modelName": SwitchbotModel.HUBMINI_MATTER,
230
+ "modelFriendlyName": "HubMini Matter",
231
+ "func": process_hubmini_matter,
232
+ "manufacturer_id": 2409,
233
+ },
234
+ "~": {
235
+ "modelName": SwitchbotModel.CIRCULATOR_FAN,
236
+ "modelFriendlyName": "Circulator Fan",
237
+ "func": process_fan,
238
+ "manufacturer_id": 2409,
239
+ },
219
240
  }
220
241
 
221
242
  _SWITCHBOT_MODEL_TO_CHAR = {
@@ -0,0 +1,33 @@
1
+ """Fan adv parser."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from ..const.fan import FanMode
6
+
7
+
8
+ def process_fan(data: bytes | None, mfr_data: bytes | None) -> dict[str, bool | int]:
9
+ """Process fan services data."""
10
+ if mfr_data is None:
11
+ return {}
12
+
13
+ device_data = mfr_data[6:]
14
+
15
+ _seq_num = device_data[0]
16
+ _isOn = bool(device_data[1] & 0b10000000)
17
+ _mode = (device_data[1] & 0b01110000) >> 4
18
+ _mode = FanMode(_mode).name if 1 <= _mode <= 4 else None
19
+ _nightLight = (device_data[1] & 0b00001100) >> 2
20
+ _oscillate_left_and_right = bool(device_data[1] & 0b00000010)
21
+ _oscillate_up_and_down = bool(device_data[1] & 0b00000001)
22
+ _battery = device_data[2] & 0b01111111
23
+ _speed = device_data[3] & 0b01111111
24
+
25
+ return {
26
+ "sequence_number": _seq_num,
27
+ "isOn": _isOn,
28
+ "mode": _mode,
29
+ "nightLight": _nightLight,
30
+ "oscillating": _oscillate_left_and_right | _oscillate_up_and_down,
31
+ "battery": _battery,
32
+ "speed": _speed,
33
+ }
@@ -0,0 +1,37 @@
1
+ """Hubmini matter parser."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+
8
+ def process_hubmini_matter(
9
+ data: bytes | None, mfr_data: bytes | None
10
+ ) -> dict[str, Any]:
11
+ """Process Hubmini matter sensor manufacturer data."""
12
+ temp_data = None
13
+
14
+ if mfr_data:
15
+ temp_data = mfr_data[13:16]
16
+
17
+ if not temp_data:
18
+ return {}
19
+
20
+ _temp_sign = 1 if temp_data[1] & 0b10000000 else -1
21
+ _temp_c = _temp_sign * (
22
+ (temp_data[1] & 0b01111111) + ((temp_data[0] & 0b00001111) / 10)
23
+ )
24
+ _temp_f = (_temp_c * 9 / 5) + 32
25
+ _temp_f = (_temp_f * 10) / 10
26
+ humidity = temp_data[2] & 0b01111111
27
+
28
+ if _temp_c == 0 and humidity == 0:
29
+ return {}
30
+
31
+ paraser_data = {
32
+ "temp": {"c": _temp_c, "f": _temp_f},
33
+ "temperature": _temp_c,
34
+ "fahrenheit": bool(temp_data[2] & 0b10000000),
35
+ "humidity": humidity,
36
+ }
37
+ return paraser_data
@@ -0,0 +1,29 @@
1
+ """Library to handle connection with Switchbot."""
2
+
3
+ from __future__ import annotations
4
+
5
+
6
+ def process_worollershade(
7
+ data: bytes | None, mfr_data: bytes | None, reverse: bool = True
8
+ ) -> dict[str, bool | int]:
9
+ """Process woRollerShade services data."""
10
+ if mfr_data is None:
11
+ return {}
12
+
13
+ device_data = mfr_data[6:]
14
+
15
+ _position = max(min(device_data[2] & 0b01111111, 100), 0)
16
+ _calibrated = bool(device_data[2] & 0b10000000)
17
+ _in_motion = bool(device_data[1] & 0b00000110)
18
+ _light_level = (device_data[3] >> 4) & 0b00001111
19
+ _device_chain = device_data[3] & 0b00001111
20
+
21
+ return {
22
+ "calibration": _calibrated,
23
+ "battery": data[2] & 0b01111111 if data else None,
24
+ "inMotion": _in_motion,
25
+ "position": (100 - _position) if reverse else _position,
26
+ "lightLevel": _light_level,
27
+ "deviceChain": _device_chain,
28
+ "sequence_number": device_data[0],
29
+ }
@@ -3,6 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  from ..enum import StrEnum
6
+ from .fan import FanMode as FanMode
6
7
 
7
8
  # Preserve old LockStatus export for backwards compatibility
8
9
  from .lock import LockStatus as LockStatus
@@ -63,3 +64,6 @@ class SwitchbotModel(StrEnum):
63
64
  RELAY_SWITCH_1 = "Relay Switch 1"
64
65
  REMOTE = "WoRemote"
65
66
  EVAPORATIVE_HUMIDIFIER = "Evaporative Humidifier"
67
+ ROLLER_SHADE = "Roller Shade"
68
+ HUBMINI_MATTER = "HubMini Matter"
69
+ CIRCULATOR_FAN = "Circulator Fan"
@@ -0,0 +1,14 @@
1
+ from __future__ import annotations
2
+
3
+ from enum import Enum
4
+
5
+
6
+ class FanMode(Enum):
7
+ NORMAL = 1
8
+ NATURAL = 2
9
+ SLEEP = 3
10
+ BABY = 4
11
+
12
+ @classmethod
13
+ def get_modes(cls) -> list[str]:
14
+ return [mode.name for mode in cls]
@@ -10,6 +10,8 @@ from .device import REQ_HEADER, SwitchbotDevice, update_after_operation
10
10
 
11
11
  # Cover keys
12
12
  COVER_COMMAND = "4501"
13
+ ROLLERSHADE_COMMAND = "4701"
14
+ CONTROL_SOURCE = "00"
13
15
 
14
16
  # For second element of open and close arrs we should add two bytes i.e. ff00
15
17
  # First byte [ff] stands for speed (00 or ff - normal, 01 - slow) *