bumble 0.0.207__py3-none-any.whl → 0.0.209__py3-none-any.whl
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.
- bumble/_version.py +9 -4
- bumble/apps/auracast.py +29 -35
- bumble/apps/bench.py +13 -10
- bumble/apps/console.py +19 -12
- bumble/apps/gg_bridge.py +1 -1
- bumble/att.py +61 -39
- bumble/controller.py +7 -8
- bumble/core.py +306 -159
- bumble/device.py +127 -82
- bumble/gatt.py +25 -228
- bumble/gatt_adapters.py +374 -0
- bumble/gatt_client.py +38 -31
- bumble/gatt_server.py +5 -5
- bumble/hci.py +76 -71
- bumble/host.py +19 -8
- bumble/l2cap.py +2 -2
- bumble/link.py +2 -2
- bumble/pairing.py +5 -5
- bumble/pandora/host.py +19 -23
- bumble/pandora/security.py +2 -3
- bumble/pandora/utils.py +2 -2
- bumble/profiles/aics.py +33 -23
- bumble/profiles/ancs.py +514 -0
- bumble/profiles/ascs.py +2 -1
- bumble/profiles/asha.py +11 -9
- bumble/profiles/bass.py +8 -5
- bumble/profiles/battery_service.py +13 -3
- bumble/profiles/device_information_service.py +16 -14
- bumble/profiles/gap.py +12 -8
- bumble/profiles/gatt_service.py +1 -0
- bumble/profiles/gmap.py +16 -11
- bumble/profiles/hap.py +8 -6
- bumble/profiles/heart_rate_service.py +20 -4
- bumble/profiles/mcp.py +11 -9
- bumble/profiles/pacs.py +37 -24
- bumble/profiles/tmap.py +6 -4
- bumble/profiles/vcs.py +6 -5
- bumble/profiles/vocs.py +49 -41
- bumble/smp.py +3 -3
- bumble/transport/usb.py +1 -3
- bumble/utils.py +10 -0
- {bumble-0.0.207.dist-info → bumble-0.0.209.dist-info}/METADATA +3 -3
- {bumble-0.0.207.dist-info → bumble-0.0.209.dist-info}/RECORD +47 -45
- {bumble-0.0.207.dist-info → bumble-0.0.209.dist-info}/WHEEL +1 -1
- {bumble-0.0.207.dist-info → bumble-0.0.209.dist-info}/LICENSE +0 -0
- {bumble-0.0.207.dist-info → bumble-0.0.209.dist-info}/entry_points.txt +0 -0
- {bumble-0.0.207.dist-info → bumble-0.0.209.dist-info}/top_level.txt +0 -0
bumble/core.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2021-
|
|
1
|
+
# Copyright 2021-2025 Google LLC
|
|
2
2
|
#
|
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
# you may not use this file except in compliance with the License.
|
|
@@ -16,10 +16,10 @@
|
|
|
16
16
|
# Imports
|
|
17
17
|
# -----------------------------------------------------------------------------
|
|
18
18
|
from __future__ import annotations
|
|
19
|
-
|
|
19
|
+
|
|
20
20
|
import enum
|
|
21
21
|
import struct
|
|
22
|
-
from typing import
|
|
22
|
+
from typing import cast, overload, Literal, Union, Optional
|
|
23
23
|
from typing_extensions import Self
|
|
24
24
|
|
|
25
25
|
from bumble.company_ids import COMPANY_IDENTIFIERS
|
|
@@ -31,11 +31,12 @@ from bumble.utils import OpenIntEnum
|
|
|
31
31
|
# -----------------------------------------------------------------------------
|
|
32
32
|
# fmt: off
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
class PhysicalTransport(enum.IntEnum):
|
|
35
|
+
BR_EDR = 0
|
|
36
|
+
LE = 1
|
|
36
37
|
|
|
37
|
-
BT_BR_EDR_TRANSPORT =
|
|
38
|
-
BT_LE_TRANSPORT =
|
|
38
|
+
BT_BR_EDR_TRANSPORT = PhysicalTransport.BR_EDR
|
|
39
|
+
BT_LE_TRANSPORT = PhysicalTransport.LE
|
|
39
40
|
|
|
40
41
|
|
|
41
42
|
# fmt: on
|
|
@@ -57,7 +58,7 @@ def bit_flags_to_strings(bits, bit_flag_names):
|
|
|
57
58
|
return names
|
|
58
59
|
|
|
59
60
|
|
|
60
|
-
def name_or_number(dictionary:
|
|
61
|
+
def name_or_number(dictionary: dict[int, str], number: int, width: int = 2) -> str:
|
|
61
62
|
name = dictionary.get(number)
|
|
62
63
|
if name is not None:
|
|
63
64
|
return name
|
|
@@ -200,7 +201,7 @@ class UUID:
|
|
|
200
201
|
'''
|
|
201
202
|
|
|
202
203
|
BASE_UUID = bytes.fromhex('00001000800000805F9B34FB')[::-1] # little-endian
|
|
203
|
-
UUIDS:
|
|
204
|
+
UUIDS: list[UUID] = [] # Registry of all instances created
|
|
204
205
|
|
|
205
206
|
uuid_bytes: bytes
|
|
206
207
|
name: Optional[str]
|
|
@@ -259,11 +260,11 @@ class UUID:
|
|
|
259
260
|
return cls.from_bytes(struct.pack('<I', uuid_32), name)
|
|
260
261
|
|
|
261
262
|
@classmethod
|
|
262
|
-
def parse_uuid(cls, uuid_as_bytes: bytes, offset: int) ->
|
|
263
|
+
def parse_uuid(cls, uuid_as_bytes: bytes, offset: int) -> tuple[int, UUID]:
|
|
263
264
|
return len(uuid_as_bytes), cls.from_bytes(uuid_as_bytes[offset:])
|
|
264
265
|
|
|
265
266
|
@classmethod
|
|
266
|
-
def parse_uuid_2(cls, uuid_as_bytes: bytes, offset: int) ->
|
|
267
|
+
def parse_uuid_2(cls, uuid_as_bytes: bytes, offset: int) -> tuple[int, UUID]:
|
|
267
268
|
return offset + 2, cls.from_bytes(uuid_as_bytes[offset : offset + 2])
|
|
268
269
|
|
|
269
270
|
def to_bytes(self, force_128: bool = False) -> bytes:
|
|
@@ -1280,13 +1281,13 @@ class Appearance:
|
|
|
1280
1281
|
# Advertising Data
|
|
1281
1282
|
# -----------------------------------------------------------------------------
|
|
1282
1283
|
AdvertisingDataObject = Union[
|
|
1283
|
-
|
|
1284
|
-
|
|
1284
|
+
list[UUID],
|
|
1285
|
+
tuple[UUID, bytes],
|
|
1285
1286
|
bytes,
|
|
1286
1287
|
str,
|
|
1287
1288
|
int,
|
|
1288
|
-
|
|
1289
|
-
|
|
1289
|
+
tuple[int, int],
|
|
1290
|
+
tuple[int, bytes],
|
|
1290
1291
|
Appearance,
|
|
1291
1292
|
]
|
|
1292
1293
|
|
|
@@ -1295,116 +1296,116 @@ class AdvertisingData:
|
|
|
1295
1296
|
# fmt: off
|
|
1296
1297
|
# pylint: disable=line-too-long
|
|
1297
1298
|
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1299
|
+
class Type(OpenIntEnum):
|
|
1300
|
+
FLAGS = 0x01
|
|
1301
|
+
INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS = 0x02
|
|
1302
|
+
COMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS = 0x03
|
|
1303
|
+
INCOMPLETE_LIST_OF_32_BIT_SERVICE_CLASS_UUIDS = 0x04
|
|
1304
|
+
COMPLETE_LIST_OF_32_BIT_SERVICE_CLASS_UUIDS = 0x05
|
|
1305
|
+
INCOMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS = 0x06
|
|
1306
|
+
COMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS = 0x07
|
|
1307
|
+
SHORTENED_LOCAL_NAME = 0x08
|
|
1308
|
+
COMPLETE_LOCAL_NAME = 0x09
|
|
1309
|
+
TX_POWER_LEVEL = 0x0A
|
|
1310
|
+
CLASS_OF_DEVICE = 0x0D
|
|
1311
|
+
SIMPLE_PAIRING_HASH_C = 0x0E
|
|
1312
|
+
SIMPLE_PAIRING_HASH_C_192 = 0x0E
|
|
1313
|
+
SIMPLE_PAIRING_RANDOMIZER_R = 0x0F
|
|
1314
|
+
SIMPLE_PAIRING_RANDOMIZER_R_192 = 0x0F
|
|
1315
|
+
DEVICE_ID = 0x10
|
|
1316
|
+
SECURITY_MANAGER_TK_VALUE = 0x10
|
|
1317
|
+
SECURITY_MANAGER_OUT_OF_BAND_FLAGS = 0x11
|
|
1318
|
+
PERIPHERAL_CONNECTION_INTERVAL_RANGE = 0x12
|
|
1319
|
+
LIST_OF_16_BIT_SERVICE_SOLICITATION_UUIDS = 0x14
|
|
1320
|
+
LIST_OF_128_BIT_SERVICE_SOLICITATION_UUIDS = 0x15
|
|
1321
|
+
SERVICE_DATA_16_BIT_UUID = 0x16
|
|
1322
|
+
PUBLIC_TARGET_ADDRESS = 0x17
|
|
1323
|
+
RANDOM_TARGET_ADDRESS = 0x18
|
|
1324
|
+
APPEARANCE = 0x19
|
|
1325
|
+
ADVERTISING_INTERVAL = 0x1A
|
|
1326
|
+
LE_BLUETOOTH_DEVICE_ADDRESS = 0x1B
|
|
1327
|
+
LE_ROLE = 0x1C
|
|
1328
|
+
SIMPLE_PAIRING_HASH_C_256 = 0x1D
|
|
1329
|
+
SIMPLE_PAIRING_RANDOMIZER_R_256 = 0x1E
|
|
1330
|
+
LIST_OF_32_BIT_SERVICE_SOLICITATION_UUIDS = 0x1F
|
|
1331
|
+
SERVICE_DATA_32_BIT_UUID = 0x20
|
|
1332
|
+
SERVICE_DATA_128_BIT_UUID = 0x21
|
|
1333
|
+
LE_SECURE_CONNECTIONS_CONFIRMATION_VALUE = 0x22
|
|
1334
|
+
LE_SECURE_CONNECTIONS_RANDOM_VALUE = 0x23
|
|
1335
|
+
URI = 0x24
|
|
1336
|
+
INDOOR_POSITIONING = 0x25
|
|
1337
|
+
TRANSPORT_DISCOVERY_DATA = 0x26
|
|
1338
|
+
LE_SUPPORTED_FEATURES = 0x27
|
|
1339
|
+
CHANNEL_MAP_UPDATE_INDICATION = 0x28
|
|
1340
|
+
PB_ADV = 0x29
|
|
1341
|
+
MESH_MESSAGE = 0x2A
|
|
1342
|
+
MESH_BEACON = 0x2B
|
|
1343
|
+
BIGINFO = 0x2C
|
|
1344
|
+
BROADCAST_CODE = 0x2D
|
|
1345
|
+
RESOLVABLE_SET_IDENTIFIER = 0x2E
|
|
1346
|
+
ADVERTISING_INTERVAL_LONG = 0x2F
|
|
1347
|
+
BROADCAST_NAME = 0x30
|
|
1348
|
+
ENCRYPTED_ADVERTISING_DATA = 0x31
|
|
1349
|
+
PERIODIC_ADVERTISING_RESPONSE_TIMING_INFORMATION = 0x32
|
|
1350
|
+
ELECTRONIC_SHELF_LABEL = 0x34
|
|
1351
|
+
THREE_D_INFORMATION_DATA = 0x3D
|
|
1352
|
+
MANUFACTURER_SPECIFIC_DATA = 0xFF
|
|
1353
|
+
|
|
1354
|
+
# For backward-compatibility
|
|
1355
|
+
FLAGS = Type.FLAGS
|
|
1356
|
+
INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS = Type.INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS
|
|
1357
|
+
COMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS = Type.COMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS
|
|
1358
|
+
INCOMPLETE_LIST_OF_32_BIT_SERVICE_CLASS_UUIDS = Type.INCOMPLETE_LIST_OF_32_BIT_SERVICE_CLASS_UUIDS
|
|
1359
|
+
COMPLETE_LIST_OF_32_BIT_SERVICE_CLASS_UUIDS = Type.COMPLETE_LIST_OF_32_BIT_SERVICE_CLASS_UUIDS
|
|
1360
|
+
INCOMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS = Type.INCOMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS
|
|
1361
|
+
COMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS = Type.COMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS
|
|
1362
|
+
SHORTENED_LOCAL_NAME = Type.SHORTENED_LOCAL_NAME
|
|
1363
|
+
COMPLETE_LOCAL_NAME = Type.COMPLETE_LOCAL_NAME
|
|
1364
|
+
TX_POWER_LEVEL = Type.TX_POWER_LEVEL
|
|
1365
|
+
CLASS_OF_DEVICE = Type.CLASS_OF_DEVICE
|
|
1366
|
+
SIMPLE_PAIRING_HASH_C = Type.SIMPLE_PAIRING_HASH_C
|
|
1367
|
+
SIMPLE_PAIRING_HASH_C_192 = Type.SIMPLE_PAIRING_HASH_C_192
|
|
1368
|
+
SIMPLE_PAIRING_RANDOMIZER_R = Type.SIMPLE_PAIRING_RANDOMIZER_R
|
|
1369
|
+
SIMPLE_PAIRING_RANDOMIZER_R_192 = Type.SIMPLE_PAIRING_RANDOMIZER_R_192
|
|
1370
|
+
DEVICE_ID = Type.DEVICE_ID
|
|
1371
|
+
SECURITY_MANAGER_TK_VALUE = Type.SECURITY_MANAGER_TK_VALUE
|
|
1372
|
+
SECURITY_MANAGER_OUT_OF_BAND_FLAGS = Type.SECURITY_MANAGER_OUT_OF_BAND_FLAGS
|
|
1373
|
+
PERIPHERAL_CONNECTION_INTERVAL_RANGE = Type.PERIPHERAL_CONNECTION_INTERVAL_RANGE
|
|
1374
|
+
LIST_OF_16_BIT_SERVICE_SOLICITATION_UUIDS = Type.LIST_OF_16_BIT_SERVICE_SOLICITATION_UUIDS
|
|
1375
|
+
LIST_OF_128_BIT_SERVICE_SOLICITATION_UUIDS = Type.LIST_OF_128_BIT_SERVICE_SOLICITATION_UUIDS
|
|
1376
|
+
SERVICE_DATA = Type.SERVICE_DATA_16_BIT_UUID
|
|
1377
|
+
SERVICE_DATA_16_BIT_UUID = Type.SERVICE_DATA_16_BIT_UUID
|
|
1378
|
+
PUBLIC_TARGET_ADDRESS = Type.PUBLIC_TARGET_ADDRESS
|
|
1379
|
+
RANDOM_TARGET_ADDRESS = Type.RANDOM_TARGET_ADDRESS
|
|
1380
|
+
APPEARANCE = Type.APPEARANCE
|
|
1381
|
+
ADVERTISING_INTERVAL = Type.ADVERTISING_INTERVAL
|
|
1382
|
+
LE_BLUETOOTH_DEVICE_ADDRESS = Type.LE_BLUETOOTH_DEVICE_ADDRESS
|
|
1383
|
+
LE_ROLE = Type.LE_ROLE
|
|
1384
|
+
SIMPLE_PAIRING_HASH_C_256 = Type.SIMPLE_PAIRING_HASH_C_256
|
|
1385
|
+
SIMPLE_PAIRING_RANDOMIZER_R_256 = Type.SIMPLE_PAIRING_RANDOMIZER_R_256
|
|
1386
|
+
LIST_OF_32_BIT_SERVICE_SOLICITATION_UUIDS = Type.LIST_OF_32_BIT_SERVICE_SOLICITATION_UUIDS
|
|
1387
|
+
SERVICE_DATA_32_BIT_UUID = Type.SERVICE_DATA_32_BIT_UUID
|
|
1388
|
+
SERVICE_DATA_128_BIT_UUID = Type.SERVICE_DATA_128_BIT_UUID
|
|
1389
|
+
LE_SECURE_CONNECTIONS_CONFIRMATION_VALUE = Type.LE_SECURE_CONNECTIONS_CONFIRMATION_VALUE
|
|
1390
|
+
LE_SECURE_CONNECTIONS_RANDOM_VALUE = Type.LE_SECURE_CONNECTIONS_RANDOM_VALUE
|
|
1391
|
+
URI = Type.URI
|
|
1392
|
+
INDOOR_POSITIONING = Type.INDOOR_POSITIONING
|
|
1393
|
+
TRANSPORT_DISCOVERY_DATA = Type.TRANSPORT_DISCOVERY_DATA
|
|
1394
|
+
LE_SUPPORTED_FEATURES = Type.LE_SUPPORTED_FEATURES
|
|
1395
|
+
CHANNEL_MAP_UPDATE_INDICATION = Type.CHANNEL_MAP_UPDATE_INDICATION
|
|
1396
|
+
PB_ADV = Type.PB_ADV
|
|
1397
|
+
MESH_MESSAGE = Type.MESH_MESSAGE
|
|
1398
|
+
MESH_BEACON = Type.MESH_BEACON
|
|
1399
|
+
BIGINFO = Type.BIGINFO
|
|
1400
|
+
BROADCAST_CODE = Type.BROADCAST_CODE
|
|
1401
|
+
RESOLVABLE_SET_IDENTIFIER = Type.RESOLVABLE_SET_IDENTIFIER
|
|
1402
|
+
ADVERTISING_INTERVAL_LONG = Type.ADVERTISING_INTERVAL_LONG
|
|
1403
|
+
BROADCAST_NAME = Type.BROADCAST_NAME
|
|
1404
|
+
ENCRYPTED_ADVERTISING_DATA = Type.ENCRYPTED_ADVERTISING_DATA
|
|
1405
|
+
PERIODIC_ADVERTISING_RESPONSE_TIMING_INFORMATION = Type.PERIODIC_ADVERTISING_RESPONSE_TIMING_INFORMATION
|
|
1406
|
+
ELECTRONIC_SHELF_LABEL = Type.ELECTRONIC_SHELF_LABEL
|
|
1407
|
+
THREE_D_INFORMATION_DATA = Type.THREE_D_INFORMATION_DATA
|
|
1408
|
+
MANUFACTURER_SPECIFIC_DATA = Type.MANUFACTURER_SPECIFIC_DATA
|
|
1408
1409
|
|
|
1409
1410
|
LE_LIMITED_DISCOVERABLE_MODE_FLAG = 0x01
|
|
1410
1411
|
LE_GENERAL_DISCOVERABLE_MODE_FLAG = 0x02
|
|
@@ -1412,12 +1413,12 @@ class AdvertisingData:
|
|
|
1412
1413
|
BR_EDR_CONTROLLER_FLAG = 0x08
|
|
1413
1414
|
BR_EDR_HOST_FLAG = 0x10
|
|
1414
1415
|
|
|
1415
|
-
ad_structures:
|
|
1416
|
+
ad_structures: list[tuple[int, bytes]]
|
|
1416
1417
|
|
|
1417
1418
|
# fmt: on
|
|
1418
1419
|
# pylint: enable=line-too-long
|
|
1419
1420
|
|
|
1420
|
-
def __init__(self, ad_structures: Optional[
|
|
1421
|
+
def __init__(self, ad_structures: Optional[list[tuple[int, bytes]]] = None) -> None:
|
|
1421
1422
|
if ad_structures is None:
|
|
1422
1423
|
ad_structures = []
|
|
1423
1424
|
self.ad_structures = ad_structures[:]
|
|
@@ -1444,7 +1445,7 @@ class AdvertisingData:
|
|
|
1444
1445
|
return ','.join(bit_flags_to_strings(flags, flag_names))
|
|
1445
1446
|
|
|
1446
1447
|
@staticmethod
|
|
1447
|
-
def uuid_list_to_objects(ad_data: bytes, uuid_size: int) ->
|
|
1448
|
+
def uuid_list_to_objects(ad_data: bytes, uuid_size: int) -> list[UUID]:
|
|
1448
1449
|
uuids = []
|
|
1449
1450
|
offset = 0
|
|
1450
1451
|
while (offset + uuid_size) <= len(ad_data):
|
|
@@ -1461,8 +1462,8 @@ class AdvertisingData:
|
|
|
1461
1462
|
]
|
|
1462
1463
|
)
|
|
1463
1464
|
|
|
1464
|
-
@
|
|
1465
|
-
def ad_data_to_string(ad_type, ad_data):
|
|
1465
|
+
@classmethod
|
|
1466
|
+
def ad_data_to_string(cls, ad_type: int, ad_data: bytes) -> str:
|
|
1466
1467
|
if ad_type == AdvertisingData.FLAGS:
|
|
1467
1468
|
ad_type_str = 'Flags'
|
|
1468
1469
|
ad_data_str = AdvertisingData.flags_to_string(ad_data[0], short=True)
|
|
@@ -1521,72 +1522,72 @@ class AdvertisingData:
|
|
|
1521
1522
|
ad_type_str = 'Broadcast Name'
|
|
1522
1523
|
ad_data_str = ad_data.decode('utf-8')
|
|
1523
1524
|
else:
|
|
1524
|
-
ad_type_str = AdvertisingData.
|
|
1525
|
+
ad_type_str = AdvertisingData.Type(ad_type).name
|
|
1525
1526
|
ad_data_str = ad_data.hex()
|
|
1526
1527
|
|
|
1527
1528
|
return f'[{ad_type_str}]: {ad_data_str}'
|
|
1528
1529
|
|
|
1529
1530
|
# pylint: disable=too-many-return-statements
|
|
1530
|
-
@
|
|
1531
|
-
def ad_data_to_object(ad_type: int, ad_data: bytes) -> AdvertisingDataObject:
|
|
1531
|
+
@classmethod
|
|
1532
|
+
def ad_data_to_object(cls, ad_type: int, ad_data: bytes) -> AdvertisingDataObject:
|
|
1532
1533
|
if ad_type in (
|
|
1533
|
-
AdvertisingData.COMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS,
|
|
1534
|
-
AdvertisingData.INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS,
|
|
1535
|
-
AdvertisingData.LIST_OF_16_BIT_SERVICE_SOLICITATION_UUIDS,
|
|
1534
|
+
AdvertisingData.Type.COMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS,
|
|
1535
|
+
AdvertisingData.Type.INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS,
|
|
1536
|
+
AdvertisingData.Type.LIST_OF_16_BIT_SERVICE_SOLICITATION_UUIDS,
|
|
1536
1537
|
):
|
|
1537
1538
|
return AdvertisingData.uuid_list_to_objects(ad_data, 2)
|
|
1538
1539
|
|
|
1539
1540
|
if ad_type in (
|
|
1540
|
-
AdvertisingData.COMPLETE_LIST_OF_32_BIT_SERVICE_CLASS_UUIDS,
|
|
1541
|
-
AdvertisingData.INCOMPLETE_LIST_OF_32_BIT_SERVICE_CLASS_UUIDS,
|
|
1542
|
-
AdvertisingData.LIST_OF_32_BIT_SERVICE_SOLICITATION_UUIDS,
|
|
1541
|
+
AdvertisingData.Type.COMPLETE_LIST_OF_32_BIT_SERVICE_CLASS_UUIDS,
|
|
1542
|
+
AdvertisingData.Type.INCOMPLETE_LIST_OF_32_BIT_SERVICE_CLASS_UUIDS,
|
|
1543
|
+
AdvertisingData.Type.LIST_OF_32_BIT_SERVICE_SOLICITATION_UUIDS,
|
|
1543
1544
|
):
|
|
1544
1545
|
return AdvertisingData.uuid_list_to_objects(ad_data, 4)
|
|
1545
1546
|
|
|
1546
1547
|
if ad_type in (
|
|
1547
|
-
AdvertisingData.COMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS,
|
|
1548
|
-
AdvertisingData.INCOMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS,
|
|
1549
|
-
AdvertisingData.LIST_OF_128_BIT_SERVICE_SOLICITATION_UUIDS,
|
|
1548
|
+
AdvertisingData.Type.COMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS,
|
|
1549
|
+
AdvertisingData.Type.INCOMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS,
|
|
1550
|
+
AdvertisingData.Type.LIST_OF_128_BIT_SERVICE_SOLICITATION_UUIDS,
|
|
1550
1551
|
):
|
|
1551
1552
|
return AdvertisingData.uuid_list_to_objects(ad_data, 16)
|
|
1552
1553
|
|
|
1553
|
-
if ad_type == AdvertisingData.SERVICE_DATA_16_BIT_UUID:
|
|
1554
|
+
if ad_type == AdvertisingData.Type.SERVICE_DATA_16_BIT_UUID:
|
|
1554
1555
|
return (UUID.from_bytes(ad_data[:2]), ad_data[2:])
|
|
1555
1556
|
|
|
1556
|
-
if ad_type == AdvertisingData.SERVICE_DATA_32_BIT_UUID:
|
|
1557
|
+
if ad_type == AdvertisingData.Type.SERVICE_DATA_32_BIT_UUID:
|
|
1557
1558
|
return (UUID.from_bytes(ad_data[:4]), ad_data[4:])
|
|
1558
1559
|
|
|
1559
|
-
if ad_type == AdvertisingData.SERVICE_DATA_128_BIT_UUID:
|
|
1560
|
+
if ad_type == AdvertisingData.Type.SERVICE_DATA_128_BIT_UUID:
|
|
1560
1561
|
return (UUID.from_bytes(ad_data[:16]), ad_data[16:])
|
|
1561
1562
|
|
|
1562
1563
|
if ad_type in (
|
|
1563
|
-
AdvertisingData.SHORTENED_LOCAL_NAME,
|
|
1564
|
-
AdvertisingData.COMPLETE_LOCAL_NAME,
|
|
1565
|
-
AdvertisingData.URI,
|
|
1566
|
-
AdvertisingData.BROADCAST_NAME,
|
|
1564
|
+
AdvertisingData.Type.SHORTENED_LOCAL_NAME,
|
|
1565
|
+
AdvertisingData.Type.COMPLETE_LOCAL_NAME,
|
|
1566
|
+
AdvertisingData.Type.URI,
|
|
1567
|
+
AdvertisingData.Type.BROADCAST_NAME,
|
|
1567
1568
|
):
|
|
1568
1569
|
return ad_data.decode("utf-8")
|
|
1569
1570
|
|
|
1570
|
-
if ad_type in (AdvertisingData.TX_POWER_LEVEL, AdvertisingData.FLAGS):
|
|
1571
|
+
if ad_type in (AdvertisingData.Type.TX_POWER_LEVEL, AdvertisingData.Type.FLAGS):
|
|
1571
1572
|
return cast(int, struct.unpack('B', ad_data)[0])
|
|
1572
1573
|
|
|
1573
|
-
if ad_type in (AdvertisingData.ADVERTISING_INTERVAL,):
|
|
1574
|
+
if ad_type in (AdvertisingData.Type.ADVERTISING_INTERVAL,):
|
|
1574
1575
|
return cast(int, struct.unpack('<H', ad_data)[0])
|
|
1575
1576
|
|
|
1576
|
-
if ad_type == AdvertisingData.CLASS_OF_DEVICE:
|
|
1577
|
+
if ad_type == AdvertisingData.Type.CLASS_OF_DEVICE:
|
|
1577
1578
|
return cast(int, struct.unpack('<I', bytes([*ad_data, 0]))[0])
|
|
1578
1579
|
|
|
1579
|
-
if ad_type == AdvertisingData.PERIPHERAL_CONNECTION_INTERVAL_RANGE:
|
|
1580
|
-
return cast(
|
|
1580
|
+
if ad_type == AdvertisingData.Type.PERIPHERAL_CONNECTION_INTERVAL_RANGE:
|
|
1581
|
+
return cast(tuple[int, int], struct.unpack('<HH', ad_data))
|
|
1581
1582
|
|
|
1582
|
-
if ad_type == AdvertisingData.
|
|
1583
|
-
return (cast(int, struct.unpack_from('<H', ad_data, 0)[0]), ad_data[2:])
|
|
1584
|
-
|
|
1585
|
-
if ad_type == AdvertisingData.APPEARANCE:
|
|
1583
|
+
if ad_type == AdvertisingData.Type.APPEARANCE:
|
|
1586
1584
|
return Appearance.from_int(
|
|
1587
1585
|
cast(int, struct.unpack_from('<H', ad_data, 0)[0])
|
|
1588
1586
|
)
|
|
1589
1587
|
|
|
1588
|
+
if ad_type == AdvertisingData.Type.MANUFACTURER_SPECIFIC_DATA:
|
|
1589
|
+
return (cast(int, struct.unpack_from('<H', ad_data, 0)[0]), ad_data[2:])
|
|
1590
|
+
|
|
1590
1591
|
return ad_data
|
|
1591
1592
|
|
|
1592
1593
|
def append(self, data: bytes) -> None:
|
|
@@ -1600,7 +1601,80 @@ class AdvertisingData:
|
|
|
1600
1601
|
self.ad_structures.append((ad_type, ad_data))
|
|
1601
1602
|
offset += length
|
|
1602
1603
|
|
|
1603
|
-
|
|
1604
|
+
@overload
|
|
1605
|
+
def get_all(
|
|
1606
|
+
self,
|
|
1607
|
+
type_id: Literal[
|
|
1608
|
+
AdvertisingData.Type.COMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS,
|
|
1609
|
+
AdvertisingData.Type.INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS,
|
|
1610
|
+
AdvertisingData.Type.LIST_OF_16_BIT_SERVICE_SOLICITATION_UUIDS,
|
|
1611
|
+
AdvertisingData.Type.COMPLETE_LIST_OF_32_BIT_SERVICE_CLASS_UUIDS,
|
|
1612
|
+
AdvertisingData.Type.INCOMPLETE_LIST_OF_32_BIT_SERVICE_CLASS_UUIDS,
|
|
1613
|
+
AdvertisingData.Type.LIST_OF_32_BIT_SERVICE_SOLICITATION_UUIDS,
|
|
1614
|
+
AdvertisingData.Type.COMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS,
|
|
1615
|
+
AdvertisingData.Type.INCOMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS,
|
|
1616
|
+
AdvertisingData.Type.LIST_OF_128_BIT_SERVICE_SOLICITATION_UUIDS,
|
|
1617
|
+
],
|
|
1618
|
+
raw: Literal[False] = False,
|
|
1619
|
+
) -> list[list[UUID]]: ...
|
|
1620
|
+
@overload
|
|
1621
|
+
def get_all(
|
|
1622
|
+
self,
|
|
1623
|
+
type_id: Literal[
|
|
1624
|
+
AdvertisingData.Type.SERVICE_DATA_16_BIT_UUID,
|
|
1625
|
+
AdvertisingData.Type.SERVICE_DATA_32_BIT_UUID,
|
|
1626
|
+
AdvertisingData.Type.SERVICE_DATA_128_BIT_UUID,
|
|
1627
|
+
],
|
|
1628
|
+
raw: Literal[False] = False,
|
|
1629
|
+
) -> list[tuple[UUID, bytes]]: ...
|
|
1630
|
+
@overload
|
|
1631
|
+
def get_all(
|
|
1632
|
+
self,
|
|
1633
|
+
type_id: Literal[
|
|
1634
|
+
AdvertisingData.Type.SHORTENED_LOCAL_NAME,
|
|
1635
|
+
AdvertisingData.Type.COMPLETE_LOCAL_NAME,
|
|
1636
|
+
AdvertisingData.Type.URI,
|
|
1637
|
+
AdvertisingData.Type.BROADCAST_NAME,
|
|
1638
|
+
],
|
|
1639
|
+
raw: Literal[False] = False,
|
|
1640
|
+
) -> list[str]: ...
|
|
1641
|
+
@overload
|
|
1642
|
+
def get_all(
|
|
1643
|
+
self,
|
|
1644
|
+
type_id: Literal[
|
|
1645
|
+
AdvertisingData.Type.TX_POWER_LEVEL,
|
|
1646
|
+
AdvertisingData.Type.FLAGS,
|
|
1647
|
+
AdvertisingData.Type.ADVERTISING_INTERVAL,
|
|
1648
|
+
AdvertisingData.Type.CLASS_OF_DEVICE,
|
|
1649
|
+
],
|
|
1650
|
+
raw: Literal[False] = False,
|
|
1651
|
+
) -> list[int]: ...
|
|
1652
|
+
@overload
|
|
1653
|
+
def get_all(
|
|
1654
|
+
self,
|
|
1655
|
+
type_id: Literal[AdvertisingData.Type.PERIPHERAL_CONNECTION_INTERVAL_RANGE,],
|
|
1656
|
+
raw: Literal[False] = False,
|
|
1657
|
+
) -> list[tuple[int, int]]: ...
|
|
1658
|
+
@overload
|
|
1659
|
+
def get_all(
|
|
1660
|
+
self,
|
|
1661
|
+
type_id: Literal[AdvertisingData.Type.MANUFACTURER_SPECIFIC_DATA,],
|
|
1662
|
+
raw: Literal[False] = False,
|
|
1663
|
+
) -> list[tuple[int, bytes]]: ...
|
|
1664
|
+
@overload
|
|
1665
|
+
def get_all(
|
|
1666
|
+
self,
|
|
1667
|
+
type_id: Literal[AdvertisingData.Type.APPEARANCE,],
|
|
1668
|
+
raw: Literal[False] = False,
|
|
1669
|
+
) -> list[Appearance]: ...
|
|
1670
|
+
@overload
|
|
1671
|
+
def get_all(self, type_id: int, raw: Literal[True]) -> list[bytes]: ...
|
|
1672
|
+
@overload
|
|
1673
|
+
def get_all(
|
|
1674
|
+
self, type_id: int, raw: bool = False
|
|
1675
|
+
) -> list[AdvertisingDataObject]: ...
|
|
1676
|
+
|
|
1677
|
+
def get_all(self, type_id: int, raw: bool = False) -> list[AdvertisingDataObject]: # type: ignore[misc]
|
|
1604
1678
|
'''
|
|
1605
1679
|
Get Advertising Data Structure(s) with a given type
|
|
1606
1680
|
|
|
@@ -1612,6 +1686,79 @@ class AdvertisingData:
|
|
|
1612
1686
|
|
|
1613
1687
|
return [process_ad_data(ad[1]) for ad in self.ad_structures if ad[0] == type_id]
|
|
1614
1688
|
|
|
1689
|
+
@overload
|
|
1690
|
+
def get(
|
|
1691
|
+
self,
|
|
1692
|
+
type_id: Literal[
|
|
1693
|
+
AdvertisingData.Type.COMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS,
|
|
1694
|
+
AdvertisingData.Type.INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS,
|
|
1695
|
+
AdvertisingData.Type.LIST_OF_16_BIT_SERVICE_SOLICITATION_UUIDS,
|
|
1696
|
+
AdvertisingData.Type.COMPLETE_LIST_OF_32_BIT_SERVICE_CLASS_UUIDS,
|
|
1697
|
+
AdvertisingData.Type.INCOMPLETE_LIST_OF_32_BIT_SERVICE_CLASS_UUIDS,
|
|
1698
|
+
AdvertisingData.Type.LIST_OF_32_BIT_SERVICE_SOLICITATION_UUIDS,
|
|
1699
|
+
AdvertisingData.Type.COMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS,
|
|
1700
|
+
AdvertisingData.Type.INCOMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS,
|
|
1701
|
+
AdvertisingData.Type.LIST_OF_128_BIT_SERVICE_SOLICITATION_UUIDS,
|
|
1702
|
+
],
|
|
1703
|
+
raw: Literal[False] = False,
|
|
1704
|
+
) -> Optional[list[UUID]]: ...
|
|
1705
|
+
@overload
|
|
1706
|
+
def get(
|
|
1707
|
+
self,
|
|
1708
|
+
type_id: Literal[
|
|
1709
|
+
AdvertisingData.Type.SERVICE_DATA_16_BIT_UUID,
|
|
1710
|
+
AdvertisingData.Type.SERVICE_DATA_32_BIT_UUID,
|
|
1711
|
+
AdvertisingData.Type.SERVICE_DATA_128_BIT_UUID,
|
|
1712
|
+
],
|
|
1713
|
+
raw: Literal[False] = False,
|
|
1714
|
+
) -> Optional[tuple[UUID, bytes]]: ...
|
|
1715
|
+
@overload
|
|
1716
|
+
def get(
|
|
1717
|
+
self,
|
|
1718
|
+
type_id: Literal[
|
|
1719
|
+
AdvertisingData.Type.SHORTENED_LOCAL_NAME,
|
|
1720
|
+
AdvertisingData.Type.COMPLETE_LOCAL_NAME,
|
|
1721
|
+
AdvertisingData.Type.URI,
|
|
1722
|
+
AdvertisingData.Type.BROADCAST_NAME,
|
|
1723
|
+
],
|
|
1724
|
+
raw: Literal[False] = False,
|
|
1725
|
+
) -> Optional[Optional[str]]: ...
|
|
1726
|
+
@overload
|
|
1727
|
+
def get(
|
|
1728
|
+
self,
|
|
1729
|
+
type_id: Literal[
|
|
1730
|
+
AdvertisingData.Type.TX_POWER_LEVEL,
|
|
1731
|
+
AdvertisingData.Type.FLAGS,
|
|
1732
|
+
AdvertisingData.Type.ADVERTISING_INTERVAL,
|
|
1733
|
+
AdvertisingData.Type.CLASS_OF_DEVICE,
|
|
1734
|
+
],
|
|
1735
|
+
raw: Literal[False] = False,
|
|
1736
|
+
) -> Optional[int]: ...
|
|
1737
|
+
@overload
|
|
1738
|
+
def get(
|
|
1739
|
+
self,
|
|
1740
|
+
type_id: Literal[AdvertisingData.Type.PERIPHERAL_CONNECTION_INTERVAL_RANGE,],
|
|
1741
|
+
raw: Literal[False] = False,
|
|
1742
|
+
) -> Optional[tuple[int, int]]: ...
|
|
1743
|
+
@overload
|
|
1744
|
+
def get(
|
|
1745
|
+
self,
|
|
1746
|
+
type_id: Literal[AdvertisingData.Type.MANUFACTURER_SPECIFIC_DATA,],
|
|
1747
|
+
raw: Literal[False] = False,
|
|
1748
|
+
) -> Optional[tuple[int, bytes]]: ...
|
|
1749
|
+
@overload
|
|
1750
|
+
def get(
|
|
1751
|
+
self,
|
|
1752
|
+
type_id: Literal[AdvertisingData.Type.APPEARANCE,],
|
|
1753
|
+
raw: Literal[False] = False,
|
|
1754
|
+
) -> Optional[Appearance]: ...
|
|
1755
|
+
@overload
|
|
1756
|
+
def get(self, type_id: int, raw: Literal[True]) -> Optional[bytes]: ...
|
|
1757
|
+
@overload
|
|
1758
|
+
def get(
|
|
1759
|
+
self, type_id: int, raw: bool = False
|
|
1760
|
+
) -> Optional[AdvertisingDataObject]: ...
|
|
1761
|
+
|
|
1615
1762
|
def get(self, type_id: int, raw: bool = False) -> Optional[AdvertisingDataObject]:
|
|
1616
1763
|
'''
|
|
1617
1764
|
Get Advertising Data Structure(s) with a given type
|