From e5ba86447065b3094fd001ef59a66f8a4deb49af Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Thu, 14 Sep 2023 13:14:35 +1000 Subject: [PATCH] aioble/server.py: Add data arg for indicate. In micropython/micropython#11239 we added support for passing data to gatts_indicate (to make it match gatts_notify). This adds the same to aioble. Also update the documentation to mention this (and fix some mistakes and add a few more examples). This work was funded through GitHub Sponsors. Signed-off-by: Jim Mussared --- .../bluetooth/aioble-server/manifest.py | 2 +- micropython/bluetooth/aioble/README.md | 87 ++++++++++++++++--- micropython/bluetooth/aioble/aioble/server.py | 4 +- micropython/bluetooth/aioble/manifest.py | 2 +- 4 files changed, 80 insertions(+), 15 deletions(-) diff --git a/micropython/bluetooth/aioble-server/manifest.py b/micropython/bluetooth/aioble-server/manifest.py index fc51154..0fb1840 100644 --- a/micropython/bluetooth/aioble-server/manifest.py +++ b/micropython/bluetooth/aioble-server/manifest.py @@ -1,4 +1,4 @@ -metadata(version="0.3.0") +metadata(version="0.4.0") require("aioble-core") diff --git a/micropython/bluetooth/aioble/README.md b/micropython/bluetooth/aioble/README.md index 6b6b204..b488721 100644 --- a/micropython/bluetooth/aioble/README.md +++ b/micropython/bluetooth/aioble/README.md @@ -70,7 +70,7 @@ Alternatively, install the `aioble` package, which will install everything. Usage ----- -Passive scan for nearby devices for 5 seconds: (Observer) +#### Passive scan for nearby devices for 5 seconds: (Observer) ```py async with aioble.scan(duration_ms=5000) as scanner: @@ -87,7 +87,7 @@ async with aioble.scan(duration_ms=5000, interval_us=30000, window_us=30000, act print(result, result.name(), result.rssi, result.services()) ``` -Connect to a peripheral device: (Central) +#### Connect to a peripheral device: (Central) ```py # Either from scan result @@ -101,7 +101,7 @@ except asyncio.TimeoutError: print('Timeout') ``` -Register services and wait for connection: (Peripheral, Server) +#### Register services and wait for connection: (Peripheral, Server) ```py _ENV_SENSE_UUID = bluetooth.UUID(0x181A) @@ -126,30 +126,95 @@ while True: print("Connection from", device) ``` -Update characteristic value: (Server) +#### Update characteristic value: (Server) ```py +# Write the local value. temp_char.write(b'data') - -temp_char.notify(b'optional data') - -await temp_char.indicate(timeout_ms=2000) ``` -Query the value of a characteristic: (Client) +```py +# Write the local value and notify/indicate subscribers. +temp_char.write(b'data', send_update=True) +``` + +#### Send notifications: (Server) + +```py +# Notify with the current value. +temp_char.notify(connection) +``` + +```py +# Notify with a custom value. +temp_char.notify(connection, b'optional data') +``` + +#### Send indications: (Server) + +```py +# Indicate with current value. +await temp_char.indicate(connection, timeout_ms=2000) +``` + +```py +# Indicate with custom value. +await temp_char.indicate(connection, b'optional data', timeout_ms=2000) +``` + +This will raise `GattError` if the indication is not acknowledged. + +#### Wait for a write from the client: (Server) + +```py +# Normal characteristic, returns the connection that did the write. +connection = await char.written(timeout_ms=2000) +``` + +```py +# Characteristic with capture enabled, also returns the value. +char = Characteristic(..., capture=True) +connection, data = await char.written(timeout_ms=2000) +``` + +#### Query the value of a characteristic: (Client) ```py temp_service = await connection.service(_ENV_SENSE_UUID) temp_char = await temp_service.characteristic(_ENV_SENSE_TEMP_UUID) data = await temp_char.read(timeout_ms=1000) +``` +#### Wait for a notification/indication: (Client) + +```py +# Notification +data = await temp_char.notified(timeout_ms=1000) +``` + +```py +# Indication +data = await temp_char.indicated(timeout_ms=1000) +``` + +#### Subscribe to a characteristic: (Client) + +```py +# Subscribe for notification. await temp_char.subscribe(notify=True) while True: data = await temp_char.notified() ``` -Open L2CAP channels: (Listener) +```py +# Subscribe for indication. +await temp_char.subscribe(indicate=True) +while True: + data = await temp_char.indicated() +``` + +#### Open L2CAP channels: (Listener) ```py channel = await connection.l2cap_accept(_L2CAP_PSN, _L2CAP_MTU) @@ -158,7 +223,7 @@ n = channel.recvinto(buf) channel.send(b'response') ``` -Open L2CAP channels: (Initiator) +#### Open L2CAP channels: (Initiator) ```py channel = await connection.l2cap_connect(_L2CAP_PSN, _L2CAP_MTU) diff --git a/micropython/bluetooth/aioble/aioble/server.py b/micropython/bluetooth/aioble/aioble/server.py index b6cc4a3..ed3299d 100644 --- a/micropython/bluetooth/aioble/aioble/server.py +++ b/micropython/bluetooth/aioble/aioble/server.py @@ -257,7 +257,7 @@ class Characteristic(BaseCharacteristic): raise ValueError("Not supported") ble.gatts_notify(connection._conn_handle, self._value_handle, data) - async def indicate(self, connection, timeout_ms=1000): + async def indicate(self, connection, data=None, timeout_ms=1000): if not (self.flags & _FLAG_INDICATE): raise ValueError("Not supported") if self._indicate_connection is not None: @@ -270,7 +270,7 @@ class Characteristic(BaseCharacteristic): try: with connection.timeout(timeout_ms): - ble.gatts_indicate(connection._conn_handle, self._value_handle) + ble.gatts_indicate(connection._conn_handle, self._value_handle, data) await self._indicate_event.wait() if self._indicate_status != 0: raise GattError(self._indicate_status) diff --git a/micropython/bluetooth/aioble/manifest.py b/micropython/bluetooth/aioble/manifest.py index 4c0edbb..24187af 100644 --- a/micropython/bluetooth/aioble/manifest.py +++ b/micropython/bluetooth/aioble/manifest.py @@ -3,7 +3,7 @@ # code. This allows (for development purposes) all the files to live in the # one directory. -metadata(version="0.3.1") +metadata(version="0.4.0") # Default installation gives you everything. Install the individual # components (or a combination of them) if you want a more minimal install.