mirror of
https://github.com/google/bumble.git
synced 2026-04-16 00:25:31 +00:00
new adapter classes
This commit is contained in:
@@ -102,7 +102,6 @@ async def main() -> None:
|
||||
)
|
||||
|
||||
# Notify subscribers of the current value as soon as they subscribe
|
||||
@heart_rate_service.heart_rate_measurement_characteristic.on('subscription')
|
||||
def on_subscription(connection, notify_enabled, indicate_enabled):
|
||||
if notify_enabled or indicate_enabled:
|
||||
AsyncRunner.spawn(
|
||||
@@ -112,6 +111,10 @@ async def main() -> None:
|
||||
)
|
||||
)
|
||||
|
||||
heart_rate_service.heart_rate_measurement_characteristic.on(
|
||||
'subscription', on_subscription
|
||||
)
|
||||
|
||||
# Go!
|
||||
await device.power_on()
|
||||
await device.start_advertising(auto_restart=True)
|
||||
|
||||
@@ -70,13 +70,13 @@ async def main() -> None:
|
||||
descriptor = Descriptor(
|
||||
GATT_CHARACTERISTIC_USER_DESCRIPTION_DESCRIPTOR,
|
||||
Descriptor.READABLE,
|
||||
'My Description',
|
||||
'My Description'.encode(),
|
||||
)
|
||||
manufacturer_name_characteristic = Characteristic(
|
||||
manufacturer_name_characteristic = Characteristic[bytes](
|
||||
GATT_MANUFACTURER_NAME_STRING_CHARACTERISTIC,
|
||||
Characteristic.Properties.READ,
|
||||
Characteristic.READABLE,
|
||||
"Fitbit",
|
||||
"Fitbit".encode(),
|
||||
[descriptor],
|
||||
)
|
||||
device_info_service = Service(
|
||||
|
||||
@@ -94,13 +94,13 @@ async def main() -> None:
|
||||
descriptor = Descriptor(
|
||||
GATT_CHARACTERISTIC_USER_DESCRIPTION_DESCRIPTOR,
|
||||
Descriptor.READABLE,
|
||||
'My Description',
|
||||
'My Description'.encode(),
|
||||
)
|
||||
manufacturer_name_characteristic = Characteristic(
|
||||
GATT_MANUFACTURER_NAME_STRING_CHARACTERISTIC,
|
||||
Characteristic.Properties.READ,
|
||||
Characteristic.READABLE,
|
||||
'Fitbit',
|
||||
'Fitbit'.encode(),
|
||||
[descriptor],
|
||||
)
|
||||
device_info_service = Service(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright 2024 Google LLC
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -18,6 +18,8 @@
|
||||
from __future__ import annotations
|
||||
import asyncio
|
||||
import dataclasses
|
||||
import functools
|
||||
import enum
|
||||
import logging
|
||||
import os
|
||||
import random
|
||||
@@ -28,6 +30,8 @@ from typing import Any, List, Union
|
||||
from bumble.device import Device, Peer
|
||||
from bumble import transport
|
||||
from bumble import gatt
|
||||
from bumble import gatt_adapters
|
||||
from bumble import gatt_client
|
||||
from bumble import hci
|
||||
from bumble import core
|
||||
|
||||
@@ -36,6 +40,9 @@ from bumble import core
|
||||
SERVICE_UUID = core.UUID("50DB505C-8AC4-4738-8448-3B1D9CC09CC5")
|
||||
CHARACTERISTIC_UUID_BASE = "D901B45B-4916-412E-ACCA-0000000000"
|
||||
|
||||
DEFAULT_CLIENT_ADDRESS = "F0:F1:F2:F3:F4:F5"
|
||||
DEFAULT_SERVER_ADDRESS = "F1:F2:F3:F4:F5:F6"
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
@dataclasses.dataclass
|
||||
@@ -65,6 +72,12 @@ class CustomClass:
|
||||
return struct.pack(">II", self.a, self.b)
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
class CustomEnum(enum.IntEnum):
|
||||
FOO = 1234
|
||||
BAR = 5678
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
async def client(device: Device, address: hci.Address) -> None:
|
||||
print(f'=== Connecting to {address}...')
|
||||
@@ -78,8 +91,8 @@ async def client(device: Device, address: hci.Address) -> None:
|
||||
print("*** Discovery complete")
|
||||
|
||||
service = peer.get_services_by_uuid(SERVICE_UUID)[0]
|
||||
characteristics = []
|
||||
for index in range(1, 9):
|
||||
characteristics: list[gatt_client.CharacteristicProxy] = []
|
||||
for index in range(1, 10):
|
||||
characteristics.append(
|
||||
service.get_characteristics_by_uuid(
|
||||
core.UUID(CHARACTERISTIC_UUID_BASE + f"{index:02X}")
|
||||
@@ -91,59 +104,92 @@ async def client(device: Device, address: hci.Address) -> None:
|
||||
value = await characteristic.read_value()
|
||||
print(f"### {characteristic} = {value!r} ({value.hex()})")
|
||||
|
||||
# Subscribe to all characteristics as a raw bytes listener.
|
||||
def on_raw_characteristic_update(characteristic, value):
|
||||
print(f"^^^ Update[RAW] {characteristic.uuid} value = {value.hex()}")
|
||||
|
||||
for characteristic in characteristics:
|
||||
await characteristic.subscribe(
|
||||
functools.partial(on_raw_characteristic_update, characteristic)
|
||||
)
|
||||
|
||||
# Function to subscribe to adapted characteristics
|
||||
def on_adapted_characteristic_update(characteristic, value):
|
||||
print(
|
||||
f"^^^ Update[ADAPTED] {characteristic.uuid} value = {value!r}, "
|
||||
f"type={type(value)}"
|
||||
)
|
||||
|
||||
# Static characteristic with a bytes value.
|
||||
c1 = characteristics[0]
|
||||
c1_value = await c1.read_value()
|
||||
print(f"@@@ C1 {c1} value = {c1_value!r} (type={type(c1_value)})")
|
||||
await c1.write_value("happy π day".encode("utf-8"))
|
||||
await c1.subscribe(functools.partial(on_adapted_characteristic_update, c1))
|
||||
|
||||
# Static characteristic with a string value.
|
||||
c2 = gatt.UTF8CharacteristicAdapter(characteristics[1])
|
||||
c2 = gatt_adapters.UTF8CharacteristicProxyAdapter(characteristics[1])
|
||||
c2_value = await c2.read_value()
|
||||
print(f"@@@ C2 {c2} value = {c2_value} (type={type(c2_value)})")
|
||||
await c2.write_value("happy π day")
|
||||
await c2.subscribe(functools.partial(on_adapted_characteristic_update, c2))
|
||||
|
||||
# Static characteristic with a tuple value.
|
||||
c3 = gatt.PackedCharacteristicAdapter(characteristics[2], ">III")
|
||||
c3 = gatt_adapters.PackedCharacteristicProxyAdapter(characteristics[2], ">III")
|
||||
c3_value = await c3.read_value()
|
||||
print(f"@@@ C3 {c3} value = {c3_value} (type={type(c3_value)})")
|
||||
await c3.write_value((2001, 2002, 2003))
|
||||
await c3.subscribe(functools.partial(on_adapted_characteristic_update, c3))
|
||||
|
||||
# Static characteristic with a named tuple value.
|
||||
c4 = gatt.MappedCharacteristicAdapter(
|
||||
c4 = gatt_adapters.MappedCharacteristicProxyAdapter(
|
||||
characteristics[3], ">III", ["f1", "f2", "f3"]
|
||||
)
|
||||
c4_value = await c4.read_value()
|
||||
print(f"@@@ C4 {c4} value = {c4_value} (type={type(c4_value)})")
|
||||
await c4.write_value({"f1": 4001, "f2": 4002, "f3": 4003})
|
||||
await c4.subscribe(functools.partial(on_adapted_characteristic_update, c4))
|
||||
|
||||
# Static characteristic with a serializable value.
|
||||
c5 = gatt.SerializableCharacteristicAdapter(
|
||||
c5 = gatt_adapters.SerializableCharacteristicProxyAdapter(
|
||||
characteristics[4], CustomSerializableClass
|
||||
)
|
||||
c5_value = await c5.read_value()
|
||||
print(f"@@@ C5 {c5} value = {c5_value} (type={type(c5_value)})")
|
||||
await c5.write_value(CustomSerializableClass(56, 57))
|
||||
await c5.subscribe(functools.partial(on_adapted_characteristic_update, c5))
|
||||
|
||||
# Static characteristic with a delegated value.
|
||||
c6 = gatt.DelegatedCharacteristicAdapter(
|
||||
c6 = gatt_adapters.DelegatedCharacteristicProxyAdapter(
|
||||
characteristics[5], encode=CustomClass.encode, decode=CustomClass.decode
|
||||
)
|
||||
c6_value = await c6.read_value()
|
||||
print(f"@@@ C6 {c6} value = {c6_value} (type={type(c6_value)})")
|
||||
await c6.write_value(CustomClass(6, 7))
|
||||
await c6.subscribe(functools.partial(on_adapted_characteristic_update, c6))
|
||||
|
||||
# Dynamic characteristic with a bytes value.
|
||||
c7 = characteristics[6]
|
||||
c7_value = await c7.read_value()
|
||||
print(f"@@@ C7 {c7} value = {c7_value!r} (type={type(c7_value)})")
|
||||
await c7.write_value(bytes.fromhex("01020304"))
|
||||
await c7.subscribe(functools.partial(on_adapted_characteristic_update, c7))
|
||||
|
||||
# Dynamic characteristic with a string value.
|
||||
c8 = gatt.UTF8CharacteristicAdapter(characteristics[7])
|
||||
c8 = gatt_adapters.UTF8CharacteristicProxyAdapter(characteristics[7])
|
||||
c8_value = await c8.read_value()
|
||||
print(f"@@@ C8 {c8} value = {c8_value} (type={type(c8_value)})")
|
||||
await c8.write_value("howdy")
|
||||
await c8.subscribe(functools.partial(on_adapted_characteristic_update, c8))
|
||||
|
||||
# Static characteristic with an enum value
|
||||
c9 = gatt_adapters.EnumCharacteristicProxyAdapter(
|
||||
characteristics[8], CustomEnum, 3, 'big'
|
||||
)
|
||||
c9_value = await c9.read_value()
|
||||
print(f"@@@ C9 {c9} value = {c9_value.name} (type={type(c9_value)})")
|
||||
await c9.write_value(CustomEnum.BAR)
|
||||
await c9.subscribe(functools.partial(on_adapted_characteristic_update, c9))
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
@@ -175,142 +221,213 @@ def on_characteristic_write(characteristic: gatt.Characteristic, value: Any) ->
|
||||
print(f"<<< WRITE: {characteristic} <- {value} ({type(value)})")
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
async def server(device: Device) -> None:
|
||||
# Static characteristic with a bytes value.
|
||||
c1 = gatt.Characteristic(
|
||||
CHARACTERISTIC_UUID_BASE + "01",
|
||||
gatt.Characteristic.Properties.READ
|
||||
| gatt.Characteristic.Properties.WRITE
|
||||
| gatt.Characteristic.Properties.NOTIFY,
|
||||
gatt.Characteristic.READABLE | gatt.Characteristic.WRITEABLE,
|
||||
b'hello',
|
||||
)
|
||||
|
||||
# Static characteristic with a string value.
|
||||
c2 = gatt_adapters.UTF8CharacteristicAdapter(
|
||||
gatt.Characteristic(
|
||||
CHARACTERISTIC_UUID_BASE + "02",
|
||||
gatt.Characteristic.Properties.READ
|
||||
| gatt.Characteristic.Properties.WRITE
|
||||
| gatt.Characteristic.Properties.NOTIFY,
|
||||
gatt.Characteristic.READABLE | gatt.Characteristic.WRITEABLE,
|
||||
'hello',
|
||||
)
|
||||
)
|
||||
|
||||
# Static characteristic with a tuple value.
|
||||
c3 = gatt_adapters.PackedCharacteristicAdapter(
|
||||
gatt.Characteristic(
|
||||
CHARACTERISTIC_UUID_BASE + "03",
|
||||
gatt.Characteristic.Properties.READ
|
||||
| gatt.Characteristic.Properties.WRITE
|
||||
| gatt.Characteristic.Properties.NOTIFY,
|
||||
gatt.Characteristic.READABLE | gatt.Characteristic.WRITEABLE,
|
||||
(1007, 1008, 1009),
|
||||
),
|
||||
">III",
|
||||
)
|
||||
|
||||
# Static characteristic with a named tuple value.
|
||||
c4 = gatt_adapters.MappedCharacteristicAdapter(
|
||||
gatt.Characteristic(
|
||||
CHARACTERISTIC_UUID_BASE + "04",
|
||||
gatt.Characteristic.Properties.READ
|
||||
| gatt.Characteristic.Properties.WRITE
|
||||
| gatt.Characteristic.Properties.NOTIFY,
|
||||
gatt.Characteristic.READABLE | gatt.Characteristic.WRITEABLE,
|
||||
{"f1": 3007, "f2": 3008, "f3": 3009},
|
||||
),
|
||||
">III",
|
||||
["f1", "f2", "f3"],
|
||||
)
|
||||
|
||||
# Static characteristic with a serializable value.
|
||||
c5 = gatt_adapters.SerializableCharacteristicAdapter(
|
||||
gatt.Characteristic(
|
||||
CHARACTERISTIC_UUID_BASE + "05",
|
||||
gatt.Characteristic.Properties.READ
|
||||
| gatt.Characteristic.Properties.WRITE
|
||||
| gatt.Characteristic.Properties.NOTIFY,
|
||||
gatt.Characteristic.READABLE | gatt.Characteristic.WRITEABLE,
|
||||
CustomSerializableClass(11, 12),
|
||||
),
|
||||
CustomSerializableClass,
|
||||
)
|
||||
|
||||
# Static characteristic with a delegated value.
|
||||
c6 = gatt_adapters.DelegatedCharacteristicAdapter(
|
||||
gatt.Characteristic(
|
||||
CHARACTERISTIC_UUID_BASE + "06",
|
||||
gatt.Characteristic.Properties.READ
|
||||
| gatt.Characteristic.Properties.WRITE
|
||||
| gatt.Characteristic.Properties.NOTIFY,
|
||||
gatt.Characteristic.READABLE | gatt.Characteristic.WRITEABLE,
|
||||
CustomClass(1, 2),
|
||||
),
|
||||
encode=CustomClass.encode,
|
||||
decode=CustomClass.decode,
|
||||
)
|
||||
|
||||
# Dynamic characteristic with a bytes value.
|
||||
c7 = gatt.Characteristic(
|
||||
CHARACTERISTIC_UUID_BASE + "07",
|
||||
gatt.Characteristic.Properties.READ
|
||||
| gatt.Characteristic.Properties.WRITE
|
||||
| gatt.Characteristic.Properties.NOTIFY,
|
||||
gatt.Characteristic.READABLE | gatt.Characteristic.WRITEABLE,
|
||||
gatt.CharacteristicValue(
|
||||
read=lambda connection: dynamic_read("bytes"),
|
||||
write=lambda connection, value: dynamic_write("bytes", value),
|
||||
),
|
||||
)
|
||||
|
||||
# Dynamic characteristic with a string value.
|
||||
c8 = gatt_adapters.UTF8CharacteristicAdapter(
|
||||
gatt.Characteristic(
|
||||
CHARACTERISTIC_UUID_BASE + "08",
|
||||
gatt.Characteristic.Properties.READ
|
||||
| gatt.Characteristic.Properties.WRITE
|
||||
| gatt.Characteristic.Properties.NOTIFY,
|
||||
gatt.Characteristic.READABLE | gatt.Characteristic.WRITEABLE,
|
||||
gatt.CharacteristicValue(
|
||||
read=lambda connection: dynamic_read("string"),
|
||||
write=lambda connection, value: dynamic_write("string", value),
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
# Static characteristic with an enum value
|
||||
c9 = gatt_adapters.EnumCharacteristicAdapter(
|
||||
gatt.Characteristic(
|
||||
CHARACTERISTIC_UUID_BASE + "09",
|
||||
gatt.Characteristic.Properties.READ
|
||||
| gatt.Characteristic.Properties.WRITE
|
||||
| gatt.Characteristic.Properties.NOTIFY,
|
||||
gatt.Characteristic.READABLE | gatt.Characteristic.WRITEABLE,
|
||||
CustomEnum.FOO,
|
||||
),
|
||||
cls=CustomEnum,
|
||||
length=3,
|
||||
byteorder='big',
|
||||
)
|
||||
|
||||
characteristics: List[gatt.Characteristic] = [
|
||||
c1,
|
||||
c2,
|
||||
c3,
|
||||
c4,
|
||||
c5,
|
||||
c6,
|
||||
c7,
|
||||
c8,
|
||||
c9,
|
||||
]
|
||||
|
||||
# Listen for read and write events.
|
||||
for characteristic in characteristics:
|
||||
characteristic.on(
|
||||
"read",
|
||||
lambda _, value, c=characteristic: on_characteristic_read(c, value),
|
||||
)
|
||||
characteristic.on(
|
||||
"write",
|
||||
lambda _, value, c=characteristic: on_characteristic_write(c, value),
|
||||
)
|
||||
|
||||
device.add_service(gatt.Service(SERVICE_UUID, characteristics))
|
||||
|
||||
# Notify every 3 seconds
|
||||
i = 0
|
||||
while True:
|
||||
await asyncio.sleep(3)
|
||||
|
||||
# Notifying can be done with the characteristic's current value, or
|
||||
# by explicitly passing a value to notify with. Both variants are used
|
||||
# here: for c1..c4 we set the value and then notify, for c4..c9 we notify
|
||||
# with an explicit value.
|
||||
c1.value = f'hello c1 {i}'.encode()
|
||||
await device.notify_subscribers(c1)
|
||||
c2.value = f'hello c2 {i}'
|
||||
await device.notify_subscribers(c2)
|
||||
c3.value = (1000 + i, 2000 + i, 3000 + i)
|
||||
await device.notify_subscribers(c3)
|
||||
c4.value = {"f1": 4000 + i, "f2": 5000 + i, "f3": 6000 + i}
|
||||
await device.notify_subscribers(c4)
|
||||
await device.notify_subscribers(c5, CustomSerializableClass(1000 + i, 2000 + i))
|
||||
await device.notify_subscribers(c6, CustomClass(3000 + i, 4000 + i))
|
||||
await device.notify_subscribers(c7, bytes([1, 2, 3, i % 256]))
|
||||
await device.notify_subscribers(c8, f'hello c8 {i}')
|
||||
await device.notify_subscribers(
|
||||
c9, CustomEnum.FOO if i % 2 == 0 else CustomEnum.BAR
|
||||
)
|
||||
|
||||
i += 1
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
async def main() -> None:
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: run_gatt_with_adapters.py <transport-spec> [<bluetooth-address>]")
|
||||
print("example: run_gatt_with_adapters.py usb:0 E1:CA:72:48:C4:E8")
|
||||
print("Usage: run_gatt_with_adapters.py <transport-spec> client|server")
|
||||
print("example: run_gatt_with_adapters.py usb:0 F0:F1:F2:F3:F4:F5")
|
||||
return
|
||||
|
||||
async with await transport.open_transport(sys.argv[1]) as hci_transport:
|
||||
is_client = sys.argv[2] == "client"
|
||||
|
||||
# Create a device to manage the host
|
||||
device = Device.with_hci(
|
||||
"Bumble",
|
||||
hci.Address("F0:F1:F2:F3:F4:F5"),
|
||||
hci.Address(
|
||||
DEFAULT_CLIENT_ADDRESS if is_client else DEFAULT_SERVER_ADDRESS
|
||||
),
|
||||
hci_transport.source,
|
||||
hci_transport.sink,
|
||||
)
|
||||
|
||||
# Static characteristic with a bytes value.
|
||||
c1 = gatt.Characteristic(
|
||||
CHARACTERISTIC_UUID_BASE + "01",
|
||||
gatt.Characteristic.Properties.READ | gatt.Characteristic.Properties.WRITE,
|
||||
gatt.Characteristic.READABLE | gatt.Characteristic.WRITEABLE,
|
||||
b'hello',
|
||||
)
|
||||
|
||||
# Static characteristic with a string value.
|
||||
c2 = gatt.UTF8CharacteristicAdapter(
|
||||
gatt.Characteristic(
|
||||
CHARACTERISTIC_UUID_BASE + "02",
|
||||
gatt.Characteristic.Properties.READ
|
||||
| gatt.Characteristic.Properties.WRITE,
|
||||
gatt.Characteristic.READABLE | gatt.Characteristic.WRITEABLE,
|
||||
'hello',
|
||||
)
|
||||
)
|
||||
|
||||
# Static characteristic with a tuple value.
|
||||
c3 = gatt.PackedCharacteristicAdapter(
|
||||
gatt.Characteristic(
|
||||
CHARACTERISTIC_UUID_BASE + "03",
|
||||
gatt.Characteristic.Properties.READ
|
||||
| gatt.Characteristic.Properties.WRITE,
|
||||
gatt.Characteristic.READABLE | gatt.Characteristic.WRITEABLE,
|
||||
(1007, 1008, 1009),
|
||||
),
|
||||
">III",
|
||||
)
|
||||
|
||||
# Static characteristic with a named tuple value.
|
||||
c4 = gatt.MappedCharacteristicAdapter(
|
||||
gatt.Characteristic(
|
||||
CHARACTERISTIC_UUID_BASE + "04",
|
||||
gatt.Characteristic.Properties.READ
|
||||
| gatt.Characteristic.Properties.WRITE,
|
||||
gatt.Characteristic.READABLE | gatt.Characteristic.WRITEABLE,
|
||||
{"f1": 3007, "f2": 3008, "f3": 3009},
|
||||
),
|
||||
">III",
|
||||
["f1", "f2", "f3"],
|
||||
)
|
||||
|
||||
# Static characteristic with a serializable value.
|
||||
c5 = gatt.SerializableCharacteristicAdapter(
|
||||
gatt.Characteristic(
|
||||
CHARACTERISTIC_UUID_BASE + "05",
|
||||
gatt.Characteristic.Properties.READ
|
||||
| gatt.Characteristic.Properties.WRITE,
|
||||
gatt.Characteristic.READABLE | gatt.Characteristic.WRITEABLE,
|
||||
CustomSerializableClass(11, 12),
|
||||
),
|
||||
CustomSerializableClass,
|
||||
)
|
||||
|
||||
# Static characteristic with a delegated value.
|
||||
c6 = gatt.DelegatedCharacteristicAdapter(
|
||||
gatt.Characteristic(
|
||||
CHARACTERISTIC_UUID_BASE + "06",
|
||||
gatt.Characteristic.Properties.READ
|
||||
| gatt.Characteristic.Properties.WRITE,
|
||||
gatt.Characteristic.READABLE | gatt.Characteristic.WRITEABLE,
|
||||
CustomClass(1, 2),
|
||||
),
|
||||
encode=CustomClass.encode,
|
||||
decode=CustomClass.decode,
|
||||
)
|
||||
|
||||
# Dynamic characteristic with a bytes value.
|
||||
c7 = gatt.Characteristic(
|
||||
CHARACTERISTIC_UUID_BASE + "07",
|
||||
gatt.Characteristic.Properties.READ | gatt.Characteristic.Properties.WRITE,
|
||||
gatt.Characteristic.READABLE | gatt.Characteristic.WRITEABLE,
|
||||
gatt.CharacteristicValue(
|
||||
read=lambda connection: dynamic_read("bytes"),
|
||||
write=lambda connection, value: dynamic_write("bytes", value),
|
||||
),
|
||||
)
|
||||
|
||||
# Dynamic characteristic with a string value.
|
||||
c8 = gatt.UTF8CharacteristicAdapter(
|
||||
gatt.Characteristic(
|
||||
CHARACTERISTIC_UUID_BASE + "08",
|
||||
gatt.Characteristic.Properties.READ
|
||||
| gatt.Characteristic.Properties.WRITE,
|
||||
gatt.Characteristic.READABLE | gatt.Characteristic.WRITEABLE,
|
||||
gatt.CharacteristicValue(
|
||||
read=lambda connection: dynamic_read("string"),
|
||||
write=lambda connection, value: dynamic_write("string", value),
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
characteristics: List[
|
||||
Union[gatt.Characteristic, gatt.CharacteristicAdapter]
|
||||
] = [c1, c2, c3, c4, c5, c6, c7, c8]
|
||||
|
||||
# Listen for read and write events.
|
||||
for characteristic in characteristics:
|
||||
characteristic.on(
|
||||
"read",
|
||||
lambda _, value, c=characteristic: on_characteristic_read(c, value),
|
||||
)
|
||||
characteristic.on(
|
||||
"write",
|
||||
lambda _, value, c=characteristic: on_characteristic_write(c, value),
|
||||
)
|
||||
|
||||
device.add_service(gatt.Service(SERVICE_UUID, characteristics)) # type: ignore
|
||||
|
||||
# Get things going
|
||||
await device.power_on()
|
||||
|
||||
# Connect to a peer
|
||||
if len(sys.argv) > 2:
|
||||
await client(device, hci.Address(sys.argv[2]))
|
||||
if is_client:
|
||||
# Connect a client to a peer
|
||||
await client(device, hci.Address(DEFAULT_SERVER_ADDRESS))
|
||||
else:
|
||||
# Advertise so a peer can connect
|
||||
await device.start_advertising(auto_restart=True)
|
||||
|
||||
# Setup a server
|
||||
await server(device)
|
||||
|
||||
await hci_transport.source.wait_for_termination()
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user