bumble 0.0.179__tar.gz → 0.0.180__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 (520) hide show
  1. {bumble-0.0.179 → bumble-0.0.180}/.vscode/settings.json +3 -0
  2. {bumble-0.0.179 → bumble-0.0.180}/PKG-INFO +1 -1
  3. {bumble-0.0.179 → bumble-0.0.180}/bumble/_version.py +2 -2
  4. {bumble-0.0.179 → bumble-0.0.180}/bumble/device.py +64 -23
  5. {bumble-0.0.179 → bumble-0.0.180}/bumble/gatt.py +117 -7
  6. {bumble-0.0.179 → bumble-0.0.180}/bumble/gatt_client.py +56 -20
  7. {bumble-0.0.179 → bumble-0.0.180}/bumble/hci.py +4 -0
  8. {bumble-0.0.179 → bumble-0.0.180}/bumble/helpers.py +67 -42
  9. {bumble-0.0.179 → bumble-0.0.180}/bumble/l2cap.py +8 -0
  10. bumble-0.0.180/bumble/profiles/csip.py +147 -0
  11. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/common.py +1 -1
  12. {bumble-0.0.179 → bumble-0.0.180}/bumble.egg-info/PKG-INFO +1 -1
  13. {bumble-0.0.179 → bumble-0.0.180}/bumble.egg-info/SOURCES.txt +2 -0
  14. bumble-0.0.180/tests/csip_test.py +74 -0
  15. {bumble-0.0.179 → bumble-0.0.180}/tests/gatt_test.py +79 -0
  16. {bumble-0.0.179 → bumble-0.0.180}/tests/test_utils.py +3 -0
  17. {bumble-0.0.179 → bumble-0.0.180}/.git-blame-ignore-revs +0 -0
  18. {bumble-0.0.179 → bumble-0.0.180}/.github/workflows/code-check.yml +0 -0
  19. {bumble-0.0.179 → bumble-0.0.180}/.github/workflows/codeql-analysis.yml +0 -0
  20. {bumble-0.0.179 → bumble-0.0.180}/.github/workflows/python-avatar.yml +0 -0
  21. {bumble-0.0.179 → bumble-0.0.180}/.github/workflows/python-build-test.yml +0 -0
  22. {bumble-0.0.179 → bumble-0.0.180}/.github/workflows/python-publish.yml +0 -0
  23. {bumble-0.0.179 → bumble-0.0.180}/.gitignore +0 -0
  24. {bumble-0.0.179 → bumble-0.0.180}/CONTRIBUTING.md +0 -0
  25. {bumble-0.0.179 → bumble-0.0.180}/LICENSE +0 -0
  26. {bumble-0.0.179 → bumble-0.0.180}/README.md +0 -0
  27. {bumble-0.0.179 → bumble-0.0.180}/apps/README.md +0 -0
  28. {bumble-0.0.179 → bumble-0.0.180}/apps/__init__.py +0 -0
  29. {bumble-0.0.179 → bumble-0.0.180}/apps/bench.py +0 -0
  30. {bumble-0.0.179 → bumble-0.0.180}/apps/console.py +0 -0
  31. {bumble-0.0.179 → bumble-0.0.180}/apps/controller_info.py +0 -0
  32. {bumble-0.0.179 → bumble-0.0.180}/apps/controllers.py +0 -0
  33. {bumble-0.0.179 → bumble-0.0.180}/apps/gatt_dump.py +0 -0
  34. {bumble-0.0.179 → bumble-0.0.180}/apps/gg_bridge.py +0 -0
  35. {bumble-0.0.179 → bumble-0.0.180}/apps/hci_bridge.py +0 -0
  36. {bumble-0.0.179 → bumble-0.0.180}/apps/l2cap_bridge.py +0 -0
  37. {bumble-0.0.179 → bumble-0.0.180}/apps/link_relay/__init__.py +0 -0
  38. {bumble-0.0.179 → bumble-0.0.180}/apps/link_relay/link_relay.py +0 -0
  39. {bumble-0.0.179 → bumble-0.0.180}/apps/link_relay/logging.yml +0 -0
  40. {bumble-0.0.179 → bumble-0.0.180}/apps/pair.py +0 -0
  41. {bumble-0.0.179 → bumble-0.0.180}/apps/pandora_server.py +0 -0
  42. {bumble-0.0.179 → bumble-0.0.180}/apps/scan.py +0 -0
  43. {bumble-0.0.179 → bumble-0.0.180}/apps/show.py +0 -0
  44. {bumble-0.0.179 → bumble-0.0.180}/apps/speaker/__init__.py +0 -0
  45. {bumble-0.0.179 → bumble-0.0.180}/apps/speaker/logo.svg +0 -0
  46. {bumble-0.0.179 → bumble-0.0.180}/apps/speaker/speaker.css +0 -0
  47. {bumble-0.0.179 → bumble-0.0.180}/apps/speaker/speaker.html +0 -0
  48. {bumble-0.0.179 → bumble-0.0.180}/apps/speaker/speaker.js +0 -0
  49. {bumble-0.0.179 → bumble-0.0.180}/apps/speaker/speaker.py +0 -0
  50. {bumble-0.0.179 → bumble-0.0.180}/apps/unbond.py +0 -0
  51. {bumble-0.0.179 → bumble-0.0.180}/apps/usb_probe.py +0 -0
  52. {bumble-0.0.179 → bumble-0.0.180}/bumble/__init__.py +0 -0
  53. {bumble-0.0.179 → bumble-0.0.180}/bumble/a2dp.py +0 -0
  54. {bumble-0.0.179 → bumble-0.0.180}/bumble/at.py +0 -0
  55. {bumble-0.0.179 → bumble-0.0.180}/bumble/att.py +0 -0
  56. {bumble-0.0.179 → bumble-0.0.180}/bumble/avdtp.py +0 -0
  57. {bumble-0.0.179 → bumble-0.0.180}/bumble/bridge.py +0 -0
  58. {bumble-0.0.179 → bumble-0.0.180}/bumble/codecs.py +0 -0
  59. {bumble-0.0.179 → bumble-0.0.180}/bumble/colors.py +0 -0
  60. {bumble-0.0.179 → bumble-0.0.180}/bumble/company_ids.py +0 -0
  61. {bumble-0.0.179 → bumble-0.0.180}/bumble/controller.py +0 -0
  62. {bumble-0.0.179 → bumble-0.0.180}/bumble/core.py +0 -0
  63. {bumble-0.0.179 → bumble-0.0.180}/bumble/crypto.py +0 -0
  64. {bumble-0.0.179 → bumble-0.0.180}/bumble/decoder.py +0 -0
  65. {bumble-0.0.179 → bumble-0.0.180}/bumble/drivers/__init__.py +0 -0
  66. {bumble-0.0.179 → bumble-0.0.180}/bumble/drivers/rtk.py +0 -0
  67. {bumble-0.0.179 → bumble-0.0.180}/bumble/gap.py +0 -0
  68. {bumble-0.0.179 → bumble-0.0.180}/bumble/gatt_server.py +0 -0
  69. {bumble-0.0.179 → bumble-0.0.180}/bumble/hfp.py +0 -0
  70. {bumble-0.0.179 → bumble-0.0.180}/bumble/hid.py +0 -0
  71. {bumble-0.0.179 → bumble-0.0.180}/bumble/host.py +0 -0
  72. {bumble-0.0.179 → bumble-0.0.180}/bumble/keys.py +0 -0
  73. {bumble-0.0.179 → bumble-0.0.180}/bumble/link.py +0 -0
  74. {bumble-0.0.179 → bumble-0.0.180}/bumble/pairing.py +0 -0
  75. {bumble-0.0.179 → bumble-0.0.180}/bumble/pandora/__init__.py +0 -0
  76. {bumble-0.0.179 → bumble-0.0.180}/bumble/pandora/config.py +0 -0
  77. {bumble-0.0.179 → bumble-0.0.180}/bumble/pandora/device.py +0 -0
  78. {bumble-0.0.179 → bumble-0.0.180}/bumble/pandora/host.py +0 -0
  79. {bumble-0.0.179 → bumble-0.0.180}/bumble/pandora/py.typed +0 -0
  80. {bumble-0.0.179 → bumble-0.0.180}/bumble/pandora/security.py +0 -0
  81. {bumble-0.0.179 → bumble-0.0.180}/bumble/pandora/utils.py +0 -0
  82. {bumble-0.0.179 → bumble-0.0.180}/bumble/profiles/__init__.py +0 -0
  83. {bumble-0.0.179 → bumble-0.0.180}/bumble/profiles/asha_service.py +0 -0
  84. {bumble-0.0.179 → bumble-0.0.180}/bumble/profiles/battery_service.py +0 -0
  85. {bumble-0.0.179 → bumble-0.0.180}/bumble/profiles/device_information_service.py +0 -0
  86. {bumble-0.0.179 → bumble-0.0.180}/bumble/profiles/heart_rate_service.py +0 -0
  87. {bumble-0.0.179 → bumble-0.0.180}/bumble/profiles/py.typed +0 -0
  88. {bumble-0.0.179 → bumble-0.0.180}/bumble/py.typed +0 -0
  89. {bumble-0.0.179 → bumble-0.0.180}/bumble/rfcomm.py +0 -0
  90. {bumble-0.0.179 → bumble-0.0.180}/bumble/sdp.py +0 -0
  91. {bumble-0.0.179 → bumble-0.0.180}/bumble/smp.py +0 -0
  92. {bumble-0.0.179 → bumble-0.0.180}/bumble/snoop.py +0 -0
  93. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/__init__.py +0 -0
  94. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/android_emulator.py +0 -0
  95. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/android_netsim.py +0 -0
  96. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/file.py +0 -0
  97. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/grpc_protobuf/__init__.py +0 -0
  98. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/grpc_protobuf/common_pb2.py +0 -0
  99. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/grpc_protobuf/common_pb2.pyi +0 -0
  100. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/grpc_protobuf/common_pb2_grpc.py +0 -0
  101. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/grpc_protobuf/emulated_bluetooth_device_pb2.py +0 -0
  102. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/grpc_protobuf/emulated_bluetooth_device_pb2.pyi +0 -0
  103. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/grpc_protobuf/emulated_bluetooth_device_pb2_grpc.py +0 -0
  104. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/grpc_protobuf/emulated_bluetooth_packets_pb2.py +0 -0
  105. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/grpc_protobuf/emulated_bluetooth_packets_pb2.pyi +0 -0
  106. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/grpc_protobuf/emulated_bluetooth_packets_pb2_grpc.py +0 -0
  107. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/grpc_protobuf/emulated_bluetooth_pb2.py +0 -0
  108. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/grpc_protobuf/emulated_bluetooth_pb2.pyi +0 -0
  109. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/grpc_protobuf/emulated_bluetooth_pb2_grpc.py +0 -0
  110. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/grpc_protobuf/emulated_bluetooth_vhci_pb2.py +0 -0
  111. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/grpc_protobuf/emulated_bluetooth_vhci_pb2.pyi +0 -0
  112. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/grpc_protobuf/emulated_bluetooth_vhci_pb2_grpc.py +0 -0
  113. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/grpc_protobuf/grpc_endpoint_description_pb2.py +0 -0
  114. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/grpc_protobuf/grpc_endpoint_description_pb2.pyi +0 -0
  115. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/grpc_protobuf/grpc_endpoint_description_pb2_grpc.py +0 -0
  116. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/grpc_protobuf/hci_packet_pb2.py +0 -0
  117. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/grpc_protobuf/hci_packet_pb2.pyi +0 -0
  118. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/grpc_protobuf/hci_packet_pb2_grpc.py +0 -0
  119. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/grpc_protobuf/packet_streamer_pb2.py +0 -0
  120. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/grpc_protobuf/packet_streamer_pb2.pyi +0 -0
  121. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/grpc_protobuf/packet_streamer_pb2_grpc.py +0 -0
  122. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/grpc_protobuf/startup_pb2.py +0 -0
  123. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/grpc_protobuf/startup_pb2.pyi +0 -0
  124. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/grpc_protobuf/startup_pb2_grpc.py +0 -0
  125. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/hci_socket.py +0 -0
  126. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/pty.py +0 -0
  127. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/py.typed +0 -0
  128. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/pyusb.py +0 -0
  129. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/serial.py +0 -0
  130. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/tcp_client.py +0 -0
  131. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/tcp_server.py +0 -0
  132. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/udp.py +0 -0
  133. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/usb.py +0 -0
  134. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/vhci.py +0 -0
  135. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/ws_client.py +0 -0
  136. {bumble-0.0.179 → bumble-0.0.180}/bumble/transport/ws_server.py +0 -0
  137. {bumble-0.0.179 → bumble-0.0.180}/bumble/utils.py +0 -0
  138. {bumble-0.0.179 → bumble-0.0.180}/bumble/vendor/__init__.py +0 -0
  139. {bumble-0.0.179 → bumble-0.0.180}/bumble/vendor/android/__init__.py +0 -0
  140. {bumble-0.0.179 → bumble-0.0.180}/bumble/vendor/android/hci.py +0 -0
  141. {bumble-0.0.179 → bumble-0.0.180}/bumble/vendor/zephyr/__init__.py +0 -0
  142. {bumble-0.0.179 → bumble-0.0.180}/bumble/vendor/zephyr/hci.py +0 -0
  143. {bumble-0.0.179 → bumble-0.0.180}/bumble.egg-info/dependency_links.txt +0 -0
  144. {bumble-0.0.179 → bumble-0.0.180}/bumble.egg-info/entry_points.txt +0 -0
  145. {bumble-0.0.179 → bumble-0.0.180}/bumble.egg-info/requires.txt +0 -0
  146. {bumble-0.0.179 → bumble-0.0.180}/bumble.egg-info/top_level.txt +0 -0
  147. {bumble-0.0.179 → bumble-0.0.180}/docs/README.md +0 -0
  148. {bumble-0.0.179 → bumble-0.0.180}/docs/images/logo.png +0 -0
  149. {bumble-0.0.179 → bumble-0.0.180}/docs/images/logo.svg +0 -0
  150. {bumble-0.0.179 → bumble-0.0.180}/docs/images/logo.vectornator/Artboard0.json +0 -0
  151. {bumble-0.0.179 → bumble-0.0.180}/docs/images/logo.vectornator/Document.json +0 -0
  152. {bumble-0.0.179 → bumble-0.0.180}/docs/images/logo.vectornator/Manifest.json +0 -0
  153. {bumble-0.0.179 → bumble-0.0.180}/docs/images/logo.vectornator/Thumbnail.png +0 -0
  154. {bumble-0.0.179 → bumble-0.0.180}/docs/images/logo.vectornator/UndoHistory.json +0 -0
  155. {bumble-0.0.179 → bumble-0.0.180}/docs/images/logo_framed.png +0 -0
  156. {bumble-0.0.179 → bumble-0.0.180}/docs/images/logo_framed.svg +0 -0
  157. {bumble-0.0.179 → bumble-0.0.180}/docs/images/logo_framed.vectornator/Artboard0.json +0 -0
  158. {bumble-0.0.179 → bumble-0.0.180}/docs/images/logo_framed.vectornator/Document.json +0 -0
  159. {bumble-0.0.179 → bumble-0.0.180}/docs/images/logo_framed.vectornator/Manifest.json +0 -0
  160. {bumble-0.0.179 → bumble-0.0.180}/docs/images/logo_framed.vectornator/Thumbnail.png +0 -0
  161. {bumble-0.0.179 → bumble-0.0.180}/docs/images/logo_framed.vectornator/UndoHistory.json +0 -0
  162. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/mkdocs.yml +0 -0
  163. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/requirements.txt +0 -0
  164. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/api/examples.md +0 -0
  165. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/api/guide.md +0 -0
  166. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/api/reference.md +0 -0
  167. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/apps_and_tools/bench.md +0 -0
  168. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/apps_and_tools/console.md +0 -0
  169. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/apps_and_tools/gatt_dump.md +0 -0
  170. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/apps_and_tools/gg_bridge.md +0 -0
  171. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/apps_and_tools/hci_bridge.md +0 -0
  172. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/apps_and_tools/index.md +0 -0
  173. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/apps_and_tools/link_relay.md +0 -0
  174. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/apps_and_tools/pair.md +0 -0
  175. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/apps_and_tools/show.md +0 -0
  176. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/apps_and_tools/speaker.md +0 -0
  177. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/apps_and_tools/unbond.md +0 -0
  178. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/apps_and_tools/usb_probe.md +0 -0
  179. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/components/controller.md +0 -0
  180. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/components/gatt.md +0 -0
  181. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/components/host.md +0 -0
  182. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/components/security_manager.md +0 -0
  183. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/development/code_style.md +0 -0
  184. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/development/contributing.md +0 -0
  185. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/development/python_environments.md +0 -0
  186. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/downloads/zephyr/hci_usb.zip +0 -0
  187. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/drivers/index.md +0 -0
  188. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/drivers/realtek.md +0 -0
  189. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/examples/index.md +0 -0
  190. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/extras/android_bt_bench.md +0 -0
  191. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/extras/android_remote_hci.md +0 -0
  192. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/extras/index.md +0 -0
  193. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/getting_started.md +0 -0
  194. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/hardware/index.md +0 -0
  195. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/hive/index.md +0 -0
  196. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/hive/index.toml +0 -0
  197. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/hive/web/bumble.js +0 -0
  198. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/hive/web/heart_rate_monitor/heart_rate_monitor.html +0 -0
  199. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/hive/web/heart_rate_monitor/heart_rate_monitor.js +0 -0
  200. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/hive/web/heart_rate_monitor/heart_rate_monitor.py +0 -0
  201. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/hive/web/scanner/scanner.css +0 -0
  202. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/hive/web/scanner/scanner.html +0 -0
  203. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/hive/web/scanner/scanner.js +0 -0
  204. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/hive/web/scanner/scanner.py +0 -0
  205. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/hive/web/speaker/logo.svg +0 -0
  206. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/hive/web/speaker/speaker.css +0 -0
  207. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/hive/web/speaker/speaker.html +0 -0
  208. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/hive/web/speaker/speaker.js +0 -0
  209. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/hive/web/speaker/speaker.py +0 -0
  210. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/hive/web/ui.js +0 -0
  211. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/images/bumble_layers.svg +0 -0
  212. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/images/console_screenshot.png +0 -0
  213. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/images/favicon.ico +0 -0
  214. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/images/logo.png +0 -0
  215. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/images/logo_framed.png +0 -0
  216. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/images/speaker_screenshot.png +0 -0
  217. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/index.md +0 -0
  218. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/platforms/android.md +0 -0
  219. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/platforms/index.md +0 -0
  220. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/platforms/linux.md +0 -0
  221. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/platforms/macos.md +0 -0
  222. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/platforms/windows.md +0 -0
  223. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/platforms/winusb_driver.png +0 -0
  224. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/platforms/zephyr.md +0 -0
  225. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/transports/android_emulator.md +0 -0
  226. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/transports/file.md +0 -0
  227. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/transports/hci_socket.md +0 -0
  228. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/transports/index.md +0 -0
  229. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/transports/pty.md +0 -0
  230. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/transports/serial.md +0 -0
  231. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/transports/tcp_client.md +0 -0
  232. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/transports/tcp_server.md +0 -0
  233. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/transports/udp.md +0 -0
  234. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/transports/usb.md +0 -0
  235. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/transports/vhci.md +0 -0
  236. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/transports/ws_client.md +0 -0
  237. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/transports/ws_server.md +0 -0
  238. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/use_cases/index.md +0 -0
  239. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/use_cases/use_case_1.md +0 -0
  240. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/use_cases/use_case_2.md +0 -0
  241. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/use_cases/use_case_3.md +0 -0
  242. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/use_cases/use_case_4.md +0 -0
  243. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/use_cases/use_case_5.md +0 -0
  244. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/src/use_cases/use_case_6.md +0 -0
  245. {bumble-0.0.179 → bumble-0.0.180}/docs/mkdocs/theme/partials/footer.html +0 -0
  246. {bumble-0.0.179 → bumble-0.0.180}/environment.yml +0 -0
  247. {bumble-0.0.179 → bumble-0.0.180}/examples/README.md +0 -0
  248. {bumble-0.0.179 → bumble-0.0.180}/examples/a2dp_sink1.json +0 -0
  249. {bumble-0.0.179 → bumble-0.0.180}/examples/asha_sink1.json +0 -0
  250. {bumble-0.0.179 → bumble-0.0.180}/examples/asha_sink2.json +0 -0
  251. {bumble-0.0.179 → bumble-0.0.180}/examples/async_runner.py +0 -0
  252. {bumble-0.0.179 → bumble-0.0.180}/examples/battery_client.py +0 -0
  253. {bumble-0.0.179 → bumble-0.0.180}/examples/battery_server.py +0 -0
  254. {bumble-0.0.179 → bumble-0.0.180}/examples/classic1.json +0 -0
  255. {bumble-0.0.179 → bumble-0.0.180}/examples/classic2.json +0 -0
  256. {bumble-0.0.179 → bumble-0.0.180}/examples/device1.json +0 -0
  257. {bumble-0.0.179 → bumble-0.0.180}/examples/device2.json +0 -0
  258. {bumble-0.0.179 → bumble-0.0.180}/examples/device3.json +0 -0
  259. {bumble-0.0.179 → bumble-0.0.180}/examples/device_information_client.py +0 -0
  260. {bumble-0.0.179 → bumble-0.0.180}/examples/device_information_server.py +0 -0
  261. {bumble-0.0.179 → bumble-0.0.180}/examples/heart_rate_client.py +0 -0
  262. {bumble-0.0.179 → bumble-0.0.180}/examples/heart_rate_server.py +0 -0
  263. {bumble-0.0.179 → bumble-0.0.180}/examples/hfp_gateway.json +0 -0
  264. {bumble-0.0.179 → bumble-0.0.180}/examples/hfp_handsfree.html +0 -0
  265. {bumble-0.0.179 → bumble-0.0.180}/examples/hfp_handsfree.json +0 -0
  266. {bumble-0.0.179 → bumble-0.0.180}/examples/hid_key_map.py +0 -0
  267. {bumble-0.0.179 → bumble-0.0.180}/examples/hid_report_parser.py +0 -0
  268. {bumble-0.0.179 → bumble-0.0.180}/examples/keyboard.html +0 -0
  269. {bumble-0.0.179 → bumble-0.0.180}/examples/keyboard.json +0 -0
  270. {bumble-0.0.179 → bumble-0.0.180}/examples/keyboard.py +0 -0
  271. {bumble-0.0.179 → bumble-0.0.180}/examples/run_a2dp_info.py +0 -0
  272. {bumble-0.0.179 → bumble-0.0.180}/examples/run_a2dp_sink.py +0 -0
  273. {bumble-0.0.179 → bumble-0.0.180}/examples/run_a2dp_source.py +0 -0
  274. {bumble-0.0.179 → bumble-0.0.180}/examples/run_advertiser.py +0 -0
  275. {bumble-0.0.179 → bumble-0.0.180}/examples/run_asha_sink.py +0 -0
  276. {bumble-0.0.179 → bumble-0.0.180}/examples/run_classic_connect.py +0 -0
  277. {bumble-0.0.179 → bumble-0.0.180}/examples/run_classic_discoverable.py +0 -0
  278. {bumble-0.0.179 → bumble-0.0.180}/examples/run_classic_discovery.py +0 -0
  279. {bumble-0.0.179 → bumble-0.0.180}/examples/run_connect_and_encrypt.py +0 -0
  280. {bumble-0.0.179 → bumble-0.0.180}/examples/run_controller.py +0 -0
  281. {bumble-0.0.179 → bumble-0.0.180}/examples/run_controller_with_scanner.py +0 -0
  282. {bumble-0.0.179 → bumble-0.0.180}/examples/run_device_with_snooper.py +0 -0
  283. {bumble-0.0.179 → bumble-0.0.180}/examples/run_extended_advertiser.py +0 -0
  284. {bumble-0.0.179 → bumble-0.0.180}/examples/run_gatt_client.py +0 -0
  285. {bumble-0.0.179 → bumble-0.0.180}/examples/run_gatt_client_and_server.py +0 -0
  286. {bumble-0.0.179 → bumble-0.0.180}/examples/run_gatt_server.py +0 -0
  287. {bumble-0.0.179 → bumble-0.0.180}/examples/run_hfp_gateway.py +0 -0
  288. {bumble-0.0.179 → bumble-0.0.180}/examples/run_hfp_handsfree.py +0 -0
  289. {bumble-0.0.179 → bumble-0.0.180}/examples/run_hid_host.py +0 -0
  290. {bumble-0.0.179 → bumble-0.0.180}/examples/run_notifier.py +0 -0
  291. {bumble-0.0.179 → bumble-0.0.180}/examples/run_rfcomm_client.py +0 -0
  292. {bumble-0.0.179 → bumble-0.0.180}/examples/run_rfcomm_server.py +0 -0
  293. {bumble-0.0.179 → bumble-0.0.180}/examples/run_scanner.py +0 -0
  294. {bumble-0.0.179 → bumble-0.0.180}/examples/speaker.json +0 -0
  295. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/.gitignore +0 -0
  296. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/.gitignore +0 -0
  297. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/build.gradle.kts +0 -0
  298. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/proguard-rules.pro +0 -0
  299. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/AndroidManifest.xml +0 -0
  300. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/ic_launcher-playstore.png +0 -0
  301. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/java/com/github/google/bumble/btbench/L2capClient.kt +0 -0
  302. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/java/com/github/google/bumble/btbench/L2capServer.kt +0 -0
  303. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/java/com/github/google/bumble/btbench/MainActivity.kt +0 -0
  304. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/java/com/github/google/bumble/btbench/Model.kt +0 -0
  305. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/java/com/github/google/bumble/btbench/Packet.kt +0 -0
  306. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/java/com/github/google/bumble/btbench/Receiver.kt +0 -0
  307. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/java/com/github/google/bumble/btbench/RfcommClient.kt +0 -0
  308. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/java/com/github/google/bumble/btbench/RfcommServer.kt +0 -0
  309. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/java/com/github/google/bumble/btbench/Sender.kt +0 -0
  310. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/java/com/github/google/bumble/btbench/SocketClient.kt +0 -0
  311. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/java/com/github/google/bumble/btbench/SocketServer.kt +0 -0
  312. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/java/com/github/google/bumble/btbench/ui/theme/Color.kt +0 -0
  313. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/java/com/github/google/bumble/btbench/ui/theme/Theme.kt +0 -0
  314. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/java/com/github/google/bumble/btbench/ui/theme/Type.kt +0 -0
  315. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/res/drawable/ic_launcher_background.xml +0 -0
  316. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/res/drawable/ic_launcher_foreground.xml +0 -0
  317. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +0 -0
  318. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +0 -0
  319. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp +0 -0
  320. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp +0 -0
  321. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp +0 -0
  322. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp +0 -0
  323. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp +0 -0
  324. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp +0 -0
  325. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp +0 -0
  326. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp +0 -0
  327. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp +0 -0
  328. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp +0 -0
  329. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/res/values/colors.xml +0 -0
  330. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/res/values/ic_launcher_background.xml +0 -0
  331. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/res/values/strings.xml +0 -0
  332. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/res/values/themes.xml +0 -0
  333. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/res/xml/backup_rules.xml +0 -0
  334. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/app/src/main/res/xml/data_extraction_rules.xml +0 -0
  335. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/build.gradle.kts +0 -0
  336. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/gradle/libs.versions.toml +0 -0
  337. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/gradle/wrapper/gradle-wrapper.jar +0 -0
  338. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/gradle/wrapper/gradle-wrapper.properties +0 -0
  339. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/gradle.properties +0 -0
  340. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/gradlew +0 -0
  341. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/gradlew.bat +0 -0
  342. {bumble-0.0.179 → bumble-0.0.180}/extras/android/BtBench/settings.gradle.kts +0 -0
  343. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/.gitignore +0 -0
  344. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/.gitignore +0 -0
  345. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/build.gradle.kts +0 -0
  346. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/proguard-rules.pro +0 -0
  347. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/AndroidManifest.xml +0 -0
  348. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/aidl/android/hardware/bluetooth/IBluetoothHci.aidl +0 -0
  349. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/aidl/android/hardware/bluetooth/IBluetoothHciCallbacks.aidl +0 -0
  350. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/aidl/android/hardware/bluetooth/Status.aidl +0 -0
  351. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/hidl/bluetooth/1.1/IBluetoothHci.hal +0 -0
  352. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/hidl/bluetooth/1.1/IBluetoothHciCallbacks.hal +0 -0
  353. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/ic_launcher-playstore.png +0 -0
  354. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/java/android/hardware/bluetooth/IBluetoothHci.java +0 -0
  355. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/java/android/hardware/bluetooth/IBluetoothHciCallbacks.java +0 -0
  356. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/java/android/hardware/bluetooth/Status.java +0 -0
  357. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/java/android/hardware/bluetooth/V1_0/IBluetoothHci.java +0 -0
  358. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/java/android/hardware/bluetooth/V1_0/IBluetoothHciCallbacks.java +0 -0
  359. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/java/android/hardware/bluetooth/V1_0/Status.java +0 -0
  360. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/java/android/hardware/bluetooth/V1_1/IBluetoothHci.java +0 -0
  361. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/java/android/hardware/bluetooth/V1_1/IBluetoothHciCallbacks.java +0 -0
  362. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/HciHal.java +0 -0
  363. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/HciHalCallback.java +0 -0
  364. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/HciPacket.java +0 -0
  365. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/HciParser.java +0 -0
  366. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/HciProxy.java +0 -0
  367. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/HciServer.java +0 -0
  368. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/MainActivity.kt +0 -0
  369. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/ui/theme/Color.kt +0 -0
  370. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/ui/theme/Theme.kt +0 -0
  371. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/ui/theme/Type.kt +0 -0
  372. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +0 -0
  373. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +0 -0
  374. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/res/mipmap-hdpi/ic_launcher.webp +0 -0
  375. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp +0 -0
  376. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp +0 -0
  377. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/res/mipmap-mdpi/ic_launcher.webp +0 -0
  378. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp +0 -0
  379. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp +0 -0
  380. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/res/mipmap-xhdpi/ic_launcher.webp +0 -0
  381. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp +0 -0
  382. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp +0 -0
  383. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp +0 -0
  384. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp +0 -0
  385. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp +0 -0
  386. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp +0 -0
  387. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp +0 -0
  388. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp +0 -0
  389. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/res/values/colors.xml +0 -0
  390. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/res/values/ic_launcher_background.xml +0 -0
  391. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/res/values/strings.xml +0 -0
  392. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/res/values/themes.xml +0 -0
  393. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/res/xml/backup_rules.xml +0 -0
  394. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/app/src/main/res/xml/data_extraction_rules.xml +0 -0
  395. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/build.gradle.kts +0 -0
  396. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/gradle/libs.versions.toml +0 -0
  397. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/gradle/wrapper/gradle-wrapper.jar +0 -0
  398. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/gradle/wrapper/gradle-wrapper.properties +0 -0
  399. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/gradle.properties +0 -0
  400. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/gradlew +0 -0
  401. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/gradlew.bat +0 -0
  402. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/lib/.gitignore +0 -0
  403. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/lib/build.gradle.kts +0 -0
  404. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/lib/consumer-rules.pro +0 -0
  405. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/lib/proguard-rules.pro +0 -0
  406. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/lib/src/main/AndroidManifest.xml +0 -0
  407. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/lib/src/main/java/android/internal/hidl/base/V1_0/DebugInfo.java +0 -0
  408. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/lib/src/main/java/android/internal/hidl/base/V1_0/IBase.java +0 -0
  409. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/lib/src/main/java/android/os/HidlSupport.java +0 -0
  410. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/lib/src/main/java/android/os/HwBinder.java +0 -0
  411. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/lib/src/main/java/android/os/HwBlob.java +0 -0
  412. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/lib/src/main/java/android/os/HwParcel.java +0 -0
  413. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/lib/src/main/java/android/os/IHwBinder.java +0 -0
  414. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/lib/src/main/java/android/os/IHwInterface.java +0 -0
  415. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/lib/src/main/java/android/os/NativeHandle.java +0 -0
  416. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/lib/src/main/java/android/os/ServiceManager.java +0 -0
  417. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/scripts/generate_java_from_aidl.sh +0 -0
  418. {bumble-0.0.179 → bumble-0.0.180}/extras/android/RemoteHCI/settings.gradle.kts +0 -0
  419. {bumble-0.0.179 → bumble-0.0.180}/noxfile.py +0 -0
  420. {bumble-0.0.179 → bumble-0.0.180}/pyproject.toml +0 -0
  421. {bumble-0.0.179 → bumble-0.0.180}/rust/.gitignore +0 -0
  422. {bumble-0.0.179 → bumble-0.0.180}/rust/CHANGELOG.md +0 -0
  423. {bumble-0.0.179 → bumble-0.0.180}/rust/Cargo.lock +0 -0
  424. {bumble-0.0.179 → bumble-0.0.180}/rust/Cargo.toml +0 -0
  425. {bumble-0.0.179 → bumble-0.0.180}/rust/README.md +0 -0
  426. {bumble-0.0.179 → bumble-0.0.180}/rust/examples/battery_client.rs +0 -0
  427. {bumble-0.0.179 → bumble-0.0.180}/rust/examples/broadcast.rs +0 -0
  428. {bumble-0.0.179 → bumble-0.0.180}/rust/examples/scanner.rs +0 -0
  429. {bumble-0.0.179 → bumble-0.0.180}/rust/pytests/assigned_numbers.rs +0 -0
  430. {bumble-0.0.179 → bumble-0.0.180}/rust/pytests/pytests.rs +0 -0
  431. {bumble-0.0.179 → bumble-0.0.180}/rust/pytests/wrapper/drivers.rs +0 -0
  432. {bumble-0.0.179 → bumble-0.0.180}/rust/pytests/wrapper/hci.rs +0 -0
  433. {bumble-0.0.179 → bumble-0.0.180}/rust/pytests/wrapper/mod.rs +0 -0
  434. {bumble-0.0.179 → bumble-0.0.180}/rust/pytests/wrapper/transport.rs +0 -0
  435. {bumble-0.0.179 → bumble-0.0.180}/rust/resources/test/firmware/realtek/README.md +0 -0
  436. {bumble-0.0.179 → bumble-0.0.180}/rust/resources/test/firmware/realtek/rtl8723b_fw_structure.bin +0 -0
  437. {bumble-0.0.179 → bumble-0.0.180}/rust/resources/test/firmware/realtek/rtl8761bu_fw_structure.bin +0 -0
  438. {bumble-0.0.179 → bumble-0.0.180}/rust/src/adv.rs +0 -0
  439. {bumble-0.0.179 → bumble-0.0.180}/rust/src/cli/firmware/mod.rs +0 -0
  440. {bumble-0.0.179 → bumble-0.0.180}/rust/src/cli/firmware/rtk.rs +0 -0
  441. {bumble-0.0.179 → bumble-0.0.180}/rust/src/cli/l2cap/client_bridge.rs +0 -0
  442. {bumble-0.0.179 → bumble-0.0.180}/rust/src/cli/l2cap/mod.rs +0 -0
  443. {bumble-0.0.179 → bumble-0.0.180}/rust/src/cli/l2cap/server_bridge.rs +0 -0
  444. {bumble-0.0.179 → bumble-0.0.180}/rust/src/cli/mod.rs +0 -0
  445. {bumble-0.0.179 → bumble-0.0.180}/rust/src/cli/usb/mod.rs +0 -0
  446. {bumble-0.0.179 → bumble-0.0.180}/rust/src/internal/drivers/mod.rs +0 -0
  447. {bumble-0.0.179 → bumble-0.0.180}/rust/src/internal/drivers/rtk.rs +0 -0
  448. {bumble-0.0.179 → bumble-0.0.180}/rust/src/internal/hci/mod.rs +0 -0
  449. {bumble-0.0.179 → bumble-0.0.180}/rust/src/internal/hci/packets.pdl +0 -0
  450. {bumble-0.0.179 → bumble-0.0.180}/rust/src/internal/hci/tests.rs +0 -0
  451. {bumble-0.0.179 → bumble-0.0.180}/rust/src/internal/mod.rs +0 -0
  452. {bumble-0.0.179 → bumble-0.0.180}/rust/src/lib.rs +0 -0
  453. {bumble-0.0.179 → bumble-0.0.180}/rust/src/main.rs +0 -0
  454. {bumble-0.0.179 → bumble-0.0.180}/rust/src/wrapper/assigned_numbers/company_ids.rs +0 -0
  455. {bumble-0.0.179 → bumble-0.0.180}/rust/src/wrapper/assigned_numbers/mod.rs +0 -0
  456. {bumble-0.0.179 → bumble-0.0.180}/rust/src/wrapper/assigned_numbers/services.rs +0 -0
  457. {bumble-0.0.179 → bumble-0.0.180}/rust/src/wrapper/common.rs +0 -0
  458. {bumble-0.0.179 → bumble-0.0.180}/rust/src/wrapper/controller.rs +0 -0
  459. {bumble-0.0.179 → bumble-0.0.180}/rust/src/wrapper/core.rs +0 -0
  460. {bumble-0.0.179 → bumble-0.0.180}/rust/src/wrapper/device/mod.rs +0 -0
  461. {bumble-0.0.179 → bumble-0.0.180}/rust/src/wrapper/device/tests.rs +0 -0
  462. {bumble-0.0.179 → bumble-0.0.180}/rust/src/wrapper/drivers/mod.rs +0 -0
  463. {bumble-0.0.179 → bumble-0.0.180}/rust/src/wrapper/drivers/rtk.rs +0 -0
  464. {bumble-0.0.179 → bumble-0.0.180}/rust/src/wrapper/gatt_client.rs +0 -0
  465. {bumble-0.0.179 → bumble-0.0.180}/rust/src/wrapper/hci.rs +0 -0
  466. {bumble-0.0.179 → bumble-0.0.180}/rust/src/wrapper/host.rs +0 -0
  467. {bumble-0.0.179 → bumble-0.0.180}/rust/src/wrapper/l2cap.rs +0 -0
  468. {bumble-0.0.179 → bumble-0.0.180}/rust/src/wrapper/link.rs +0 -0
  469. {bumble-0.0.179 → bumble-0.0.180}/rust/src/wrapper/logging.rs +0 -0
  470. {bumble-0.0.179 → bumble-0.0.180}/rust/src/wrapper/mod.rs +0 -0
  471. {bumble-0.0.179 → bumble-0.0.180}/rust/src/wrapper/profile.rs +0 -0
  472. {bumble-0.0.179 → bumble-0.0.180}/rust/src/wrapper/transport.rs +0 -0
  473. {bumble-0.0.179 → bumble-0.0.180}/rust/tools/file_header.rs +0 -0
  474. {bumble-0.0.179 → bumble-0.0.180}/rust/tools/gen_assigned_numbers.rs +0 -0
  475. {bumble-0.0.179 → bumble-0.0.180}/scripts/process_android_emulator_protos.sh +0 -0
  476. {bumble-0.0.179 → bumble-0.0.180}/scripts/process_android_netsim_protos.sh +0 -0
  477. {bumble-0.0.179 → bumble-0.0.180}/setup.cfg +0 -0
  478. {bumble-0.0.179 → bumble-0.0.180}/setup.py +0 -0
  479. {bumble-0.0.179 → bumble-0.0.180}/tasks.py +0 -0
  480. {bumble-0.0.179 → bumble-0.0.180}/tests/__init__.py +0 -0
  481. {bumble-0.0.179 → bumble-0.0.180}/tests/a2dp_test.py +0 -0
  482. {bumble-0.0.179 → bumble-0.0.180}/tests/at_test.py +0 -0
  483. {bumble-0.0.179 → bumble-0.0.180}/tests/avdtp_test.py +0 -0
  484. {bumble-0.0.179 → bumble-0.0.180}/tests/codecs_test.py +0 -0
  485. {bumble-0.0.179 → bumble-0.0.180}/tests/core_test.py +0 -0
  486. {bumble-0.0.179 → bumble-0.0.180}/tests/decoder_test.py +0 -0
  487. {bumble-0.0.179 → bumble-0.0.180}/tests/device_test.py +0 -0
  488. {bumble-0.0.179 → bumble-0.0.180}/tests/g722_sample.g722 +0 -0
  489. {bumble-0.0.179 → bumble-0.0.180}/tests/hci_data_001.bin +0 -0
  490. {bumble-0.0.179 → bumble-0.0.180}/tests/hci_test.py +0 -0
  491. {bumble-0.0.179 → bumble-0.0.180}/tests/hfp_test.py +0 -0
  492. {bumble-0.0.179 → bumble-0.0.180}/tests/import_test.py +0 -0
  493. {bumble-0.0.179 → bumble-0.0.180}/tests/keystore_test.py +0 -0
  494. {bumble-0.0.179 → bumble-0.0.180}/tests/l2cap_test.py +0 -0
  495. {bumble-0.0.179 → bumble-0.0.180}/tests/pytest.ini +0 -0
  496. {bumble-0.0.179 → bumble-0.0.180}/tests/rfcomm_test.py +0 -0
  497. {bumble-0.0.179 → bumble-0.0.180}/tests/sdp_test.py +0 -0
  498. {bumble-0.0.179 → bumble-0.0.180}/tests/self_test.py +0 -0
  499. {bumble-0.0.179 → bumble-0.0.180}/tests/smp_test.py +0 -0
  500. {bumble-0.0.179 → bumble-0.0.180}/tests/transport_test.py +0 -0
  501. {bumble-0.0.179 → bumble-0.0.180}/tests/utils_test.py +0 -0
  502. {bumble-0.0.179 → bumble-0.0.180}/tools/__init__.py +0 -0
  503. {bumble-0.0.179 → bumble-0.0.180}/tools/generate_company_id_list.py +0 -0
  504. {bumble-0.0.179 → bumble-0.0.180}/tools/rtk_fw_download.py +0 -0
  505. {bumble-0.0.179 → bumble-0.0.180}/tools/rtk_util.py +0 -0
  506. {bumble-0.0.179 → bumble-0.0.180}/web/README.md +0 -0
  507. {bumble-0.0.179 → bumble-0.0.180}/web/bumble.js +0 -0
  508. {bumble-0.0.179 → bumble-0.0.180}/web/heart_rate_monitor/heart_rate_monitor.html +0 -0
  509. {bumble-0.0.179 → bumble-0.0.180}/web/heart_rate_monitor/heart_rate_monitor.js +0 -0
  510. {bumble-0.0.179 → bumble-0.0.180}/web/heart_rate_monitor/heart_rate_monitor.py +0 -0
  511. {bumble-0.0.179 → bumble-0.0.180}/web/scanner/scanner.css +0 -0
  512. {bumble-0.0.179 → bumble-0.0.180}/web/scanner/scanner.html +0 -0
  513. {bumble-0.0.179 → bumble-0.0.180}/web/scanner/scanner.js +0 -0
  514. {bumble-0.0.179 → bumble-0.0.180}/web/scanner/scanner.py +0 -0
  515. {bumble-0.0.179 → bumble-0.0.180}/web/speaker/logo.svg +0 -0
  516. {bumble-0.0.179 → bumble-0.0.180}/web/speaker/speaker.css +0 -0
  517. {bumble-0.0.179 → bumble-0.0.180}/web/speaker/speaker.html +0 -0
  518. {bumble-0.0.179 → bumble-0.0.180}/web/speaker/speaker.js +0 -0
  519. {bumble-0.0.179 → bumble-0.0.180}/web/speaker/speaker.py +0 -0
  520. {bumble-0.0.179 → bumble-0.0.180}/web/ui.js +0 -0
@@ -21,6 +21,7 @@
21
21
  "cccds",
22
22
  "cmac",
23
23
  "CONNECTIONLESS",
24
+ "csip",
24
25
  "csrcs",
25
26
  "datagram",
26
27
  "DATALINK",
@@ -45,6 +46,7 @@
45
46
  "NONCONN",
46
47
  "OXIMETER",
47
48
  "popleft",
49
+ "PRAND",
48
50
  "protobuf",
49
51
  "psms",
50
52
  "pyee",
@@ -56,6 +58,7 @@
56
58
  "SEID",
57
59
  "seids",
58
60
  "SERV",
61
+ "SIRK",
59
62
  "ssrc",
60
63
  "strerror",
61
64
  "subband",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bumble
3
- Version: 0.0.179
3
+ Version: 0.0.180
4
4
  Summary: Bluetooth Stack for Apps, Emulation, Test and Experimentation
5
5
  Home-page: https://github.com/google/bumble
6
6
  Author: Google
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.0.179'
16
- __version_tuple__ = version_tuple = (0, 0, 179)
15
+ __version__ = version = '0.0.180'
16
+ __version_tuple__ = version_tuple = (0, 0, 180)
@@ -23,6 +23,7 @@ import asyncio
23
23
  import logging
24
24
  from contextlib import asynccontextmanager, AsyncExitStack
25
25
  from dataclasses import dataclass
26
+ from collections.abc import Iterable
26
27
  from typing import (
27
28
  Any,
28
29
  Callable,
@@ -32,6 +33,7 @@ from typing import (
32
33
  Optional,
33
34
  Tuple,
34
35
  Type,
36
+ TypeVar,
35
37
  Set,
36
38
  Union,
37
39
  cast,
@@ -440,8 +442,11 @@ class LePhyOptions:
440
442
 
441
443
 
442
444
  # -----------------------------------------------------------------------------
445
+ _PROXY_CLASS = TypeVar('_PROXY_CLASS', bound=gatt_client.ProfileServiceProxy)
446
+
447
+
443
448
  class Peer:
444
- def __init__(self, connection):
449
+ def __init__(self, connection: Connection) -> None:
445
450
  self.connection = connection
446
451
 
447
452
  # Create a GATT client for the connection
@@ -449,77 +454,113 @@ class Peer:
449
454
  connection.gatt_client = self.gatt_client
450
455
 
451
456
  @property
452
- def services(self):
457
+ def services(self) -> List[gatt_client.ServiceProxy]:
453
458
  return self.gatt_client.services
454
459
 
455
- async def request_mtu(self, mtu):
460
+ async def request_mtu(self, mtu: int) -> int:
456
461
  mtu = await self.gatt_client.request_mtu(mtu)
457
462
  self.connection.emit('connection_att_mtu_update')
458
463
  return mtu
459
464
 
460
- async def discover_service(self, uuid):
465
+ async def discover_service(
466
+ self, uuid: Union[core.UUID, str]
467
+ ) -> List[gatt_client.ServiceProxy]:
461
468
  return await self.gatt_client.discover_service(uuid)
462
469
 
463
- async def discover_services(self, uuids=()):
470
+ async def discover_services(
471
+ self, uuids: Iterable[core.UUID] = ()
472
+ ) -> List[gatt_client.ServiceProxy]:
464
473
  return await self.gatt_client.discover_services(uuids)
465
474
 
466
- async def discover_included_services(self, service):
475
+ async def discover_included_services(
476
+ self, service: gatt_client.ServiceProxy
477
+ ) -> List[gatt_client.ServiceProxy]:
467
478
  return await self.gatt_client.discover_included_services(service)
468
479
 
469
- async def discover_characteristics(self, uuids=(), service=None):
480
+ async def discover_characteristics(
481
+ self,
482
+ uuids: Iterable[Union[core.UUID, str]] = (),
483
+ service: Optional[gatt_client.ServiceProxy] = None,
484
+ ) -> List[gatt_client.CharacteristicProxy]:
470
485
  return await self.gatt_client.discover_characteristics(
471
486
  uuids=uuids, service=service
472
487
  )
473
488
 
474
489
  async def discover_descriptors(
475
- self, characteristic=None, start_handle=None, end_handle=None
490
+ self,
491
+ characteristic: Optional[gatt_client.CharacteristicProxy] = None,
492
+ start_handle: Optional[int] = None,
493
+ end_handle: Optional[int] = None,
476
494
  ):
477
495
  return await self.gatt_client.discover_descriptors(
478
496
  characteristic, start_handle, end_handle
479
497
  )
480
498
 
481
- async def discover_attributes(self):
499
+ async def discover_attributes(self) -> List[gatt_client.AttributeProxy]:
482
500
  return await self.gatt_client.discover_attributes()
483
501
 
484
- async def subscribe(self, characteristic, subscriber=None, prefer_notify=True):
502
+ async def subscribe(
503
+ self,
504
+ characteristic: gatt_client.CharacteristicProxy,
505
+ subscriber: Optional[Callable[[bytes], Any]] = None,
506
+ prefer_notify: bool = True,
507
+ ) -> None:
485
508
  return await self.gatt_client.subscribe(
486
509
  characteristic, subscriber, prefer_notify
487
510
  )
488
511
 
489
- async def unsubscribe(self, characteristic, subscriber=None):
512
+ async def unsubscribe(
513
+ self,
514
+ characteristic: gatt_client.CharacteristicProxy,
515
+ subscriber: Optional[Callable[[bytes], Any]] = None,
516
+ ) -> None:
490
517
  return await self.gatt_client.unsubscribe(characteristic, subscriber)
491
518
 
492
- async def read_value(self, attribute):
519
+ async def read_value(
520
+ self, attribute: Union[int, gatt_client.AttributeProxy]
521
+ ) -> bytes:
493
522
  return await self.gatt_client.read_value(attribute)
494
523
 
495
- async def write_value(self, attribute, value, with_response=False):
524
+ async def write_value(
525
+ self,
526
+ attribute: Union[int, gatt_client.AttributeProxy],
527
+ value: bytes,
528
+ with_response: bool = False,
529
+ ) -> None:
496
530
  return await self.gatt_client.write_value(attribute, value, with_response)
497
531
 
498
- async def read_characteristics_by_uuid(self, uuid, service=None):
532
+ async def read_characteristics_by_uuid(
533
+ self, uuid: core.UUID, service: Optional[gatt_client.ServiceProxy] = None
534
+ ) -> List[bytes]:
499
535
  return await self.gatt_client.read_characteristics_by_uuid(uuid, service)
500
536
 
501
- def get_services_by_uuid(self, uuid):
537
+ def get_services_by_uuid(self, uuid: core.UUID) -> List[gatt_client.ServiceProxy]:
502
538
  return self.gatt_client.get_services_by_uuid(uuid)
503
539
 
504
- def get_characteristics_by_uuid(self, uuid, service=None):
540
+ def get_characteristics_by_uuid(
541
+ self, uuid: core.UUID, service: Optional[gatt_client.ServiceProxy] = None
542
+ ) -> List[gatt_client.CharacteristicProxy]:
505
543
  return self.gatt_client.get_characteristics_by_uuid(uuid, service)
506
544
 
507
- def create_service_proxy(self, proxy_class):
508
- return proxy_class.from_client(self.gatt_client)
545
+ def create_service_proxy(self, proxy_class: Type[_PROXY_CLASS]) -> _PROXY_CLASS:
546
+ return cast(_PROXY_CLASS, proxy_class.from_client(self.gatt_client))
509
547
 
510
- async def discover_service_and_create_proxy(self, proxy_class):
548
+ async def discover_service_and_create_proxy(
549
+ self, proxy_class: Type[_PROXY_CLASS]
550
+ ) -> Optional[_PROXY_CLASS]:
511
551
  # Discover the first matching service and its characteristics
512
552
  services = await self.discover_service(proxy_class.SERVICE_CLASS.UUID)
513
553
  if services:
514
554
  service = services[0]
515
555
  await service.discover_characteristics()
516
556
  return self.create_service_proxy(proxy_class)
557
+ return None
517
558
 
518
- async def sustain(self, timeout=None):
559
+ async def sustain(self, timeout: Optional[float] = None) -> None:
519
560
  await self.connection.sustain(timeout)
520
561
 
521
562
  # [Classic only]
522
- async def request_name(self):
563
+ async def request_name(self) -> str:
523
564
  return await self.connection.request_remote_name()
524
565
 
525
566
  async def __aenter__(self):
@@ -532,7 +573,7 @@ class Peer:
532
573
  async def __aexit__(self, exc_type, exc_value, traceback):
533
574
  pass
534
575
 
535
- def __str__(self):
576
+ def __str__(self) -> str:
536
577
  return f'{self.connection.peer_address} as {self.connection.role_name}'
537
578
 
538
579
 
@@ -732,7 +773,7 @@ class Connection(CompositeEventEmitter):
732
773
  async def switch_role(self, role: int) -> None:
733
774
  return await self.device.switch_role(self, role)
734
775
 
735
- async def sustain(self, timeout=None):
776
+ async def sustain(self, timeout: Optional[float] = None) -> None:
736
777
  """Idles the current task waiting for a disconnect or timeout"""
737
778
 
738
779
  abort = asyncio.get_running_loop().create_future()
@@ -93,20 +93,35 @@ GATT_RECONNECTION_CONFIGURATION_SERVICE = UUID.from_16_bits(0x1829, 'Reconne
93
93
  GATT_INSULIN_DELIVERY_SERVICE = UUID.from_16_bits(0x183A, 'Insulin Delivery')
94
94
  GATT_BINARY_SENSOR_SERVICE = UUID.from_16_bits(0x183B, 'Binary Sensor')
95
95
  GATT_EMERGENCY_CONFIGURATION_SERVICE = UUID.from_16_bits(0x183C, 'Emergency Configuration')
96
+ GATT_AUTHORIZATION_CONTROL_SERVICE = UUID.from_16_bits(0x183D, 'Authorization Control')
96
97
  GATT_PHYSICAL_ACTIVITY_MONITOR_SERVICE = UUID.from_16_bits(0x183E, 'Physical Activity Monitor')
98
+ GATT_ELAPSED_TIME_SERVICE = UUID.from_16_bits(0x183F, 'Elapsed Time')
99
+ GATT_GENERIC_HEALTH_SENSOR_SERVICE = UUID.from_16_bits(0x1840, 'Generic Health Sensor')
97
100
  GATT_AUDIO_INPUT_CONTROL_SERVICE = UUID.from_16_bits(0x1843, 'Audio Input Control')
98
101
  GATT_VOLUME_CONTROL_SERVICE = UUID.from_16_bits(0x1844, 'Volume Control')
99
102
  GATT_VOLUME_OFFSET_CONTROL_SERVICE = UUID.from_16_bits(0x1845, 'Volume Offset Control')
100
- GATT_COORDINATED_SET_IDENTIFICATION_SERVICE = UUID.from_16_bits(0x1846, 'Coordinated Set Identification Service')
103
+ GATT_COORDINATED_SET_IDENTIFICATION_SERVICE = UUID.from_16_bits(0x1846, 'Coordinated Set Identification')
101
104
  GATT_DEVICE_TIME_SERVICE = UUID.from_16_bits(0x1847, 'Device Time')
102
- GATT_MEDIA_CONTROL_SERVICE = UUID.from_16_bits(0x1848, 'Media Control Service')
103
- GATT_GENERIC_MEDIA_CONTROL_SERVICE = UUID.from_16_bits(0x1849, 'Generic Media Control Service')
105
+ GATT_MEDIA_CONTROL_SERVICE = UUID.from_16_bits(0x1848, 'Media Control')
106
+ GATT_GENERIC_MEDIA_CONTROL_SERVICE = UUID.from_16_bits(0x1849, 'Generic Media Control')
104
107
  GATT_CONSTANT_TONE_EXTENSION_SERVICE = UUID.from_16_bits(0x184A, 'Constant Tone Extension')
105
- GATT_TELEPHONE_BEARER_SERVICE = UUID.from_16_bits(0x184B, 'Telephone Bearer Service')
106
- GATT_GENERIC_TELEPHONE_BEARER_SERVICE = UUID.from_16_bits(0x184C, 'Generic Telephone Bearer Service')
108
+ GATT_TELEPHONE_BEARER_SERVICE = UUID.from_16_bits(0x184B, 'Telephone Bearer')
109
+ GATT_GENERIC_TELEPHONE_BEARER_SERVICE = UUID.from_16_bits(0x184C, 'Generic Telephone Bearer')
107
110
  GATT_MICROPHONE_CONTROL_SERVICE = UUID.from_16_bits(0x184D, 'Microphone Control')
108
-
109
- # Types
111
+ GATT_AUDIO_STREAM_CONTROL_SERVICE = UUID.from_16_bits(0x184E, 'Audio Stream Control')
112
+ GATT_BROADCAST_AUDIO_SCAN_SERVICE = UUID.from_16_bits(0x184F, 'Broadcast Audio Scan')
113
+ GATT_PUBLISHED_AUDIO_CAPABILITIES_SERVICE = UUID.from_16_bits(0x1850, 'Published Audio Capabilities')
114
+ GATT_BASIC_AUDIO_ANNOUNCEMENT_SERVICE = UUID.from_16_bits(0x1851, 'Basic Audio Announcement')
115
+ GATT_BROADCAST_AUDIO_ANNOUNCEMENT_SERVICE = UUID.from_16_bits(0x1852, 'Broadcast Audio Announcement')
116
+ GATT_COMMON_AUDIO_SERVICE = UUID.from_16_bits(0x1853, 'Common Audio')
117
+ GATT_HEARING_ACCESS_SERVICE = UUID.from_16_bits(0x1854, 'Hearing Access')
118
+ GATT_TELEPHONY_AND_MEDIA_AUDIO_SERVICE = UUID.from_16_bits(0x1855, 'Telephony and Media Audio')
119
+ GATT_PUBLIC_BROADCAST_ANNOUNCEMENT_SERVICE = UUID.from_16_bits(0x1856, 'Public Broadcast Announcement')
120
+ GATT_ELECTRONIC_SHELF_LABEL_SERVICE = UUID.from_16_bits(0X1857, 'Electronic Shelf Label')
121
+ GATT_GAMING_AUDIO_SERVICE = UUID.from_16_bits(0x1858, 'Gaming Audio')
122
+ GATT_MESH_PROXY_SOLICITATION_SERVICE = UUID.from_16_bits(0x1859, 'Mesh Audio Solicitation')
123
+
124
+ # Attribute Types
110
125
  GATT_PRIMARY_SERVICE_ATTRIBUTE_TYPE = UUID.from_16_bits(0x2800, 'Primary Service')
111
126
  GATT_SECONDARY_SERVICE_ATTRIBUTE_TYPE = UUID.from_16_bits(0x2801, 'Secondary Service')
112
127
  GATT_INCLUDE_ATTRIBUTE_TYPE = UUID.from_16_bits(0x2802, 'Include')
@@ -129,6 +144,8 @@ GATT_ENVIRONMENTAL_SENSING_MEASUREMENT_DESCRIPTOR = UUID.from_16_bits(0x290C,
129
144
  GATT_ENVIRONMENTAL_SENSING_TRIGGER_DESCRIPTOR = UUID.from_16_bits(0x290D, 'Environmental Sensing Trigger Setting')
130
145
  GATT_TIME_TRIGGER_DESCRIPTOR = UUID.from_16_bits(0x290E, 'Time Trigger Setting')
131
146
  GATT_COMPLETE_BR_EDR_TRANSPORT_BLOCK_DATA_DESCRIPTOR = UUID.from_16_bits(0x290F, 'Complete BR-EDR Transport Block Data')
147
+ GATT_OBSERVATION_SCHEDULE_DESCRIPTOR = UUID.from_16_bits(0x290F, 'Observation Schedule')
148
+ GATT_VALID_RANGE_AND_ACCURACY_DESCRIPTOR = UUID.from_16_bits(0x290F, 'Valid Range And Accuracy')
132
149
 
133
150
  # Device Information Service
134
151
  GATT_SYSTEM_ID_CHARACTERISTIC = UUID.from_16_bits(0x2A23, 'System ID')
@@ -156,6 +173,96 @@ GATT_HEART_RATE_CONTROL_POINT_CHARACTERISTIC = UUID.from_16_bits(0x2A39, 'Heart
156
173
  # Battery Service
157
174
  GATT_BATTERY_LEVEL_CHARACTERISTIC = UUID.from_16_bits(0x2A19, 'Battery Level')
158
175
 
176
+ # Telephony And Media Audio Service (TMAS)
177
+ GATT_TMAP_ROLE_CHARACTERISTIC = UUID.from_16_bits(0x2B51, 'TMAP Role')
178
+
179
+ # Audio Input Control Service (AICS)
180
+ GATT_AUDIO_INPUT_STATE_CHARACTERISTIC = UUID.from_16_bits(0x2B77, 'Audio Input State')
181
+ GATT_GAIN_SETTINGS_ATTRIBUTE_CHARACTERISTIC = UUID.from_16_bits(0x2B78, 'Gain Settings Attribute')
182
+ GATT_AUDIO_INPUT_TYPE_CHARACTERISTIC = UUID.from_16_bits(0x2B79, 'Audio Input Type')
183
+ GATT_AUDIO_INPUT_STATUS_CHARACTERISTIC = UUID.from_16_bits(0x2B7A, 'Audio Input Status')
184
+ GATT_AUDIO_INPUT_CONTROL_POINT_CHARACTERISTIC = UUID.from_16_bits(0x2B7B, 'Audio Input Control Point')
185
+ GATT_AUDIO_INPUT_DESCRIPTION_CHARACTERISTIC = UUID.from_16_bits(0x2B7C, 'Audio Input Description')
186
+
187
+ # Volume Control Service (VCS)
188
+ GATT_VOLUME_STATE_CHARACTERISTIC = UUID.from_16_bits(0x2B7D, 'Volume State')
189
+ GATT_VOLUME_CONTROL_POINT_CHARACTERISTIC = UUID.from_16_bits(0x2B7E, 'Volume Control Point')
190
+ GATT_VOLUME_FLAGS_CHARACTERISTIC = UUID.from_16_bits(0x2B7F, 'Volume Flags')
191
+
192
+ # Volume Offset Control Service (VOCS)
193
+ GATT_VOLUME_OFFSET_STATE_CHARACTERISTIC = UUID.from_16_bits(0x2B80, 'Volume Offset State')
194
+ GATT_AUDIO_LOCATION_CHARACTERISTIC = UUID.from_16_bits(0x2B81, 'Audio Location')
195
+ GATT_VOLUME_OFFSET_CONTROL_POINT_CHARACTERISTIC = UUID.from_16_bits(0x2B82, 'Volume Offset Control Point')
196
+ GATT_AUDIO_OUTPUT_DESCRIPTION_CHARACTERISTIC = UUID.from_16_bits(0x2B83, 'Audio Output Description')
197
+
198
+ # Coordinated Set Identification Service (CSIS)
199
+ GATT_SET_IDENTITY_RESOLVING_KEY_CHARACTERISTIC = UUID.from_16_bits(0x2B84, 'Set Identity Resolving Key')
200
+ GATT_COORDINATED_SET_SIZE_CHARACTERISTIC = UUID.from_16_bits(0x2B85, 'Coordinated Set Size')
201
+ GATT_SET_MEMBER_LOCK_CHARACTERISTIC = UUID.from_16_bits(0x2B86, 'Set Member Lock')
202
+ GATT_SET_MEMBER_RANK_CHARACTERISTIC = UUID.from_16_bits(0x2B87, 'Set Member Rank')
203
+
204
+ # Media Control Service (MCS)
205
+ GATT_MEDIA_PLAYER_NAME_CHARACTERISTIC = UUID.from_16_bits(0x2B93, 'Media Player Name')
206
+ GATT_MEDIA_PLAYER_ICON_OBJECT_ID_CHARACTERISTIC = UUID.from_16_bits(0x2B94, 'Media Player Icon Object ID')
207
+ GATT_MEDIA_PLAYER_ICON_URL_CHARACTERISTIC = UUID.from_16_bits(0x2B95, 'Media Player Icon URL')
208
+ GATT_TRACK_CHANGED_CHARACTERISTIC = UUID.from_16_bits(0x2B96, 'Track Changed')
209
+ GATT_TRACK_TITLE_CHARACTERISTIC = UUID.from_16_bits(0x2B97, 'Track Title')
210
+ GATT_TRACK_DURATION_CHARACTERISTIC = UUID.from_16_bits(0x2B98, 'Track Duration')
211
+ GATT_TRACK_POSITION_CHARACTERISTIC = UUID.from_16_bits(0x2B99, 'Track Position')
212
+ GATT_PLAYBACK_SPEED_CHARACTERISTIC = UUID.from_16_bits(0x2B9A, 'Playback Speed')
213
+ GATT_SEEKING_SPEED_CHARACTERISTIC = UUID.from_16_bits(0x2B9B, 'Seeking Speed')
214
+ GATT_CURRENT_TRACK_SEGMENTS_OBJECT_ID_CHARACTERISTIC = UUID.from_16_bits(0x2B9C, 'Current Track Segments Object ID')
215
+ GATT_CURRENT_TRACK_OBJECT_ID_CHARACTERISTIC = UUID.from_16_bits(0x2B9D, 'Current Track Object ID')
216
+ GATT_NEXT_TRACK_OBJECT_ID_CHARACTERISTIC = UUID.from_16_bits(0x2B9E, 'Next Track Object ID')
217
+ GATT_PARENT_GROUP_OBJECT_ID_CHARACTERISTIC = UUID.from_16_bits(0x2B9F, 'Parent Group Object ID')
218
+ GATT_CURRENT_GROUP_OBJECT_ID_CHARACTERISTIC = UUID.from_16_bits(0x2BA0, 'Current Group Object ID')
219
+ GATT_PLAYING_ORDER_CHARACTERISTIC = UUID.from_16_bits(0x2BA1, 'Playing Order')
220
+ GATT_PLAYING_ORDERS_SUPPORTED_CHARACTERISTIC = UUID.from_16_bits(0x2BA2, 'Playing Orders Supported')
221
+ GATT_MEDIA_STATE_CHARACTERISTIC = UUID.from_16_bits(0x2BA3, 'Media State')
222
+ GATT_MEDIA_CONTROL_POINT_CHARACTERISTIC = UUID.from_16_bits(0x2BA4, 'Media Control Point')
223
+ GATT_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED_CHARACTERISTIC = UUID.from_16_bits(0x2BA5, 'Media Control Point Opcodes Supported')
224
+ GATT_SEARCH_RESULTS_OBJECT_ID_CHARACTERISTIC = UUID.from_16_bits(0x2BA6, 'Search Results Object ID')
225
+ GATT_SEARCH_CONTROL_POINT_CHARACTERISTIC = UUID.from_16_bits(0x2BA7, 'Search Control Point')
226
+ GATT_CONTENT_CONTROL_ID_CHARACTERISTIC = UUID.from_16_bits(0x2BBA, 'Content Control Id')
227
+
228
+ # Telephone Bearer Service (TBS)
229
+ GATT_BEARER_PROVIDER_NAME_CHARACTERISTIC = UUID.from_16_bits(0x2BB4, 'Bearer Provider Name')
230
+ GATT_BEARER_UCI_CHARACTERISTIC = UUID.from_16_bits(0x2BB5, 'Bearer UCI')
231
+ GATT_BEARER_TECHNOLOGY_CHARACTERISTIC = UUID.from_16_bits(0x2BB6, 'Bearer Technology')
232
+ GATT_BEARER_URI_SCHEMES_SUPPORTED_LIST_CHARACTERISTIC = UUID.from_16_bits(0x2BB7, 'Bearer URI Schemes Supported List')
233
+ GATT_BEARER_SIGNAL_STRENGTH_CHARACTERISTIC = UUID.from_16_bits(0x2BB8, 'Bearer Signal Strength')
234
+ GATT_BEARER_SIGNAL_STRENGTH_REPORTING_INTERVAL_CHARACTERISTIC = UUID.from_16_bits(0x2BB9, 'Bearer Signal Strength Reporting Interval')
235
+ GATT_BEARER_LIST_CURRENT_CALLS_CHARACTERISTIC = UUID.from_16_bits(0x2BBA, 'Bearer List Current Calls')
236
+ GATT_CONTENT_CONTROL_ID_CHARACTERISTIC = UUID.from_16_bits(0x2BBB, 'Content Control ID')
237
+ GATT_STATUS_FLAGS_CHARACTERISTIC = UUID.from_16_bits(0x2BBC, 'Status Flags')
238
+ GATT_INCOMING_CALL_TARGET_BEARER_URI_CHARACTERISTIC = UUID.from_16_bits(0x2BBD, 'Incoming Call Target Bearer URI')
239
+ GATT_CALL_STATE_CHARACTERISTIC = UUID.from_16_bits(0x2BBE, 'Call State')
240
+ GATT_CALL_CONTROL_POINT_CHARACTERISTIC = UUID.from_16_bits(0x2BBF, 'Call Control Point')
241
+ GATT_CALL_CONTROL_POINT_OPTIONAL_OPCODES_CHARACTERISTIC = UUID.from_16_bits(0x2BC0, 'Call Control Point Optional Opcodes')
242
+ GATT_TERMINATION_REASON_CHARACTERISTIC = UUID.from_16_bits(0x2BC1, 'Termination Reason')
243
+ GATT_INCOMING_CALL_CHARACTERISTIC = UUID.from_16_bits(0x2BC2, 'Incoming Call')
244
+ GATT_CALL_FRIENDLY_NAME_CHARACTERISTIC = UUID.from_16_bits(0x2BC3, 'Call Friendly Name')
245
+
246
+ # Microphone Control Service (MICS)
247
+ GATT_MUTE_CHARACTERISTIC = UUID.from_16_bits(0x2BC3, 'Mute')
248
+
249
+ # Audio Stream Control Service (ASCS)
250
+ GATT_SINK_ASE_CHARACTERISTIC = UUID.from_16_bits(0x2BC4, 'Sink ASE')
251
+ GATT_SOURCE_ASE_CHARACTERISTIC = UUID.from_16_bits(0x2BC5, 'Source ASE')
252
+ GATT_ASE_CONTROL_POINT_CHARACTERISTIC = UUID.from_16_bits(0x2BC6, 'ASE Control Point')
253
+
254
+ # Broadcast Audio Scan Service (BASS)
255
+ GATT_BROADCAST_AUDIO_SCAN_CONTROL_POINT_CHARACTERISTIC = UUID.from_16_bits(0x2BC7, 'Broadcast Audio Scan Control Point')
256
+ GATT_BROADCAST_RECEIVE_STATE_CHARACTERISTIC = UUID.from_16_bits(0x2BC8, 'Broadcast Receive State')
257
+
258
+ # Published Audio Capabilities Service (PACS)
259
+ GATT_SINK_PAC_CHARACTERISTIC = UUID.from_16_bits(0x2BC9, 'Sink PAC')
260
+ GATT_SINK_AUDIO_LOCATION_CHARACTERISTIC = UUID.from_16_bits(0x2BCA, 'Sink Audio Location')
261
+ GATT_SOURCE_PAC_CHARACTERISTIC = UUID.from_16_bits(0x2BCB, 'Source PAC')
262
+ GATT_SOURCE_AUDIO_LOCATION_CHARACTERISTIC = UUID.from_16_bits(0x2BCC, 'Source Audio Location')
263
+ GATT_AVAILABLE_AUDIO_CONTEXTS_CHARACTERISTIC = UUID.from_16_bits(0x2BCD, 'Available Audio Contexts')
264
+ GATT_SUPPORTED_AUDIO_CONTEXTS_CHARACTERISTIC = UUID.from_16_bits(0x2BCE, 'Supported Audio Contexts')
265
+
159
266
  # ASHA Service
160
267
  GATT_ASHA_SERVICE = UUID.from_16_bits(0xFDF0, 'Audio Streaming for Hearing Aid')
161
268
  GATT_ASHA_READ_ONLY_PROPERTIES_CHARACTERISTIC = UUID('6333651e-c481-4a3e-9169-7c902aad37bb', 'ReadOnlyProperties')
@@ -177,6 +284,9 @@ GATT_BOOT_KEYBOARD_INPUT_REPORT_CHARACTERISTIC = UUID.from_16_bi
177
284
  GATT_CURRENT_TIME_CHARACTERISTIC = UUID.from_16_bits(0x2A2B, 'Current Time')
178
285
  GATT_BOOT_KEYBOARD_OUTPUT_REPORT_CHARACTERISTIC = UUID.from_16_bits(0x2A32, 'Boot Keyboard Output Report')
179
286
  GATT_CENTRAL_ADDRESS_RESOLUTION__CHARACTERISTIC = UUID.from_16_bits(0x2AA6, 'Central Address Resolution')
287
+ GATT_CLIENT_SUPPORTED_FEATURES_CHARACTERISTIC = UUID.from_16_bits(0x2B29, 'Client Supported Features')
288
+ GATT_DATABASE_HASH_CHARACTERISTIC = UUID.from_16_bits(0x2B2A, 'Database Hash')
289
+ GATT_SERVER_SUPPORTED_FEATURES_CHARACTERISTIC = UUID.from_16_bits(0x2B3A, 'Server Supported Features')
180
290
 
181
291
  # fmt: on
182
292
  # pylint: enable=line-too-long
@@ -38,6 +38,7 @@ from typing import (
38
38
  Any,
39
39
  Iterable,
40
40
  Type,
41
+ Set,
41
42
  TYPE_CHECKING,
42
43
  )
43
44
 
@@ -128,7 +129,7 @@ class ServiceProxy(AttributeProxy):
128
129
  included_services: List[ServiceProxy]
129
130
 
130
131
  @staticmethod
131
- def from_client(service_class, client, service_uuid):
132
+ def from_client(service_class, client: Client, service_uuid: UUID):
132
133
  # The service and its characteristics are considered to have already been
133
134
  # discovered
134
135
  services = client.get_services_by_uuid(service_uuid)
@@ -206,11 +207,11 @@ class CharacteristicProxy(AttributeProxy):
206
207
 
207
208
  return await self.client.subscribe(self, subscriber, prefer_notify)
208
209
 
209
- async def unsubscribe(self, subscriber=None):
210
+ async def unsubscribe(self, subscriber=None, force=False):
210
211
  if subscriber in self.subscribers:
211
212
  subscriber = self.subscribers.pop(subscriber)
212
213
 
213
- return await self.client.unsubscribe(self, subscriber)
214
+ return await self.client.unsubscribe(self, subscriber, force)
214
215
 
215
216
  def __str__(self) -> str:
216
217
  return (
@@ -246,8 +247,12 @@ class ProfileServiceProxy:
246
247
  class Client:
247
248
  services: List[ServiceProxy]
248
249
  cached_values: Dict[int, Tuple[datetime, bytes]]
249
- notification_subscribers: Dict[int, Callable[[bytes], Any]]
250
- indication_subscribers: Dict[int, Callable[[bytes], Any]]
250
+ notification_subscribers: Dict[
251
+ int, Set[Union[CharacteristicProxy, Callable[[bytes], Any]]]
252
+ ]
253
+ indication_subscribers: Dict[
254
+ int, Set[Union[CharacteristicProxy, Callable[[bytes], Any]]]
255
+ ]
251
256
  pending_response: Optional[asyncio.futures.Future[ATT_PDU]]
252
257
  pending_request: Optional[ATT_PDU]
253
258
 
@@ -257,10 +262,8 @@ class Client:
257
262
  self.request_semaphore = asyncio.Semaphore(1)
258
263
  self.pending_request = None
259
264
  self.pending_response = None
260
- self.notification_subscribers = (
261
- {}
262
- ) # Notification subscribers, by attribute handle
263
- self.indication_subscribers = {} # Indication subscribers, by attribute handle
265
+ self.notification_subscribers = {} # Subscriber set, by attribute handle
266
+ self.indication_subscribers = {} # Subscriber set, by attribute handle
264
267
  self.services = []
265
268
  self.cached_values = {}
266
269
 
@@ -682,8 +685,8 @@ class Client:
682
685
  async def discover_descriptors(
683
686
  self,
684
687
  characteristic: Optional[CharacteristicProxy] = None,
685
- start_handle=None,
686
- end_handle=None,
688
+ start_handle: Optional[int] = None,
689
+ end_handle: Optional[int] = None,
687
690
  ) -> List[DescriptorProxy]:
688
691
  '''
689
692
  See Vol 3, Part G - 4.7.1 Discover All Characteristic Descriptors
@@ -789,7 +792,12 @@ class Client:
789
792
 
790
793
  return attributes
791
794
 
792
- async def subscribe(self, characteristic, subscriber=None, prefer_notify=True):
795
+ async def subscribe(
796
+ self,
797
+ characteristic: CharacteristicProxy,
798
+ subscriber: Optional[Callable[[bytes], Any]] = None,
799
+ prefer_notify: bool = True,
800
+ ) -> None:
793
801
  # If we haven't already discovered the descriptors for this characteristic,
794
802
  # do it now
795
803
  if not characteristic.descriptors_discovered:
@@ -826,6 +834,7 @@ class Client:
826
834
  subscriber_set = subscribers.setdefault(characteristic.handle, set())
827
835
  if subscriber is not None:
828
836
  subscriber_set.add(subscriber)
837
+
829
838
  # Add the characteristic as a subscriber, which will result in the
830
839
  # characteristic emitting an 'update' event when a notification or indication
831
840
  # is received
@@ -833,7 +842,18 @@ class Client:
833
842
 
834
843
  await self.write_value(cccd, struct.pack('<H', bits), with_response=True)
835
844
 
836
- async def unsubscribe(self, characteristic, subscriber=None):
845
+ async def unsubscribe(
846
+ self,
847
+ characteristic: CharacteristicProxy,
848
+ subscriber: Optional[Callable[[bytes], Any]] = None,
849
+ force: bool = False,
850
+ ) -> None:
851
+ '''
852
+ Unsubscribe from a characteristic.
853
+
854
+ If `force` is True, this will write zeros to the CCCD when there are no
855
+ subscribers left, even if there were already no registered subscribers.
856
+ '''
837
857
  # If we haven't already discovered the descriptors for this characteristic,
838
858
  # do it now
839
859
  if not characteristic.descriptors_discovered:
@@ -847,31 +867,45 @@ class Client:
847
867
  logger.warning('unsubscribing from characteristic with no CCCD descriptor')
848
868
  return
849
869
 
870
+ # Check if the characteristic has subscribers
871
+ if not (
872
+ characteristic.handle in self.notification_subscribers
873
+ or characteristic.handle in self.indication_subscribers
874
+ ):
875
+ if not force:
876
+ return
877
+
878
+ # Remove the subscriber(s)
850
879
  if subscriber is not None:
851
880
  # Remove matching subscriber from subscriber sets
852
881
  for subscriber_set in (
853
882
  self.notification_subscribers,
854
883
  self.indication_subscribers,
855
884
  ):
856
- subscribers = subscriber_set.get(characteristic.handle, [])
857
- if subscriber in subscribers:
885
+ if (
886
+ subscribers := subscriber_set.get(characteristic.handle)
887
+ ) and subscriber in subscribers:
858
888
  subscribers.remove(subscriber)
859
889
 
860
890
  # Cleanup if we removed the last one
861
891
  if not subscribers:
862
892
  del subscriber_set[characteristic.handle]
863
893
  else:
864
- # Remove all subscribers for this attribute from the sets!
894
+ # Remove all subscribers for this attribute from the sets
865
895
  self.notification_subscribers.pop(characteristic.handle, None)
866
896
  self.indication_subscribers.pop(characteristic.handle, None)
867
897
 
868
- if not self.notification_subscribers and not self.indication_subscribers:
898
+ # Update the CCCD
899
+ if not (
900
+ characteristic.handle in self.notification_subscribers
901
+ or characteristic.handle in self.indication_subscribers
902
+ ):
869
903
  # No more subscribers left
870
904
  await self.write_value(cccd, b'\x00\x00', with_response=True)
871
905
 
872
906
  async def read_value(
873
907
  self, attribute: Union[int, AttributeProxy], no_long_read: bool = False
874
- ) -> Any:
908
+ ) -> bytes:
875
909
  '''
876
910
  See Vol 3, Part G - 4.8.1 Read Characteristic Value
877
911
 
@@ -1067,7 +1101,7 @@ class Client:
1067
1101
  def on_att_handle_value_notification(self, notification):
1068
1102
  # Call all subscribers
1069
1103
  subscribers = self.notification_subscribers.get(
1070
- notification.attribute_handle, []
1104
+ notification.attribute_handle, set()
1071
1105
  )
1072
1106
  if not subscribers:
1073
1107
  logger.warning('!!! received notification with no subscriber')
@@ -1081,7 +1115,9 @@ class Client:
1081
1115
 
1082
1116
  def on_att_handle_value_indication(self, indication):
1083
1117
  # Call all subscribers
1084
- subscribers = self.indication_subscribers.get(indication.attribute_handle, [])
1118
+ subscribers = self.indication_subscribers.get(
1119
+ indication.attribute_handle, set()
1120
+ )
1085
1121
  if not subscribers:
1086
1122
  logger.warning('!!! received indication with no subscriber')
1087
1123
 
@@ -5296,6 +5296,10 @@ class HCI_Disconnection_Complete_Event(HCI_Event):
5296
5296
  See Bluetooth spec @ 7.7.5 Disconnection Complete Event
5297
5297
  '''
5298
5298
 
5299
+ status: int
5300
+ connection_handle: int
5301
+ reason: int
5302
+
5299
5303
 
5300
5304
  # -----------------------------------------------------------------------------
5301
5305
  @HCI_Event.event([('status', STATUS_SPEC), ('connection_handle', 2)])