bumble 0.0.194__py3-none-any.whl → 0.0.198__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 +2 -2
- bumble/apps/auracast.py +692 -0
- bumble/apps/bench.py +77 -23
- bumble/apps/console.py +5 -20
- bumble/apps/controller_info.py +3 -3
- bumble/apps/device_info.py +230 -0
- bumble/apps/gatt_dump.py +4 -0
- bumble/apps/lea_unicast/app.py +16 -17
- bumble/at.py +12 -6
- bumble/avc.py +8 -5
- bumble/avctp.py +3 -2
- bumble/avdtp.py +5 -1
- bumble/avrcp.py +2 -1
- bumble/codecs.py +17 -13
- bumble/colors.py +6 -2
- bumble/core.py +726 -122
- bumble/device.py +817 -117
- bumble/drivers/rtk.py +13 -8
- bumble/gatt.py +6 -1
- bumble/gatt_client.py +10 -4
- bumble/hci.py +283 -20
- bumble/hid.py +24 -28
- bumble/host.py +29 -0
- bumble/l2cap.py +24 -17
- bumble/link.py +8 -3
- bumble/pandora/host.py +3 -2
- bumble/profiles/ascs.py +739 -0
- bumble/profiles/bap.py +85 -862
- bumble/profiles/bass.py +440 -0
- bumble/profiles/csip.py +4 -4
- bumble/profiles/gap.py +110 -0
- bumble/profiles/heart_rate_service.py +4 -3
- bumble/profiles/le_audio.py +83 -0
- bumble/profiles/mcp.py +448 -0
- bumble/profiles/pacs.py +210 -0
- bumble/profiles/pbp.py +46 -0
- bumble/profiles/tmap.py +89 -0
- bumble/rfcomm.py +14 -3
- bumble/sdp.py +13 -11
- bumble/smp.py +20 -8
- bumble/snoop.py +5 -4
- bumble/transport/__init__.py +8 -2
- bumble/transport/android_emulator.py +9 -3
- bumble/transport/android_netsim.py +9 -7
- bumble/transport/common.py +46 -18
- bumble/transport/pyusb.py +2 -2
- bumble/transport/unix.py +56 -0
- bumble/transport/usb.py +57 -46
- {bumble-0.0.194.dist-info → bumble-0.0.198.dist-info}/METADATA +41 -41
- {bumble-0.0.194.dist-info → bumble-0.0.198.dist-info}/RECORD +54 -43
- {bumble-0.0.194.dist-info → bumble-0.0.198.dist-info}/WHEEL +1 -1
- {bumble-0.0.194.dist-info → bumble-0.0.198.dist-info}/LICENSE +0 -0
- {bumble-0.0.194.dist-info → bumble-0.0.198.dist-info}/entry_points.txt +0 -0
- {bumble-0.0.194.dist-info → bumble-0.0.198.dist-info}/top_level.txt +0 -0
bumble/hid.py
CHANGED
|
@@ -23,13 +23,12 @@ import struct
|
|
|
23
23
|
|
|
24
24
|
from abc import ABC, abstractmethod
|
|
25
25
|
from pyee import EventEmitter
|
|
26
|
-
from typing import Optional, Callable
|
|
26
|
+
from typing import Optional, Callable
|
|
27
27
|
from typing_extensions import override
|
|
28
28
|
|
|
29
29
|
from bumble import l2cap, device
|
|
30
|
-
from bumble.colors import color
|
|
31
30
|
from bumble.core import InvalidStateError, ProtocolError
|
|
32
|
-
from .hci import Address
|
|
31
|
+
from bumble.hci import Address
|
|
33
32
|
|
|
34
33
|
|
|
35
34
|
# -----------------------------------------------------------------------------
|
|
@@ -220,31 +219,27 @@ class HID(ABC, EventEmitter):
|
|
|
220
219
|
async def connect_control_channel(self) -> None:
|
|
221
220
|
# Create a new L2CAP connection - control channel
|
|
222
221
|
try:
|
|
223
|
-
|
|
222
|
+
channel = await self.device.l2cap_channel_manager.connect(
|
|
224
223
|
self.connection, HID_CONTROL_PSM
|
|
225
224
|
)
|
|
225
|
+
channel.sink = self.on_ctrl_pdu
|
|
226
|
+
self.l2cap_ctrl_channel = channel
|
|
226
227
|
except ProtocolError:
|
|
227
228
|
logging.exception(f'L2CAP connection failed.')
|
|
228
229
|
raise
|
|
229
230
|
|
|
230
|
-
assert self.l2cap_ctrl_channel is not None
|
|
231
|
-
# Become a sink for the L2CAP channel
|
|
232
|
-
self.l2cap_ctrl_channel.sink = self.on_ctrl_pdu
|
|
233
|
-
|
|
234
231
|
async def connect_interrupt_channel(self) -> None:
|
|
235
232
|
# Create a new L2CAP connection - interrupt channel
|
|
236
233
|
try:
|
|
237
|
-
|
|
234
|
+
channel = await self.device.l2cap_channel_manager.connect(
|
|
238
235
|
self.connection, HID_INTERRUPT_PSM
|
|
239
236
|
)
|
|
237
|
+
channel.sink = self.on_intr_pdu
|
|
238
|
+
self.l2cap_intr_channel = channel
|
|
240
239
|
except ProtocolError:
|
|
241
240
|
logging.exception(f'L2CAP connection failed.')
|
|
242
241
|
raise
|
|
243
242
|
|
|
244
|
-
assert self.l2cap_intr_channel is not None
|
|
245
|
-
# Become a sink for the L2CAP channel
|
|
246
|
-
self.l2cap_intr_channel.sink = self.on_intr_pdu
|
|
247
|
-
|
|
248
243
|
async def disconnect_interrupt_channel(self) -> None:
|
|
249
244
|
if self.l2cap_intr_channel is None:
|
|
250
245
|
raise InvalidStateError('invalid state')
|
|
@@ -334,17 +329,18 @@ class Device(HID):
|
|
|
334
329
|
ERR_INVALID_PARAMETER = 0x04
|
|
335
330
|
SUCCESS = 0xFF
|
|
336
331
|
|
|
332
|
+
@dataclass
|
|
337
333
|
class GetSetStatus:
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
334
|
+
data: bytes = b''
|
|
335
|
+
status: int = 0
|
|
336
|
+
|
|
337
|
+
get_report_cb: Optional[Callable[[int, int, int], GetSetStatus]] = None
|
|
338
|
+
set_report_cb: Optional[Callable[[int, int, int, bytes], GetSetStatus]] = None
|
|
339
|
+
get_protocol_cb: Optional[Callable[[], GetSetStatus]] = None
|
|
340
|
+
set_protocol_cb: Optional[Callable[[int], GetSetStatus]] = None
|
|
341
341
|
|
|
342
342
|
def __init__(self, device: device.Device) -> None:
|
|
343
343
|
super().__init__(device, HID.Role.DEVICE)
|
|
344
|
-
get_report_cb: Optional[Callable[[int, int, int], None]] = None
|
|
345
|
-
set_report_cb: Optional[Callable[[int, int, int, bytes], None]] = None
|
|
346
|
-
get_protocol_cb: Optional[Callable[[], None]] = None
|
|
347
|
-
set_protocol_cb: Optional[Callable[[int], None]] = None
|
|
348
344
|
|
|
349
345
|
@override
|
|
350
346
|
def on_ctrl_pdu(self, pdu: bytes) -> None:
|
|
@@ -410,7 +406,6 @@ class Device(HID):
|
|
|
410
406
|
buffer_size = 0
|
|
411
407
|
|
|
412
408
|
ret = self.get_report_cb(report_id, report_type, buffer_size)
|
|
413
|
-
assert ret is not None
|
|
414
409
|
if ret.status == self.GetSetReturn.FAILURE:
|
|
415
410
|
self.send_handshake_message(Message.Handshake.ERR_UNKNOWN)
|
|
416
411
|
elif ret.status == self.GetSetReturn.SUCCESS:
|
|
@@ -428,7 +423,9 @@ class Device(HID):
|
|
|
428
423
|
elif ret.status == self.GetSetReturn.ERR_UNSUPPORTED_REQUEST:
|
|
429
424
|
self.send_handshake_message(Message.Handshake.ERR_UNSUPPORTED_REQUEST)
|
|
430
425
|
|
|
431
|
-
def register_get_report_cb(
|
|
426
|
+
def register_get_report_cb(
|
|
427
|
+
self, cb: Callable[[int, int, int], Device.GetSetStatus]
|
|
428
|
+
) -> None:
|
|
432
429
|
self.get_report_cb = cb
|
|
433
430
|
logger.debug("GetReport callback registered successfully")
|
|
434
431
|
|
|
@@ -442,7 +439,6 @@ class Device(HID):
|
|
|
442
439
|
report_data = pdu[2:]
|
|
443
440
|
report_size = len(report_data) + 1
|
|
444
441
|
ret = self.set_report_cb(report_id, report_type, report_size, report_data)
|
|
445
|
-
assert ret is not None
|
|
446
442
|
if ret.status == self.GetSetReturn.SUCCESS:
|
|
447
443
|
self.send_handshake_message(Message.Handshake.SUCCESSFUL)
|
|
448
444
|
elif ret.status == self.GetSetReturn.ERR_INVALID_PARAMETER:
|
|
@@ -453,7 +449,7 @@ class Device(HID):
|
|
|
453
449
|
self.send_handshake_message(Message.Handshake.ERR_UNSUPPORTED_REQUEST)
|
|
454
450
|
|
|
455
451
|
def register_set_report_cb(
|
|
456
|
-
self, cb: Callable[[int, int, int, bytes],
|
|
452
|
+
self, cb: Callable[[int, int, int, bytes], Device.GetSetStatus]
|
|
457
453
|
) -> None:
|
|
458
454
|
self.set_report_cb = cb
|
|
459
455
|
logger.debug("SetReport callback registered successfully")
|
|
@@ -464,13 +460,12 @@ class Device(HID):
|
|
|
464
460
|
self.send_handshake_message(Message.Handshake.ERR_UNSUPPORTED_REQUEST)
|
|
465
461
|
return
|
|
466
462
|
ret = self.get_protocol_cb()
|
|
467
|
-
assert ret is not None
|
|
468
463
|
if ret.status == self.GetSetReturn.SUCCESS:
|
|
469
464
|
self.send_control_data(Message.ReportType.OTHER_REPORT, ret.data)
|
|
470
465
|
else:
|
|
471
466
|
self.send_handshake_message(Message.Handshake.ERR_UNSUPPORTED_REQUEST)
|
|
472
467
|
|
|
473
|
-
def register_get_protocol_cb(self, cb: Callable[[],
|
|
468
|
+
def register_get_protocol_cb(self, cb: Callable[[], Device.GetSetStatus]) -> None:
|
|
474
469
|
self.get_protocol_cb = cb
|
|
475
470
|
logger.debug("GetProtocol callback registered successfully")
|
|
476
471
|
|
|
@@ -480,13 +475,14 @@ class Device(HID):
|
|
|
480
475
|
self.send_handshake_message(Message.Handshake.ERR_UNSUPPORTED_REQUEST)
|
|
481
476
|
return
|
|
482
477
|
ret = self.set_protocol_cb(pdu[0] & 0x01)
|
|
483
|
-
assert ret is not None
|
|
484
478
|
if ret.status == self.GetSetReturn.SUCCESS:
|
|
485
479
|
self.send_handshake_message(Message.Handshake.SUCCESSFUL)
|
|
486
480
|
else:
|
|
487
481
|
self.send_handshake_message(Message.Handshake.ERR_UNSUPPORTED_REQUEST)
|
|
488
482
|
|
|
489
|
-
def register_set_protocol_cb(
|
|
483
|
+
def register_set_protocol_cb(
|
|
484
|
+
self, cb: Callable[[int], Device.GetSetStatus]
|
|
485
|
+
) -> None:
|
|
490
486
|
self.set_protocol_cb = cb
|
|
491
487
|
logger.debug("SetProtocol callback registered successfully")
|
|
492
488
|
|
bumble/host.py
CHANGED
|
@@ -772,6 +772,8 @@ class Host(AbortableEventEmitter):
|
|
|
772
772
|
event.connection_handle,
|
|
773
773
|
BT_LE_TRANSPORT,
|
|
774
774
|
event.peer_address,
|
|
775
|
+
getattr(event, 'local_resolvable_private_address', None),
|
|
776
|
+
getattr(event, 'peer_resolvable_private_address', None),
|
|
775
777
|
event.role,
|
|
776
778
|
connection_parameters,
|
|
777
779
|
)
|
|
@@ -787,6 +789,10 @@ class Host(AbortableEventEmitter):
|
|
|
787
789
|
# Just use the same implementation as for the non-enhanced event for now
|
|
788
790
|
self.on_hci_le_connection_complete_event(event)
|
|
789
791
|
|
|
792
|
+
def on_hci_le_enhanced_connection_complete_v2_event(self, event):
|
|
793
|
+
# Just use the same implementation as for the v1 event for now
|
|
794
|
+
self.on_hci_le_enhanced_connection_complete_event(event)
|
|
795
|
+
|
|
790
796
|
def on_hci_connection_complete_event(self, event):
|
|
791
797
|
if event.status == hci.HCI_SUCCESS:
|
|
792
798
|
# Create/update the connection
|
|
@@ -813,6 +819,8 @@ class Host(AbortableEventEmitter):
|
|
|
813
819
|
event.bd_addr,
|
|
814
820
|
None,
|
|
815
821
|
None,
|
|
822
|
+
None,
|
|
823
|
+
None,
|
|
816
824
|
)
|
|
817
825
|
else:
|
|
818
826
|
logger.debug(f'### BR/EDR CONNECTION FAILED: {event.status}')
|
|
@@ -905,6 +913,27 @@ class Host(AbortableEventEmitter):
|
|
|
905
913
|
event.num_completed_extended_advertising_events,
|
|
906
914
|
)
|
|
907
915
|
|
|
916
|
+
def on_hci_le_periodic_advertising_sync_established_event(self, event):
|
|
917
|
+
self.emit(
|
|
918
|
+
'periodic_advertising_sync_establishment',
|
|
919
|
+
event.status,
|
|
920
|
+
event.sync_handle,
|
|
921
|
+
event.advertising_sid,
|
|
922
|
+
event.advertiser_address,
|
|
923
|
+
event.advertiser_phy,
|
|
924
|
+
event.periodic_advertising_interval,
|
|
925
|
+
event.advertiser_clock_accuracy,
|
|
926
|
+
)
|
|
927
|
+
|
|
928
|
+
def on_hci_le_periodic_advertising_sync_lost_event(self, event):
|
|
929
|
+
self.emit('periodic_advertising_sync_loss', event.sync_handle)
|
|
930
|
+
|
|
931
|
+
def on_hci_le_periodic_advertising_report_event(self, event):
|
|
932
|
+
self.emit('periodic_advertising_report', event.sync_handle, event)
|
|
933
|
+
|
|
934
|
+
def on_hci_le_biginfo_advertising_report_event(self, event):
|
|
935
|
+
self.emit('biginfo_advertising_report', event.sync_handle, event)
|
|
936
|
+
|
|
908
937
|
def on_hci_le_cis_request_event(self, event):
|
|
909
938
|
self.emit(
|
|
910
939
|
'cis_request',
|
bumble/l2cap.py
CHANGED
|
@@ -41,7 +41,14 @@ from typing import (
|
|
|
41
41
|
|
|
42
42
|
from .utils import deprecated
|
|
43
43
|
from .colors import color
|
|
44
|
-
from .core import
|
|
44
|
+
from .core import (
|
|
45
|
+
BT_CENTRAL_ROLE,
|
|
46
|
+
InvalidStateError,
|
|
47
|
+
InvalidArgumentError,
|
|
48
|
+
InvalidPacketError,
|
|
49
|
+
OutOfResourcesError,
|
|
50
|
+
ProtocolError,
|
|
51
|
+
)
|
|
45
52
|
from .hci import (
|
|
46
53
|
HCI_LE_Connection_Update_Command,
|
|
47
54
|
HCI_Object,
|
|
@@ -189,17 +196,17 @@ class LeCreditBasedChannelSpec:
|
|
|
189
196
|
self.max_credits < 1
|
|
190
197
|
or self.max_credits > L2CAP_LE_CREDIT_BASED_CONNECTION_MAX_CREDITS
|
|
191
198
|
):
|
|
192
|
-
raise
|
|
199
|
+
raise InvalidArgumentError('max credits out of range')
|
|
193
200
|
if (
|
|
194
201
|
self.mtu < L2CAP_LE_CREDIT_BASED_CONNECTION_MIN_MTU
|
|
195
202
|
or self.mtu > L2CAP_LE_CREDIT_BASED_CONNECTION_MAX_MTU
|
|
196
203
|
):
|
|
197
|
-
raise
|
|
204
|
+
raise InvalidArgumentError('MTU out of range')
|
|
198
205
|
if (
|
|
199
206
|
self.mps < L2CAP_LE_CREDIT_BASED_CONNECTION_MIN_MPS
|
|
200
207
|
or self.mps > L2CAP_LE_CREDIT_BASED_CONNECTION_MAX_MPS
|
|
201
208
|
):
|
|
202
|
-
raise
|
|
209
|
+
raise InvalidArgumentError('MPS out of range')
|
|
203
210
|
|
|
204
211
|
|
|
205
212
|
class L2CAP_PDU:
|
|
@@ -211,7 +218,7 @@ class L2CAP_PDU:
|
|
|
211
218
|
def from_bytes(data: bytes) -> L2CAP_PDU:
|
|
212
219
|
# Check parameters
|
|
213
220
|
if len(data) < 4:
|
|
214
|
-
raise
|
|
221
|
+
raise InvalidPacketError('not enough data for L2CAP header')
|
|
215
222
|
|
|
216
223
|
_, l2cap_pdu_cid = struct.unpack_from('<HH', data, 0)
|
|
217
224
|
l2cap_pdu_payload = data[4:]
|
|
@@ -816,7 +823,7 @@ class ClassicChannel(EventEmitter):
|
|
|
816
823
|
|
|
817
824
|
# Check that we can start a new connection
|
|
818
825
|
if self.connection_result:
|
|
819
|
-
raise
|
|
826
|
+
raise InvalidStateError('connection already pending')
|
|
820
827
|
|
|
821
828
|
self._change_state(self.State.WAIT_CONNECT_RSP)
|
|
822
829
|
self.send_control_frame(
|
|
@@ -1129,7 +1136,7 @@ class LeCreditBasedChannel(EventEmitter):
|
|
|
1129
1136
|
# Check that we can start a new connection
|
|
1130
1137
|
identifier = self.manager.next_identifier(self.connection)
|
|
1131
1138
|
if identifier in self.manager.le_coc_requests:
|
|
1132
|
-
raise
|
|
1139
|
+
raise InvalidStateError('too many concurrent connection requests')
|
|
1133
1140
|
|
|
1134
1141
|
self._change_state(self.State.CONNECTING)
|
|
1135
1142
|
request = L2CAP_LE_Credit_Based_Connection_Request(
|
|
@@ -1516,7 +1523,7 @@ class ChannelManager:
|
|
|
1516
1523
|
if cid not in channels:
|
|
1517
1524
|
return cid
|
|
1518
1525
|
|
|
1519
|
-
raise
|
|
1526
|
+
raise OutOfResourcesError('no free CID available')
|
|
1520
1527
|
|
|
1521
1528
|
@staticmethod
|
|
1522
1529
|
def find_free_le_cid(channels: Iterable[int]) -> int:
|
|
@@ -1529,7 +1536,7 @@ class ChannelManager:
|
|
|
1529
1536
|
if cid not in channels:
|
|
1530
1537
|
return cid
|
|
1531
1538
|
|
|
1532
|
-
raise
|
|
1539
|
+
raise OutOfResourcesError('no free CID')
|
|
1533
1540
|
|
|
1534
1541
|
def next_identifier(self, connection: Connection) -> int:
|
|
1535
1542
|
identifier = (self.identifiers.setdefault(connection.handle, 0) + 1) % 256
|
|
@@ -1576,15 +1583,15 @@ class ChannelManager:
|
|
|
1576
1583
|
else:
|
|
1577
1584
|
# Check that the PSM isn't already in use
|
|
1578
1585
|
if spec.psm in self.servers:
|
|
1579
|
-
raise
|
|
1586
|
+
raise InvalidArgumentError('PSM already in use')
|
|
1580
1587
|
|
|
1581
1588
|
# Check that the PSM is valid
|
|
1582
1589
|
if spec.psm % 2 == 0:
|
|
1583
|
-
raise
|
|
1590
|
+
raise InvalidArgumentError('invalid PSM (not odd)')
|
|
1584
1591
|
check = spec.psm >> 8
|
|
1585
1592
|
while check:
|
|
1586
1593
|
if check % 2 != 0:
|
|
1587
|
-
raise
|
|
1594
|
+
raise InvalidArgumentError('invalid PSM')
|
|
1588
1595
|
check >>= 8
|
|
1589
1596
|
|
|
1590
1597
|
self.servers[spec.psm] = ClassicChannelServer(self, spec.psm, handler, spec.mtu)
|
|
@@ -1626,7 +1633,7 @@ class ChannelManager:
|
|
|
1626
1633
|
else:
|
|
1627
1634
|
# Check that the PSM isn't already in use
|
|
1628
1635
|
if spec.psm in self.le_coc_servers:
|
|
1629
|
-
raise
|
|
1636
|
+
raise InvalidArgumentError('PSM already in use')
|
|
1630
1637
|
|
|
1631
1638
|
self.le_coc_servers[spec.psm] = LeCreditBasedChannelServer(
|
|
1632
1639
|
self,
|
|
@@ -2154,10 +2161,10 @@ class ChannelManager:
|
|
|
2154
2161
|
connection_channels = self.channels.setdefault(connection.handle, {})
|
|
2155
2162
|
source_cid = self.find_free_le_cid(connection_channels)
|
|
2156
2163
|
if source_cid is None: # Should never happen!
|
|
2157
|
-
raise
|
|
2164
|
+
raise OutOfResourcesError('all CIDs already in use')
|
|
2158
2165
|
|
|
2159
2166
|
if spec.psm is None:
|
|
2160
|
-
raise
|
|
2167
|
+
raise InvalidArgumentError('PSM cannot be None')
|
|
2161
2168
|
|
|
2162
2169
|
# Create the channel
|
|
2163
2170
|
logger.debug(f'creating coc channel with cid={source_cid} for psm {spec.psm}')
|
|
@@ -2206,10 +2213,10 @@ class ChannelManager:
|
|
|
2206
2213
|
connection_channels = self.channels.setdefault(connection.handle, {})
|
|
2207
2214
|
source_cid = self.find_free_br_edr_cid(connection_channels)
|
|
2208
2215
|
if source_cid is None: # Should never happen!
|
|
2209
|
-
raise
|
|
2216
|
+
raise OutOfResourcesError('all CIDs already in use')
|
|
2210
2217
|
|
|
2211
2218
|
if spec.psm is None:
|
|
2212
|
-
raise
|
|
2219
|
+
raise InvalidArgumentError('PSM cannot be None')
|
|
2213
2220
|
|
|
2214
2221
|
# Create the channel
|
|
2215
2222
|
logger.debug(
|
bumble/link.py
CHANGED
|
@@ -19,7 +19,12 @@ import logging
|
|
|
19
19
|
import asyncio
|
|
20
20
|
from functools import partial
|
|
21
21
|
|
|
22
|
-
from bumble.core import
|
|
22
|
+
from bumble.core import (
|
|
23
|
+
BT_PERIPHERAL_ROLE,
|
|
24
|
+
BT_BR_EDR_TRANSPORT,
|
|
25
|
+
BT_LE_TRANSPORT,
|
|
26
|
+
InvalidStateError,
|
|
27
|
+
)
|
|
23
28
|
from bumble.colors import color
|
|
24
29
|
from bumble.hci import (
|
|
25
30
|
Address,
|
|
@@ -405,12 +410,12 @@ class RemoteLink:
|
|
|
405
410
|
|
|
406
411
|
def add_controller(self, controller):
|
|
407
412
|
if self.controller:
|
|
408
|
-
raise
|
|
413
|
+
raise InvalidStateError('controller already set')
|
|
409
414
|
self.controller = controller
|
|
410
415
|
|
|
411
416
|
def remove_controller(self, controller):
|
|
412
417
|
if self.controller != controller:
|
|
413
|
-
raise
|
|
418
|
+
raise InvalidStateError('controller mismatch')
|
|
414
419
|
self.controller = None
|
|
415
420
|
|
|
416
421
|
def get_pending_connection(self):
|
bumble/pandora/host.py
CHANGED
|
@@ -28,6 +28,7 @@ from bumble.core import (
|
|
|
28
28
|
BT_PERIPHERAL_ROLE,
|
|
29
29
|
UUID,
|
|
30
30
|
AdvertisingData,
|
|
31
|
+
Appearance,
|
|
31
32
|
ConnectionError,
|
|
32
33
|
)
|
|
33
34
|
from bumble.device import (
|
|
@@ -988,8 +989,8 @@ class HostService(HostServicer):
|
|
|
988
989
|
dt.random_target_addresses.extend(
|
|
989
990
|
[data[i * 6 :: i * 6 + 6] for i in range(int(len(data) / 6))]
|
|
990
991
|
)
|
|
991
|
-
if
|
|
992
|
-
dt.appearance =
|
|
992
|
+
if appearance := cast(Appearance, ad.get(AdvertisingData.APPEARANCE)):
|
|
993
|
+
dt.appearance = int(appearance)
|
|
993
994
|
if i := cast(int, ad.get(AdvertisingData.ADVERTISING_INTERVAL)):
|
|
994
995
|
dt.advertising_interval = i
|
|
995
996
|
if s := cast(str, ad.get(AdvertisingData.URI)):
|