add support for data type classes

This commit is contained in:
Gilles Boccon-Gibod
2025-08-29 13:16:07 -07:00
parent 6f73b736d7
commit 116dc9b319
24 changed files with 1775 additions and 467 deletions

View File

@@ -104,5 +104,8 @@
"python.testing.unittestEnabled": false, "python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true, "python.testing.pytestEnabled": true,
"python-envs.defaultEnvManager": "ms-python.python:system", "python-envs.defaultEnvManager": "ms-python.python:system",
"python-envs.pythonProjects": [] "python-envs.pythonProjects": [],
"nrf-connect.applications": [
"${workspaceFolder}/extras/zephyr/hci_usb"
]
} }

View File

@@ -39,7 +39,7 @@ import bumble.device
import bumble.logging import bumble.logging
import bumble.transport import bumble.transport
import bumble.utils import bumble.utils
from bumble import company_ids, core, gatt, hci from bumble import company_ids, core, data_types, gatt, hci
from bumble.audio import io as audio_io from bumble.audio import io as audio_io
from bumble.colors import color from bumble.colors import color
from bumble.profiles import bap, bass, le_audio, pbp from bumble.profiles import bap, bass, le_audio, pbp
@@ -859,21 +859,13 @@ async def run_transmit(
) )
broadcast_audio_announcement = bap.BroadcastAudioAnnouncement(broadcast_id) broadcast_audio_announcement = bap.BroadcastAudioAnnouncement(broadcast_id)
advertising_manufacturer_data = ( advertising_data_types: list[core.DataType] = [
b'' data_types.BroadcastName(broadcast_name)
if manufacturer_data is None ]
else bytes( if manufacturer_data is not None:
core.AdvertisingData( advertising_data_types.append(
[ data_types.ManufacturerSpecificData(*manufacturer_data)
(
core.AdvertisingData.MANUFACTURER_SPECIFIC_DATA,
struct.pack('<H', manufacturer_data[0])
+ manufacturer_data[1],
)
]
)
) )
)
advertising_set = await device.create_advertising_set( advertising_set = await device.create_advertising_set(
advertising_parameters=bumble.device.AdvertisingParameters( advertising_parameters=bumble.device.AdvertisingParameters(
@@ -885,12 +877,7 @@ async def run_transmit(
), ),
advertising_data=( advertising_data=(
broadcast_audio_announcement.get_advertising_data() broadcast_audio_announcement.get_advertising_data()
+ bytes( + bytes(core.AdvertisingData(advertising_data_types))
core.AdvertisingData(
[(core.AdvertisingData.BROADCAST_NAME, broadcast_name.encode())]
)
)
+ advertising_manufacturer_data
), ),
periodic_advertising_parameters=bumble.device.PeriodicAdvertisingParameters( periodic_advertising_parameters=bumble.device.PeriodicAdvertisingParameters(
periodic_advertising_interval_min=80, periodic_advertising_interval_min=80,

View File

@@ -37,7 +37,7 @@ import click
import bumble import bumble
import bumble.logging import bumble.logging
from bumble import utils from bumble import data_types, utils
from bumble.colors import color from bumble.colors import color
from bumble.core import AdvertisingData from bumble.core import AdvertisingData
from bumble.device import AdvertisingParameters, CisLink, Device, DeviceConfiguration from bumble.device import AdvertisingParameters, CisLink, Device, DeviceConfiguration
@@ -330,22 +330,13 @@ class Speaker:
advertising_data = bytes( advertising_data = bytes(
AdvertisingData( AdvertisingData(
[ [
( data_types.CompleteLocalName(device_config.name),
AdvertisingData.COMPLETE_LOCAL_NAME, data_types.Flags(
bytes(device_config.name, 'utf-8'), AdvertisingData.Flags.LE_GENERAL_DISCOVERABLE_MODE
| AdvertisingData.Flags.BR_EDR_NOT_SUPPORTED
), ),
( data_types.IncompleteListOf16BitServiceUUIDs(
AdvertisingData.FLAGS, [pacs.PublishedAudioCapabilitiesService.UUID]
bytes(
[
AdvertisingData.LE_GENERAL_DISCOVERABLE_MODE_FLAG
| AdvertisingData.BR_EDR_NOT_SUPPORTED_FLAG
]
),
),
(
AdvertisingData.INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS,
bytes(pacs.PublishedAudioCapabilitiesService.UUID),
), ),
] ]
) )

View File

@@ -23,6 +23,7 @@ import struct
import click import click
from prompt_toolkit.shortcuts import PromptSession from prompt_toolkit.shortcuts import PromptSession
from bumble import data_types
from bumble.a2dp import make_audio_sink_service_sdp_records from bumble.a2dp import make_audio_sink_service_sdp_records
from bumble.att import ( from bumble.att import (
ATT_INSUFFICIENT_AUTHENTICATION_ERROR, ATT_INSUFFICIENT_AUTHENTICATION_ERROR,
@@ -34,6 +35,7 @@ from bumble.core import (
UUID, UUID,
AdvertisingData, AdvertisingData,
Appearance, Appearance,
DataType,
PhysicalTransport, PhysicalTransport,
ProtocolError, ProtocolError,
) )
@@ -506,33 +508,21 @@ async def pair(
if mode == 'dual': if mode == 'dual':
flags |= AdvertisingData.Flags.SIMULTANEOUS_LE_BR_EDR_CAPABLE flags |= AdvertisingData.Flags.SIMULTANEOUS_LE_BR_EDR_CAPABLE
ad_structs = [ advertising_data_types: list[DataType] = [
( data_types.Flags(flags),
AdvertisingData.FLAGS, data_types.CompleteLocalName('Bumble'),
bytes([flags]),
),
(AdvertisingData.COMPLETE_LOCAL_NAME, 'Bumble'.encode()),
] ]
if service_uuids_16: if service_uuids_16:
ad_structs.append( advertising_data_types.append(
( data_types.IncompleteListOf16BitServiceUUIDs(service_uuids_16)
AdvertisingData.INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS,
b"".join(bytes(uuid) for uuid in service_uuids_16),
)
) )
if service_uuids_32: if service_uuids_32:
ad_structs.append( advertising_data_types.append(
( data_types.IncompleteListOf32BitServiceUUIDs(service_uuids_32)
AdvertisingData.INCOMPLETE_LIST_OF_32_BIT_SERVICE_CLASS_UUIDS,
b"".join(bytes(uuid) for uuid in service_uuids_32),
)
) )
if service_uuids_128: if service_uuids_128:
ad_structs.append( advertising_data_types.append(
( data_types.IncompleteListOf128BitServiceUUIDs(service_uuids_128)
AdvertisingData.INCOMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS,
b"".join(bytes(uuid) for uuid in service_uuids_128),
)
) )
if advertise_appearance: if advertise_appearance:
@@ -559,13 +549,10 @@ async def pair(
advertise_appearance_int = int( advertise_appearance_int = int(
Appearance(category_enum, subcategory_enum) Appearance(category_enum, subcategory_enum)
) )
ad_structs.append( advertising_data_types.append(
( data_types.Appearance(category_enum, subcategory_enum)
AdvertisingData.APPEARANCE,
struct.pack('<H', advertise_appearance_int),
)
) )
device.advertising_data = bytes(AdvertisingData(ad_structs)) device.advertising_data = bytes(AdvertisingData(advertising_data_types))
await device.start_advertising( await device.start_advertising(
auto_restart=True, auto_restart=True,
own_address_type=( own_address_type=(

View File

@@ -20,6 +20,7 @@ import asyncio
import click import click
import bumble.logging import bumble.logging
from bumble import data_types
from bumble.colors import color from bumble.colors import color
from bumble.device import Advertisement, Device from bumble.device import Advertisement, Device
from bumble.hci import HCI_LE_1M_PHY, HCI_LE_CODED_PHY, Address, HCI_Constant from bumble.hci import HCI_LE_1M_PHY, HCI_LE_CODED_PHY, Address, HCI_Constant
@@ -94,13 +95,22 @@ class AdvertisementPrinter:
else: else:
phy_info = '' phy_info = ''
details = separator.join(
[
data_type.to_string(use_label=True)
for data_type in data_types.data_types_from_advertising_data(
advertisement.data
)
]
)
print( print(
f'>>> {color(address, address_color)} ' f'>>> {color(address, address_color)} '
f'[{color(address_type_string, type_color)}]{address_qualifier}' f'[{color(address_type_string, type_color)}]{address_qualifier}'
f'{resolution_qualifier}:{separator}' f'{resolution_qualifier}:{separator}'
f'{phy_info}' f'{phy_info}'
f'RSSI:{advertisement.rssi:4} {rssi_bar}{separator}' f'RSSI:{advertisement.rssi:4} {rssi_bar}{separator}'
f'{advertisement.data.to_string(separator)}\n' f'{details}\n'
) )
def on_advertisement(self, advertisement): def on_advertisement(self, advertisement):

File diff suppressed because it is too large Load Diff

1018
bumble/data_types.py Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -45,7 +45,18 @@ from typing import (
from typing_extensions import Self from typing_extensions import Self
from bumble import core, gatt_client, gatt_server, hci, l2cap, pairing, sdp, smp, utils from bumble import (
core,
data_types,
gatt_client,
gatt_server,
hci,
l2cap,
pairing,
sdp,
smp,
utils,
)
from bumble.att import ATT_CID, ATT_DEFAULT_MTU, ATT_PDU from bumble.att import ATT_CID, ATT_DEFAULT_MTU, ATT_PDU
from bumble.colors import color from bumble.colors import color
from bumble.core import ( from bumble.core import (
@@ -2049,9 +2060,7 @@ class DeviceConfiguration:
connectable: bool = True connectable: bool = True
discoverable: bool = True discoverable: bool = True
advertising_data: bytes = bytes( advertising_data: bytes = bytes(
AdvertisingData( AdvertisingData([data_types.CompleteLocalName(DEVICE_DEFAULT_NAME)])
[(AdvertisingData.COMPLETE_LOCAL_NAME, bytes(DEVICE_DEFAULT_NAME, 'utf-8'))]
)
) )
irk: bytes = bytes(16) # This really must be changed for any level of security irk: bytes = bytes(16) # This really must be changed for any level of security
keystore: Optional[str] = None keystore: Optional[str] = None
@@ -2095,9 +2104,7 @@ class DeviceConfiguration:
self.advertising_data = bytes.fromhex(advertising_data) self.advertising_data = bytes.fromhex(advertising_data)
elif name is not None: elif name is not None:
self.advertising_data = bytes( self.advertising_data = bytes(
AdvertisingData( AdvertisingData([data_types.CompleteLocalName(self.name)])
[(AdvertisingData.COMPLETE_LOCAL_NAME, bytes(self.name, 'utf-8'))]
)
) )
# Load scan response data # Load scan response data
@@ -3544,14 +3551,7 @@ class Device(utils.CompositeEventEmitter):
# Synthesize an inquiry response if none is set already # Synthesize an inquiry response if none is set already
if self.inquiry_response is None: if self.inquiry_response is None:
self.inquiry_response = bytes( self.inquiry_response = bytes(
AdvertisingData( AdvertisingData([data_types.CompleteLocalName(self.name)])
[
(
AdvertisingData.COMPLETE_LOCAL_NAME,
bytes(self.name, 'utf-8'),
)
]
)
) )
# Update the controller # Update the controller

View File

@@ -2135,6 +2135,7 @@ class Address:
if len(address) == 12 + 5: if len(address) == 12 + 5:
# Form with ':' separators # Form with ':' separators
address = address.replace(':', '') address = address.replace(':', '')
self.address_bytes = bytes(reversed(bytes.fromhex(address))) self.address_bytes = bytes(reversed(bytes.fromhex(address)))
if len(self.address_bytes) != 6: if len(self.address_bytes) != 6:

View File

@@ -21,7 +21,7 @@ import logging
import struct import struct
from typing import Any, Callable, Optional, Union from typing import Any, Callable, Optional, Union
from bumble import gatt, gatt_client, l2cap, utils from bumble import data_types, gatt, gatt_client, l2cap, utils
from bumble.core import AdvertisingData from bumble.core import AdvertisingData
from bumble.device import Connection, Device from bumble.device import Connection, Device
@@ -185,12 +185,11 @@ class AshaService(gatt.TemplateService):
return bytes( return bytes(
AdvertisingData( AdvertisingData(
[ [
( data_types.ServiceData16BitUUID(
AdvertisingData.SERVICE_DATA_16_BIT_UUID, gatt.GATT_ASHA_SERVICE,
bytes(gatt.GATT_ASHA_SERVICE) bytes([self.protocol_version, self.capability])
+ bytes([self.protocol_version, self.capability])
+ self.hisyncid[:4], + self.hisyncid[:4],
), )
] ]
) )
) )

View File

@@ -27,7 +27,7 @@ from collections.abc import Sequence
from typing_extensions import Self from typing_extensions import Self
from bumble import core, gatt, hci, utils from bumble import core, data_types, gatt, hci, utils
from bumble.profiles import le_audio from bumble.profiles import le_audio
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@@ -257,11 +257,10 @@ class UnicastServerAdvertisingData:
return bytes( return bytes(
core.AdvertisingData( core.AdvertisingData(
[ [
( data_types.ServiceData16BitUUID(
core.AdvertisingData.SERVICE_DATA_16_BIT_UUID, gatt.GATT_AUDIO_STREAM_CONTROL_SERVICE,
struct.pack( struct.pack(
'<2sBIB', '<BIB',
bytes(gatt.GATT_AUDIO_STREAM_CONTROL_SERVICE),
self.announcement_type, self.announcement_type,
self.available_audio_contexts, self.available_audio_contexts,
len(self.metadata), len(self.metadata),
@@ -490,12 +489,8 @@ class BroadcastAudioAnnouncement:
return bytes( return bytes(
core.AdvertisingData( core.AdvertisingData(
[ [
( data_types.ServiceData16BitUUID(
core.AdvertisingData.SERVICE_DATA_16_BIT_UUID, gatt.GATT_BROADCAST_AUDIO_ANNOUNCEMENT_SERVICE, bytes(self)
(
bytes(gatt.GATT_BROADCAST_AUDIO_ANNOUNCEMENT_SERVICE)
+ bytes(self)
),
) )
] ]
) )
@@ -607,12 +602,8 @@ class BasicAudioAnnouncement:
return bytes( return bytes(
core.AdvertisingData( core.AdvertisingData(
[ [
( data_types.ServiceData16BitUUID(
core.AdvertisingData.SERVICE_DATA_16_BIT_UUID, gatt.GATT_BASIC_AUDIO_ANNOUNCEMENT_SERVICE, bytes(self)
(
bytes(gatt.GATT_BASIC_AUDIO_ANNOUNCEMENT_SERVICE)
+ bytes(self)
),
) )
] ]
) )

View File

@@ -21,6 +21,7 @@ import struct
import sys import sys
import bumble.logging import bumble.logging
from bumble import data_types
from bumble.core import AdvertisingData from bumble.core import AdvertisingData
from bumble.device import Device from bumble.device import Device
from bumble.profiles.battery_service import BatteryService from bumble.profiles.battery_service import BatteryService
@@ -47,15 +48,14 @@ async def main() -> None:
device.advertising_data = bytes( device.advertising_data = bytes(
AdvertisingData( AdvertisingData(
[ [
( data_types.CompleteLocalName('Bumble Battery'),
AdvertisingData.COMPLETE_LOCAL_NAME, data_types.IncompleteListOf16BitServiceUUIDs(
bytes('Bumble Battery', 'utf-8'), [battery_service.uuid]
), ),
( data_types.Appearance(
AdvertisingData.INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS, data_types.Appearance.Category.WEARABLE_AUDIO_DEVICE,
bytes(battery_service.uuid), data_types.Appearance.WearableAudioDeviceSubcategory.EARBUD,
), ),
(AdvertisingData.APPEARANCE, struct.pack('<H', 0x0340)),
] ]
) )
) )

View File

@@ -20,6 +20,7 @@ import struct
import sys import sys
import bumble.logging import bumble.logging
from bumble import data_types
from bumble.core import AdvertisingData from bumble.core import AdvertisingData
from bumble.device import Device from bumble.device import Device
from bumble.profiles.device_information_service import DeviceInformationService from bumble.profiles.device_information_service import DeviceInformationService
@@ -53,11 +54,11 @@ async def main() -> None:
device.advertising_data = bytes( device.advertising_data = bytes(
AdvertisingData( AdvertisingData(
[ [
( data_types.CompleteLocalName('Bumble Device'),
AdvertisingData.COMPLETE_LOCAL_NAME, data_types.Appearance(
bytes('Bumble Device', 'utf-8'), data_types.Appearance.Category.HEART_RATE_SENSOR,
data_types.Appearance.HeartRateSensorSubcategory.GENERIC_HEART_RATE_SENSOR,
), ),
(AdvertisingData.APPEARANCE, struct.pack('<H', 0x0340)),
] ]
) )
) )

View File

@@ -24,6 +24,7 @@ import sys
import time import time
import bumble.logging import bumble.logging
from bumble import data_types
from bumble.core import AdvertisingData from bumble.core import AdvertisingData
from bumble.device import Device from bumble.device import Device
from bumble.profiles.device_information_service import DeviceInformationService from bumble.profiles.device_information_service import DeviceInformationService
@@ -88,15 +89,14 @@ async def main() -> None:
device.advertising_data = bytes( device.advertising_data = bytes(
AdvertisingData( AdvertisingData(
[ [
( data_types.CompleteLocalName('Bumble Heart'),
AdvertisingData.COMPLETE_LOCAL_NAME, data_types.IncompleteListOf16BitServiceUUIDs(
bytes('Bumble Heart', 'utf-8'), [heart_rate_service.uuid]
), ),
( data_types.Appearance(
AdvertisingData.INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS, data_types.Appearance.Category.HEART_RATE_SENSOR,
bytes(heart_rate_service.uuid), data_types.Appearance.HeartRateSensorSubcategory.GENERIC_HEART_RATE_SENSOR,
), ),
(AdvertisingData.APPEARANCE, struct.pack('<H', 0x0340)),
] ]
) )
) )

View File

@@ -23,6 +23,7 @@ import sys
import websockets import websockets
import bumble.logging import bumble.logging
from bumble import data_types
from bumble.colors import color from bumble.colors import color
from bumble.core import AdvertisingData from bumble.core import AdvertisingData
from bumble.device import Connection, Device, Peer from bumble.device import Connection, Device, Peer
@@ -341,16 +342,18 @@ async def keyboard_device(device, command):
device.advertising_data = bytes( device.advertising_data = bytes(
AdvertisingData( AdvertisingData(
[ [
( data_types.CompleteLocalName('Bumble Keyboard'),
AdvertisingData.COMPLETE_LOCAL_NAME, data_types.IncompleteListOf16BitServiceUUIDs(
bytes('Bumble Keyboard', 'utf-8'), [GATT_HUMAN_INTERFACE_DEVICE_SERVICE]
), ),
( data_types.Appearance(
AdvertisingData.INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS, data_types.Appearance.Category.HUMAN_INTERFACE_DEVICE,
bytes(GATT_HUMAN_INTERFACE_DEVICE_SERVICE), data_types.Appearance.HumanInterfaceDeviceSubcategory.KEYBOARD,
),
data_types.Flags(
AdvertisingData.Flags.LE_LIMITED_DISCOVERABLE_MODE
| AdvertisingData.Flags.BR_EDR_NOT_SUPPORTED
), ),
(AdvertisingData.APPEARANCE, struct.pack('<H', 0x03C1)),
(AdvertisingData.FLAGS, bytes([0x05])),
] ]
) )
) )

View File

@@ -20,6 +20,7 @@ import struct
import sys import sys
import bumble.logging import bumble.logging
from bumble import data_types
from bumble.core import AdvertisingData from bumble.core import AdvertisingData
from bumble.device import AdvertisingType, Device from bumble.device import AdvertisingType, Device
from bumble.hci import Address from bumble.hci import Address
@@ -60,7 +61,10 @@ async def main() -> None:
device.scan_response_data = bytes( device.scan_response_data = bytes(
AdvertisingData( AdvertisingData(
[ [
(AdvertisingData.APPEARANCE, struct.pack('<H', 0x0340)), data_types.Appearance(
data_types.Appearance.Category.HEART_RATE_SENSOR,
data_types.Appearance.HeartRateSensorSubcategory.GENERIC_HEART_RATE_SENSOR,
)
] ]
) )
) )

View File

@@ -23,7 +23,7 @@ from typing import Optional
import websockets import websockets
import bumble.logging import bumble.logging
from bumble import decoder, gatt from bumble import data_types, decoder, gatt
from bumble.core import AdvertisingData from bumble.core import AdvertisingData
from bumble.device import AdvertisingParameters, Device from bumble.device import AdvertisingParameters, Device
from bumble.profiles import asha from bumble.profiles import asha
@@ -78,14 +78,10 @@ async def main() -> None:
bytes( bytes(
AdvertisingData( AdvertisingData(
[ [
( data_types.CompleteLocalName(device.name),
AdvertisingData.COMPLETE_LOCAL_NAME, data_types.Flags(AdvertisingData.Flags(0x06)),
bytes(device.name, 'utf-8'), data_types.IncompleteListOf16BitServiceUUIDs(
), [gatt.GATT_ASHA_SERVICE]
(AdvertisingData.FLAGS, bytes([0x06])),
(
AdvertisingData.INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS,
bytes(gatt.GATT_ASHA_SERVICE),
), ),
] ]
) )

View File

@@ -20,6 +20,7 @@ import secrets
import sys import sys
import bumble.logging import bumble.logging
from bumble import data_types
from bumble.core import AdvertisingData from bumble.core import AdvertisingData
from bumble.device import Device from bumble.device import Device
from bumble.hci import Address from bumble.hci import Address
@@ -66,23 +67,14 @@ async def main() -> None:
bytes( bytes(
AdvertisingData( AdvertisingData(
[ [
( data_types.CompleteLocalName(f'Bumble LE Audio-{i}'),
AdvertisingData.COMPLETE_LOCAL_NAME, data_types.Flags(
bytes(f'Bumble LE Audio-{i}', 'utf-8'), AdvertisingData.LE_GENERAL_DISCOVERABLE_MODE_FLAG
| AdvertisingData.BR_EDR_HOST_FLAG
| AdvertisingData.BR_EDR_CONTROLLER_FLAG
), ),
( data_types.IncompleteListOf16BitServiceUUIDs(
AdvertisingData.FLAGS, [CoordinatedSetIdentificationService.UUID]
bytes(
[
AdvertisingData.LE_GENERAL_DISCOVERABLE_MODE_FLAG
| AdvertisingData.BR_EDR_HOST_FLAG
| AdvertisingData.BR_EDR_CONTROLLER_FLAG
]
),
),
(
AdvertisingData.INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS,
bytes(CoordinatedSetIdentificationService.UUID),
), ),
] ]
) )

View File

@@ -19,6 +19,7 @@ import asyncio
import sys import sys
import bumble.logging import bumble.logging
from bumble import data_types
from bumble.core import AdvertisingData from bumble.core import AdvertisingData
from bumble.device import Device from bumble.device import Device
from bumble.profiles.hap import ( from bumble.profiles.hap import (
@@ -71,23 +72,14 @@ async def main() -> None:
advertising_data = bytes( advertising_data = bytes(
AdvertisingData( AdvertisingData(
[ [
( data_types.CompleteLocalName('Bumble HearingAccessService'),
AdvertisingData.COMPLETE_LOCAL_NAME, data_types.Flags(
bytes('Bumble HearingAccessService', 'utf-8'), AdvertisingData.LE_GENERAL_DISCOVERABLE_MODE_FLAG
| AdvertisingData.BR_EDR_HOST_FLAG
| AdvertisingData.BR_EDR_CONTROLLER_FLAG
), ),
( data_types.IncompleteListOf16BitServiceUUIDs(
AdvertisingData.FLAGS, [HearingAccessService.UUID]
bytes(
[
AdvertisingData.LE_GENERAL_DISCOVERABLE_MODE_FLAG
| AdvertisingData.BR_EDR_HOST_FLAG
| AdvertisingData.BR_EDR_CONTROLLER_FLAG
]
),
),
(
AdvertisingData.INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS,
bytes(HearingAccessService.UUID),
), ),
] ]
) )

View File

@@ -23,6 +23,7 @@ from typing import Optional
import websockets import websockets
import bumble.logging import bumble.logging
from bumble import data_types
from bumble.core import AdvertisingData from bumble.core import AdvertisingData
from bumble.device import ( from bumble.device import (
AdvertisingEventProperties, AdvertisingEventProperties,
@@ -106,17 +107,10 @@ async def main() -> None:
advertising_data = bytes( advertising_data = bytes(
AdvertisingData( AdvertisingData(
[ [
( data_types.CompleteLocalName('Bumble LE Audio'),
AdvertisingData.COMPLETE_LOCAL_NAME, data_types.Flags(AdvertisingData.LE_GENERAL_DISCOVERABLE_MODE_FLAG),
bytes('Bumble LE Audio', 'utf-8'), data_types.IncompleteListOf16BitServiceUUIDs(
), [PublishedAudioCapabilitiesService.UUID]
(
AdvertisingData.FLAGS,
bytes([AdvertisingData.LE_GENERAL_DISCOVERABLE_MODE_FLAG]),
),
(
AdvertisingData.INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS,
bytes(PublishedAudioCapabilitiesService.UUID),
), ),
] ]
) )

View File

@@ -24,6 +24,7 @@ import struct
import sys import sys
import bumble.logging import bumble.logging
from bumble import data_types
from bumble.core import AdvertisingData from bumble.core import AdvertisingData
from bumble.device import Device from bumble.device import Device
from bumble.hci import CodecID, CodingFormat, HCI_IsoDataPacket from bumble.hci import CodecID, CodingFormat, HCI_IsoDataPacket
@@ -111,23 +112,14 @@ async def main() -> None:
bytes( bytes(
AdvertisingData( AdvertisingData(
[ [
( data_types.CompleteLocalName('Bumble LE Audio'),
AdvertisingData.COMPLETE_LOCAL_NAME, data_types.Flags(
bytes('Bumble LE Audio', 'utf-8'), AdvertisingData.LE_GENERAL_DISCOVERABLE_MODE_FLAG
| AdvertisingData.BR_EDR_HOST_FLAG
| AdvertisingData.BR_EDR_CONTROLLER_FLAG
), ),
( data_types.IncompleteListOf16BitServiceUUIDs(
AdvertisingData.FLAGS, [PublishedAudioCapabilitiesService.UUID]
bytes(
[
AdvertisingData.LE_GENERAL_DISCOVERABLE_MODE_FLAG
| AdvertisingData.BR_EDR_HOST_FLAG
| AdvertisingData.BR_EDR_CONTROLLER_FLAG
]
),
),
(
AdvertisingData.INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS,
bytes(PublishedAudioCapabilitiesService.UUID),
), ),
] ]
) )

View File

@@ -24,6 +24,7 @@ from typing import Optional
import websockets import websockets
import bumble.logging import bumble.logging
from bumble import data_types
from bumble.core import AdvertisingData from bumble.core import AdvertisingData
from bumble.device import AdvertisingEventProperties, AdvertisingParameters, Device from bumble.device import AdvertisingEventProperties, AdvertisingParameters, Device
from bumble.hci import CodecID, CodingFormat, OwnAddressType from bumble.hci import CodecID, CodingFormat, OwnAddressType
@@ -127,23 +128,14 @@ async def main() -> None:
bytes( bytes(
AdvertisingData( AdvertisingData(
[ [
( data_types.CompleteLocalName('Bumble LE Audio'),
AdvertisingData.COMPLETE_LOCAL_NAME, data_types.Flags(
bytes('Bumble LE Audio', 'utf-8'), AdvertisingData.LE_GENERAL_DISCOVERABLE_MODE_FLAG
| AdvertisingData.BR_EDR_HOST_FLAG
| AdvertisingData.BR_EDR_CONTROLLER_FLAG
), ),
( data_types.IncompleteListOf16BitServiceUUIDs(
AdvertisingData.FLAGS, [PublishedAudioCapabilitiesService.UUID]
bytes(
[
AdvertisingData.LE_GENERAL_DISCOVERABLE_MODE_FLAG
| AdvertisingData.BR_EDR_HOST_FLAG
| AdvertisingData.BR_EDR_CONTROLLER_FLAG
]
),
),
(
AdvertisingData.INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS,
bytes(PublishedAudioCapabilitiesService.UUID),
), ),
] ]
) )

View File

@@ -16,7 +16,13 @@
# Imports # Imports
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
from bumble.core import UUID, AdvertisingData, Appearance, get_dict_key_by_value from bumble.core import (
UUID,
AdvertisingData,
Appearance,
ClassOfDevice,
get_dict_key_by_value,
)
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@@ -93,6 +99,24 @@ def test_appearance() -> None:
assert int(a) == 0x3333 assert int(a) == 0x3333
# -----------------------------------------------------------------------------
def test_class_of_device() -> None:
c1 = ClassOfDevice(
ClassOfDevice.MajorServiceClasses.AUDIO
| ClassOfDevice.MajorServiceClasses.RENDERING,
ClassOfDevice.MajorDeviceClass.AUDIO_VIDEO,
ClassOfDevice.AudioVideoMinorDeviceClass.CAMCORDER,
)
assert str(c1) == "ClassOfDevice(RENDERING|AUDIO,AUDIO_VIDEO/CAMCORDER)"
c2 = ClassOfDevice(
ClassOfDevice.MajorServiceClasses.AUDIO,
ClassOfDevice.MajorDeviceClass.AUDIO_VIDEO,
0x123,
)
assert str(c2) == "ClassOfDevice(AUDIO,AUDIO_VIDEO/0x123)"
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
if __name__ == '__main__': if __name__ == '__main__':
test_ad_data() test_ad_data()

View File

@@ -17,6 +17,7 @@
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
import struct import struct
from bumble import data_types
from bumble.core import AdvertisingData from bumble.core import AdvertisingData
from bumble.device import Device from bumble.device import Device
from bumble.hci import HCI_Reset_Command from bumble.hci import HCI_Reset_Command
@@ -65,24 +66,18 @@ class HeartRateMonitor:
self.device.advertising_data = bytes( self.device.advertising_data = bytes(
AdvertisingData( AdvertisingData(
[ [
( data_types.Flags(
AdvertisingData.FLAGS, AdvertisingData.Flags.LE_GENERAL_DISCOVERABLE_MODE
bytes( | AdvertisingData.Flags.BR_EDR_NOT_SUPPORTED
[
AdvertisingData.LE_GENERAL_DISCOVERABLE_MODE_FLAG
| AdvertisingData.BR_EDR_NOT_SUPPORTED_FLAG
]
),
), ),
( data_types.CompleteLocalName('Bumble Heart'),
AdvertisingData.COMPLETE_LOCAL_NAME, data_types.IncompleteListOf16BitServiceUUIDs(
bytes('Bumble Heart', 'utf-8'), [self.heart_rate_service.uuid]
), ),
( data_types.Appearance(
AdvertisingData.INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS, data_types.Appearance.Category.HEART_RATE_SENSOR,
bytes(self.heart_rate_service.uuid), data_types.Appearance.HeartRateSensorSubcategory.GENERIC_HEART_RATE_SENSOR,
), ),
(AdvertisingData.APPEARANCE, struct.pack('<H', 0x0340)),
] ]
) )
) )