bumble 0.0.214__py3-none-any.whl → 0.0.216__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.
Files changed (122) hide show
  1. bumble/_version.py +16 -3
  2. bumble/a2dp.py +15 -16
  3. bumble/apps/auracast.py +13 -38
  4. bumble/apps/bench.py +9 -10
  5. bumble/apps/ble_rpa_tool.py +1 -0
  6. bumble/apps/console.py +22 -25
  7. bumble/apps/controller_info.py +19 -19
  8. bumble/apps/controller_loopback.py +2 -2
  9. bumble/apps/controllers.py +1 -1
  10. bumble/apps/device_info.py +3 -3
  11. bumble/apps/gatt_dump.py +1 -1
  12. bumble/apps/gg_bridge.py +5 -6
  13. bumble/apps/hci_bridge.py +3 -3
  14. bumble/apps/l2cap_bridge.py +3 -3
  15. bumble/apps/lea_unicast/app.py +15 -25
  16. bumble/apps/pair.py +30 -43
  17. bumble/apps/pandora_server.py +5 -4
  18. bumble/apps/player/player.py +19 -22
  19. bumble/apps/rfcomm_bridge.py +3 -8
  20. bumble/apps/scan.py +16 -6
  21. bumble/apps/show.py +3 -4
  22. bumble/apps/speaker/speaker.py +22 -22
  23. bumble/apps/unbond.py +2 -1
  24. bumble/apps/usb_probe.py +1 -2
  25. bumble/att.py +241 -246
  26. bumble/audio/io.py +5 -9
  27. bumble/avc.py +2 -2
  28. bumble/avctp.py +6 -7
  29. bumble/avdtp.py +19 -22
  30. bumble/avrcp.py +1096 -588
  31. bumble/codecs.py +2 -0
  32. bumble/controller.py +52 -13
  33. bumble/core.py +567 -248
  34. bumble/crypto/__init__.py +2 -2
  35. bumble/crypto/builtin.py +1 -1
  36. bumble/crypto/cryptography.py +2 -4
  37. bumble/data_types.py +1025 -0
  38. bumble/device.py +318 -279
  39. bumble/drivers/__init__.py +3 -2
  40. bumble/drivers/intel.py +3 -4
  41. bumble/drivers/rtk.py +26 -9
  42. bumble/gap.py +4 -4
  43. bumble/gatt.py +3 -2
  44. bumble/gatt_adapters.py +3 -11
  45. bumble/gatt_client.py +69 -81
  46. bumble/gatt_server.py +124 -124
  47. bumble/hci.py +67 -18
  48. bumble/helpers.py +19 -26
  49. bumble/hfp.py +10 -21
  50. bumble/hid.py +22 -16
  51. bumble/host.py +181 -103
  52. bumble/keys.py +5 -3
  53. bumble/l2cap.py +121 -74
  54. bumble/link.py +8 -9
  55. bumble/pairing.py +7 -6
  56. bumble/pandora/__init__.py +8 -7
  57. bumble/pandora/config.py +3 -1
  58. bumble/pandora/device.py +3 -2
  59. bumble/pandora/host.py +38 -36
  60. bumble/pandora/l2cap.py +22 -21
  61. bumble/pandora/security.py +15 -15
  62. bumble/pandora/utils.py +5 -3
  63. bumble/profiles/aics.py +11 -11
  64. bumble/profiles/ams.py +7 -8
  65. bumble/profiles/ancs.py +6 -7
  66. bumble/profiles/ascs.py +4 -9
  67. bumble/profiles/asha.py +8 -12
  68. bumble/profiles/bap.py +11 -23
  69. bumble/profiles/bass.py +2 -7
  70. bumble/profiles/battery_service.py +3 -4
  71. bumble/profiles/cap.py +1 -2
  72. bumble/profiles/csip.py +2 -6
  73. bumble/profiles/device_information_service.py +2 -2
  74. bumble/profiles/gap.py +4 -4
  75. bumble/profiles/gatt_service.py +1 -4
  76. bumble/profiles/gmap.py +5 -5
  77. bumble/profiles/hap.py +62 -59
  78. bumble/profiles/heart_rate_service.py +5 -4
  79. bumble/profiles/le_audio.py +3 -1
  80. bumble/profiles/mcp.py +3 -7
  81. bumble/profiles/pacs.py +3 -6
  82. bumble/profiles/pbp.py +2 -0
  83. bumble/profiles/tmap.py +2 -3
  84. bumble/profiles/vcs.py +2 -8
  85. bumble/profiles/vocs.py +8 -8
  86. bumble/rfcomm.py +11 -14
  87. bumble/rtp.py +1 -0
  88. bumble/sdp.py +10 -8
  89. bumble/smp.py +142 -153
  90. bumble/snoop.py +5 -5
  91. bumble/tools/generate_company_id_list.py +1 -0
  92. bumble/tools/intel_fw_download.py +3 -3
  93. bumble/tools/intel_util.py +4 -4
  94. bumble/tools/rtk_fw_download.py +6 -3
  95. bumble/tools/rtk_util.py +24 -7
  96. bumble/transport/__init__.py +19 -15
  97. bumble/transport/android_emulator.py +8 -13
  98. bumble/transport/android_netsim.py +19 -18
  99. bumble/transport/common.py +12 -15
  100. bumble/transport/file.py +1 -1
  101. bumble/transport/hci_socket.py +4 -6
  102. bumble/transport/pty.py +5 -6
  103. bumble/transport/pyusb.py +7 -10
  104. bumble/transport/serial.py +2 -1
  105. bumble/transport/tcp_client.py +2 -2
  106. bumble/transport/tcp_server.py +11 -14
  107. bumble/transport/udp.py +3 -3
  108. bumble/transport/unix.py +67 -1
  109. bumble/transport/usb.py +6 -6
  110. bumble/transport/vhci.py +0 -1
  111. bumble/transport/ws_client.py +2 -1
  112. bumble/transport/ws_server.py +3 -2
  113. bumble/utils.py +20 -5
  114. bumble/vendor/android/hci.py +1 -2
  115. bumble/vendor/zephyr/hci.py +0 -1
  116. {bumble-0.0.214.dist-info → bumble-0.0.216.dist-info}/METADATA +2 -1
  117. bumble-0.0.216.dist-info/RECORD +183 -0
  118. bumble-0.0.214.dist-info/RECORD +0 -182
  119. {bumble-0.0.214.dist-info → bumble-0.0.216.dist-info}/WHEEL +0 -0
  120. {bumble-0.0.214.dist-info → bumble-0.0.216.dist-info}/entry_points.txt +0 -0
  121. {bumble-0.0.214.dist-info → bumble-0.0.216.dist-info}/licenses/LICENSE +0 -0
  122. {bumble-0.0.214.dist-info → bumble-0.0.216.dist-info}/top_level.txt +0 -0
bumble/gatt_server.py CHANGED
@@ -13,7 +13,7 @@
13
13
  # limitations under the License.
14
14
 
15
15
  # -----------------------------------------------------------------------------
16
- # GATT - Generic Attribute Profile
16
+ # GATT - Generic att.Attribute Profile
17
17
  # Server
18
18
  #
19
19
  # See Bluetooth spec @ Vol 3, Part G
@@ -24,46 +24,16 @@
24
24
  # Imports
25
25
  # -----------------------------------------------------------------------------
26
26
  from __future__ import annotations
27
+
27
28
  import asyncio
28
29
  import logging
29
- from collections import defaultdict
30
30
  import struct
31
- from typing import (
32
- Iterable,
33
- Optional,
34
- TypeVar,
35
- TYPE_CHECKING,
36
- )
31
+ from collections import defaultdict
32
+ from typing import TYPE_CHECKING, Iterable, Optional, TypeVar
37
33
 
34
+ from bumble import att, utils
38
35
  from bumble.colors import color
39
36
  from bumble.core import UUID
40
- from bumble.att import (
41
- ATT_ATTRIBUTE_NOT_FOUND_ERROR,
42
- ATT_ATTRIBUTE_NOT_LONG_ERROR,
43
- ATT_CID,
44
- ATT_DEFAULT_MTU,
45
- ATT_INVALID_ATTRIBUTE_LENGTH_ERROR,
46
- ATT_INVALID_HANDLE_ERROR,
47
- ATT_INVALID_OFFSET_ERROR,
48
- ATT_REQUEST_NOT_SUPPORTED_ERROR,
49
- ATT_REQUESTS,
50
- ATT_PDU,
51
- ATT_UNLIKELY_ERROR_ERROR,
52
- ATT_UNSUPPORTED_GROUP_TYPE_ERROR,
53
- ATT_Error,
54
- ATT_Error_Response,
55
- ATT_Exchange_MTU_Response,
56
- ATT_Find_By_Type_Value_Response,
57
- ATT_Find_Information_Response,
58
- ATT_Handle_Value_Indication,
59
- ATT_Handle_Value_Notification,
60
- ATT_Read_Blob_Response,
61
- ATT_Read_By_Group_Type_Response,
62
- ATT_Read_By_Type_Response,
63
- ATT_Read_Response,
64
- ATT_Write_Response,
65
- Attribute,
66
- )
67
37
  from bumble.gatt import (
68
38
  GATT_CHARACTERISTIC_ATTRIBUTE_TYPE,
69
39
  GATT_CLIENT_CHARACTERISTIC_CONFIGURATION_DESCRIPTOR,
@@ -74,14 +44,13 @@ from bumble.gatt import (
74
44
  Characteristic,
75
45
  CharacteristicDeclaration,
76
46
  CharacteristicValue,
77
- IncludedServiceDeclaration,
78
47
  Descriptor,
48
+ IncludedServiceDeclaration,
79
49
  Service,
80
50
  )
81
- from bumble import utils
82
51
 
83
52
  if TYPE_CHECKING:
84
- from bumble.device import Device, Connection
53
+ from bumble.device import Connection, Device
85
54
 
86
55
  # -----------------------------------------------------------------------------
87
56
  # Logging
@@ -99,9 +68,9 @@ GATT_SERVER_DEFAULT_MAX_MTU = 517
99
68
  # GATT Server
100
69
  # -----------------------------------------------------------------------------
101
70
  class Server(utils.EventEmitter):
102
- attributes: list[Attribute]
71
+ attributes: list[att.Attribute]
103
72
  services: list[Service]
104
- attributes_by_handle: dict[int, Attribute]
73
+ attributes_by_handle: dict[int, att.Attribute]
105
74
  subscribers: dict[int, dict[int, bytes]]
106
75
  indication_semaphores: defaultdict[int, asyncio.Semaphore]
107
76
  pending_confirmations: defaultdict[int, Optional[asyncio.futures.Future]]
@@ -112,7 +81,7 @@ class Server(utils.EventEmitter):
112
81
  super().__init__()
113
82
  self.device = device
114
83
  self.services = []
115
- self.attributes = [] # Attributes, ordered by increasing handle values
84
+ self.attributes = [] # att.Attributes, ordered by increasing handle values
116
85
  self.attributes_by_handle = {} # Map for fast attribute access by handle
117
86
  self.max_mtu = (
118
87
  GATT_SERVER_DEFAULT_MAX_MTU # The max MTU we're willing to negotiate
@@ -127,12 +96,12 @@ class Server(utils.EventEmitter):
127
96
  return "\n".join(map(str, self.attributes))
128
97
 
129
98
  def send_gatt_pdu(self, connection_handle: int, pdu: bytes) -> None:
130
- self.device.send_l2cap_pdu(connection_handle, ATT_CID, pdu)
99
+ self.device.send_l2cap_pdu(connection_handle, att.ATT_CID, pdu)
131
100
 
132
101
  def next_handle(self) -> int:
133
102
  return 1 + len(self.attributes)
134
103
 
135
- def get_advertising_service_data(self) -> dict[Attribute, bytes]:
104
+ def get_advertising_service_data(self) -> dict[att.Attribute, bytes]:
136
105
  return {
137
106
  attribute: data
138
107
  for attribute in self.attributes
@@ -140,7 +109,7 @@ class Server(utils.EventEmitter):
140
109
  and (data := attribute.get_advertising_data())
141
110
  }
142
111
 
143
- def get_attribute(self, handle: int) -> Optional[Attribute]:
112
+ def get_attribute(self, handle: int) -> Optional[att.Attribute]:
144
113
  attribute = self.attributes_by_handle.get(handle)
145
114
  if attribute:
146
115
  return attribute
@@ -231,7 +200,7 @@ class Server(utils.EventEmitter):
231
200
  None,
232
201
  )
233
202
 
234
- def add_attribute(self, attribute: Attribute) -> None:
203
+ def add_attribute(self, attribute: att.Attribute) -> None:
235
204
  # Assign a handle to this attribute
236
205
  attribute.handle = self.next_handle()
237
206
  attribute.end_group_handle = (
@@ -286,7 +255,7 @@ class Server(utils.EventEmitter):
286
255
  # pylint: disable=line-too-long
287
256
  Descriptor(
288
257
  GATT_CLIENT_CHARACTERISTIC_CONFIGURATION_DESCRIPTOR,
289
- Attribute.READABLE | Attribute.WRITEABLE,
258
+ att.Attribute.READABLE | att.Attribute.WRITEABLE,
290
259
  CharacteristicValue(
291
260
  read=lambda connection, characteristic=characteristic: self.read_cccd(
292
261
  connection, characteristic
@@ -355,7 +324,7 @@ class Server(utils.EventEmitter):
355
324
  indicate_enabled,
356
325
  )
357
326
 
358
- def send_response(self, connection: Connection, response: ATT_PDU) -> None:
327
+ def send_response(self, connection: Connection, response: att.ATT_PDU) -> None:
359
328
  logger.debug(
360
329
  f'GATT Response from server: [0x{connection.handle:04X}] {response}'
361
330
  )
@@ -364,7 +333,7 @@ class Server(utils.EventEmitter):
364
333
  async def notify_subscriber(
365
334
  self,
366
335
  connection: Connection,
367
- attribute: Attribute,
336
+ attribute: att.Attribute,
368
337
  value: Optional[bytes] = None,
369
338
  force: bool = False,
370
339
  ) -> None:
@@ -396,7 +365,7 @@ class Server(utils.EventEmitter):
396
365
  value = value[: connection.att_mtu - 3]
397
366
 
398
367
  # Notify
399
- notification = ATT_Handle_Value_Notification(
368
+ notification = att.ATT_Handle_Value_Notification(
400
369
  attribute_handle=attribute.handle, attribute_value=value
401
370
  )
402
371
  logger.debug(
@@ -407,7 +376,7 @@ class Server(utils.EventEmitter):
407
376
  async def indicate_subscriber(
408
377
  self,
409
378
  connection: Connection,
410
- attribute: Attribute,
379
+ attribute: att.Attribute,
411
380
  value: Optional[bytes] = None,
412
381
  force: bool = False,
413
382
  ) -> None:
@@ -439,7 +408,7 @@ class Server(utils.EventEmitter):
439
408
  value = value[: connection.att_mtu - 3]
440
409
 
441
410
  # Indicate
442
- indication = ATT_Handle_Value_Indication(
411
+ indication = att.ATT_Handle_Value_Indication(
443
412
  attribute_handle=attribute.handle, attribute_value=value
444
413
  )
445
414
  logger.debug(
@@ -467,7 +436,7 @@ class Server(utils.EventEmitter):
467
436
  async def _notify_or_indicate_subscribers(
468
437
  self,
469
438
  indicate: bool,
470
- attribute: Attribute,
439
+ attribute: att.Attribute,
471
440
  value: Optional[bytes] = None,
472
441
  force: bool = False,
473
442
  ) -> None:
@@ -494,7 +463,7 @@ class Server(utils.EventEmitter):
494
463
 
495
464
  async def notify_subscribers(
496
465
  self,
497
- attribute: Attribute,
466
+ attribute: att.Attribute,
498
467
  value: Optional[bytes] = None,
499
468
  force: bool = False,
500
469
  ):
@@ -504,7 +473,7 @@ class Server(utils.EventEmitter):
504
473
 
505
474
  async def indicate_subscribers(
506
475
  self,
507
- attribute: Attribute,
476
+ attribute: att.Attribute,
508
477
  value: Optional[bytes] = None,
509
478
  force: bool = False,
510
479
  ):
@@ -518,33 +487,33 @@ class Server(utils.EventEmitter):
518
487
  if connection.handle in self.pending_confirmations:
519
488
  del self.pending_confirmations[connection.handle]
520
489
 
521
- def on_gatt_pdu(self, connection: Connection, att_pdu: ATT_PDU) -> None:
490
+ def on_gatt_pdu(self, connection: Connection, att_pdu: att.ATT_PDU) -> None:
522
491
  logger.debug(f'GATT Request to server: [0x{connection.handle:04X}] {att_pdu}')
523
492
  handler_name = f'on_{att_pdu.name.lower()}'
524
493
  handler = getattr(self, handler_name, None)
525
494
  if handler is not None:
526
495
  try:
527
496
  handler(connection, att_pdu)
528
- except ATT_Error as error:
497
+ except att.ATT_Error as error:
529
498
  logger.debug(f'normal exception returned by handler: {error}')
530
- response = ATT_Error_Response(
499
+ response = att.ATT_Error_Response(
531
500
  request_opcode_in_error=att_pdu.op_code,
532
501
  attribute_handle_in_error=error.att_handle,
533
502
  error_code=error.error_code,
534
503
  )
535
504
  self.send_response(connection, response)
536
- except Exception as error:
537
- logger.warning(f'{color("!!! Exception in handler:", "red")} {error}')
538
- response = ATT_Error_Response(
505
+ except Exception:
506
+ logger.exception(color("!!! Exception in handler:", "red"))
507
+ response = att.ATT_Error_Response(
539
508
  request_opcode_in_error=att_pdu.op_code,
540
509
  attribute_handle_in_error=0x0000,
541
- error_code=ATT_UNLIKELY_ERROR_ERROR,
510
+ error_code=att.ATT_UNLIKELY_ERROR_ERROR,
542
511
  )
543
512
  self.send_response(connection, response)
544
- raise error
513
+ raise
545
514
  else:
546
515
  # No specific handler registered
547
- if att_pdu.op_code in ATT_REQUESTS:
516
+ if att_pdu.op_code in att.ATT_REQUESTS:
548
517
  # Invoke the generic handler
549
518
  self.on_att_request(connection, att_pdu)
550
519
  else:
@@ -560,7 +529,7 @@ class Server(utils.EventEmitter):
560
529
  #######################################################
561
530
  # ATT handlers
562
531
  #######################################################
563
- def on_att_request(self, connection: Connection, pdu: ATT_PDU) -> None:
532
+ def on_att_request(self, connection: Connection, pdu: att.ATT_PDU) -> None:
564
533
  '''
565
534
  Handler for requests without a more specific handler
566
535
  '''
@@ -570,23 +539,25 @@ class Server(utils.EventEmitter):
570
539
  )
571
540
  + str(pdu)
572
541
  )
573
- response = ATT_Error_Response(
542
+ response = att.ATT_Error_Response(
574
543
  request_opcode_in_error=pdu.op_code,
575
544
  attribute_handle_in_error=0x0000,
576
- error_code=ATT_REQUEST_NOT_SUPPORTED_ERROR,
545
+ error_code=att.ATT_REQUEST_NOT_SUPPORTED_ERROR,
577
546
  )
578
547
  self.send_response(connection, response)
579
548
 
580
- def on_att_exchange_mtu_request(self, connection, request):
549
+ def on_att_exchange_mtu_request(
550
+ self, connection: Connection, request: att.ATT_Exchange_MTU_Request
551
+ ):
581
552
  '''
582
553
  See Bluetooth spec Vol 3, Part F - 3.4.2.1 Exchange MTU Request
583
554
  '''
584
555
  self.send_response(
585
- connection, ATT_Exchange_MTU_Response(server_rx_mtu=self.max_mtu)
556
+ connection, att.ATT_Exchange_MTU_Response(server_rx_mtu=self.max_mtu)
586
557
  )
587
558
 
588
559
  # Compute the final MTU
589
- if request.client_rx_mtu >= ATT_DEFAULT_MTU:
560
+ if request.client_rx_mtu >= att.ATT_DEFAULT_MTU:
590
561
  mtu = min(self.max_mtu, request.client_rx_mtu)
591
562
 
592
563
  # Notify the device
@@ -594,11 +565,14 @@ class Server(utils.EventEmitter):
594
565
  else:
595
566
  logger.warning('invalid client_rx_mtu received, MTU not changed')
596
567
 
597
- def on_att_find_information_request(self, connection, request):
568
+ def on_att_find_information_request(
569
+ self, connection: Connection, request: att.ATT_Find_Information_Request
570
+ ):
598
571
  '''
599
572
  See Bluetooth spec Vol 3, Part F - 3.4.3.1 Find Information Request
600
573
  '''
601
574
 
575
+ response: att.ATT_PDU
602
576
  # Check the request parameters
603
577
  if (
604
578
  request.starting_handle == 0
@@ -606,17 +580,17 @@ class Server(utils.EventEmitter):
606
580
  ):
607
581
  self.send_response(
608
582
  connection,
609
- ATT_Error_Response(
583
+ att.ATT_Error_Response(
610
584
  request_opcode_in_error=request.op_code,
611
585
  attribute_handle_in_error=request.starting_handle,
612
- error_code=ATT_INVALID_HANDLE_ERROR,
586
+ error_code=att.ATT_INVALID_HANDLE_ERROR,
613
587
  ),
614
588
  )
615
589
  return
616
590
 
617
591
  # Build list of returned attributes
618
592
  pdu_space_available = connection.att_mtu - 2
619
- attributes = []
593
+ attributes: list[att.Attribute] = []
620
594
  uuid_size = 0
621
595
  for attribute in (
622
596
  attribute
@@ -646,21 +620,23 @@ class Server(utils.EventEmitter):
646
620
  struct.pack('<H', attribute.handle) + attribute.type.to_pdu_bytes()
647
621
  for attribute in attributes
648
622
  ]
649
- response = ATT_Find_Information_Response(
623
+ response = att.ATT_Find_Information_Response(
650
624
  format=1 if len(attributes[0].type.to_pdu_bytes()) == 2 else 2,
651
625
  information_data=b''.join(information_data_list),
652
626
  )
653
627
  else:
654
- response = ATT_Error_Response(
628
+ response = att.ATT_Error_Response(
655
629
  request_opcode_in_error=request.op_code,
656
630
  attribute_handle_in_error=request.starting_handle,
657
- error_code=ATT_ATTRIBUTE_NOT_FOUND_ERROR,
631
+ error_code=att.ATT_ATTRIBUTE_NOT_FOUND_ERROR,
658
632
  )
659
633
 
660
634
  self.send_response(connection, response)
661
635
 
662
636
  @utils.AsyncRunner.run_in_task()
663
- async def on_att_find_by_type_value_request(self, connection, request):
637
+ async def on_att_find_by_type_value_request(
638
+ self, connection: Connection, request: att.ATT_Find_By_Type_Value_Request
639
+ ):
664
640
  '''
665
641
  See Bluetooth spec Vol 3, Part F - 3.4.3.3 Find By Type Value Request
666
642
  '''
@@ -668,6 +644,7 @@ class Server(utils.EventEmitter):
668
644
  # Build list of returned attributes
669
645
  pdu_space_available = connection.att_mtu - 2
670
646
  attributes = []
647
+ response: att.ATT_PDU
671
648
  async for attribute in (
672
649
  attribute
673
650
  for attribute in self.attributes
@@ -700,33 +677,35 @@ class Server(utils.EventEmitter):
700
677
  handles_information_list.append(
701
678
  struct.pack('<HH', attribute.handle, group_end_handle)
702
679
  )
703
- response = ATT_Find_By_Type_Value_Response(
680
+ response = att.ATT_Find_By_Type_Value_Response(
704
681
  handles_information_list=b''.join(handles_information_list)
705
682
  )
706
683
  else:
707
- response = ATT_Error_Response(
684
+ response = att.ATT_Error_Response(
708
685
  request_opcode_in_error=request.op_code,
709
686
  attribute_handle_in_error=request.starting_handle,
710
- error_code=ATT_ATTRIBUTE_NOT_FOUND_ERROR,
687
+ error_code=att.ATT_ATTRIBUTE_NOT_FOUND_ERROR,
711
688
  )
712
689
 
713
690
  self.send_response(connection, response)
714
691
 
715
692
  @utils.AsyncRunner.run_in_task()
716
- async def on_att_read_by_type_request(self, connection, request):
693
+ async def on_att_read_by_type_request(
694
+ self, connection: Connection, request: att.ATT_Read_By_Type_Request
695
+ ):
717
696
  '''
718
697
  See Bluetooth spec Vol 3, Part F - 3.4.4.1 Read By Type Request
719
698
  '''
720
699
 
721
700
  pdu_space_available = connection.att_mtu - 2
722
701
 
723
- response = ATT_Error_Response(
702
+ response: att.ATT_PDU = att.ATT_Error_Response(
724
703
  request_opcode_in_error=request.op_code,
725
704
  attribute_handle_in_error=request.starting_handle,
726
- error_code=ATT_ATTRIBUTE_NOT_FOUND_ERROR,
705
+ error_code=att.ATT_ATTRIBUTE_NOT_FOUND_ERROR,
727
706
  )
728
707
 
729
- attributes = []
708
+ attributes: list[tuple[int, bytes]] = []
730
709
  for attribute in (
731
710
  attribute
732
711
  for attribute in self.attributes
@@ -737,11 +716,11 @@ class Server(utils.EventEmitter):
737
716
  ):
738
717
  try:
739
718
  attribute_value = await attribute.read_value(connection)
740
- except ATT_Error as error:
719
+ except att.ATT_Error as error:
741
720
  # If the first attribute is unreadable, return an error
742
721
  # Otherwise return attributes up to this point
743
722
  if not attributes:
744
- response = ATT_Error_Response(
723
+ response = att.ATT_Error_Response(
745
724
  request_opcode_in_error=request.op_code,
746
725
  attribute_handle_in_error=attribute.handle,
747
726
  error_code=error.error_code,
@@ -770,7 +749,7 @@ class Server(utils.EventEmitter):
770
749
  attribute_data_list = [
771
750
  struct.pack('<H', handle) + value for handle, value in attributes
772
751
  ]
773
- response = ATT_Read_By_Type_Response(
752
+ response = att.ATT_Read_By_Type_Response(
774
753
  length=entry_size, attribute_data_list=b''.join(attribute_data_list)
775
754
  )
776
755
  else:
@@ -779,95 +758,104 @@ class Server(utils.EventEmitter):
779
758
  self.send_response(connection, response)
780
759
 
781
760
  @utils.AsyncRunner.run_in_task()
782
- async def on_att_read_request(self, connection, request):
761
+ async def on_att_read_request(
762
+ self, connection: Connection, request: att.ATT_Read_Request
763
+ ):
783
764
  '''
784
765
  See Bluetooth spec Vol 3, Part F - 3.4.4.3 Read Request
785
766
  '''
786
767
 
768
+ response: att.ATT_PDU
787
769
  if attribute := self.get_attribute(request.attribute_handle):
788
770
  try:
789
771
  value = await attribute.read_value(connection)
790
- except ATT_Error as error:
791
- response = ATT_Error_Response(
772
+ except att.ATT_Error as error:
773
+ response = att.ATT_Error_Response(
792
774
  request_opcode_in_error=request.op_code,
793
775
  attribute_handle_in_error=request.attribute_handle,
794
776
  error_code=error.error_code,
795
777
  )
796
778
  else:
797
779
  value_size = min(connection.att_mtu - 1, len(value))
798
- response = ATT_Read_Response(attribute_value=value[:value_size])
780
+ response = att.ATT_Read_Response(attribute_value=value[:value_size])
799
781
  else:
800
- response = ATT_Error_Response(
782
+ response = att.ATT_Error_Response(
801
783
  request_opcode_in_error=request.op_code,
802
784
  attribute_handle_in_error=request.attribute_handle,
803
- error_code=ATT_INVALID_HANDLE_ERROR,
785
+ error_code=att.ATT_INVALID_HANDLE_ERROR,
804
786
  )
805
787
  self.send_response(connection, response)
806
788
 
807
789
  @utils.AsyncRunner.run_in_task()
808
- async def on_att_read_blob_request(self, connection, request):
790
+ async def on_att_read_blob_request(
791
+ self, connection: Connection, request: att.ATT_Read_Blob_Request
792
+ ):
809
793
  '''
810
794
  See Bluetooth spec Vol 3, Part F - 3.4.4.5 Read Blob Request
811
795
  '''
812
796
 
797
+ response: att.ATT_PDU
813
798
  if attribute := self.get_attribute(request.attribute_handle):
814
799
  try:
815
800
  value = await attribute.read_value(connection)
816
- except ATT_Error as error:
817
- response = ATT_Error_Response(
801
+ except att.ATT_Error as error:
802
+ response = att.ATT_Error_Response(
818
803
  request_opcode_in_error=request.op_code,
819
804
  attribute_handle_in_error=request.attribute_handle,
820
805
  error_code=error.error_code,
821
806
  )
822
807
  else:
823
808
  if request.value_offset > len(value):
824
- response = ATT_Error_Response(
809
+ response = att.ATT_Error_Response(
825
810
  request_opcode_in_error=request.op_code,
826
811
  attribute_handle_in_error=request.attribute_handle,
827
- error_code=ATT_INVALID_OFFSET_ERROR,
812
+ error_code=att.ATT_INVALID_OFFSET_ERROR,
828
813
  )
829
814
  elif len(value) <= connection.att_mtu - 1:
830
- response = ATT_Error_Response(
815
+ response = att.ATT_Error_Response(
831
816
  request_opcode_in_error=request.op_code,
832
817
  attribute_handle_in_error=request.attribute_handle,
833
- error_code=ATT_ATTRIBUTE_NOT_LONG_ERROR,
818
+ error_code=att.ATT_ATTRIBUTE_NOT_LONG_ERROR,
834
819
  )
835
820
  else:
836
821
  part_size = min(
837
822
  connection.att_mtu - 1, len(value) - request.value_offset
838
823
  )
839
- response = ATT_Read_Blob_Response(
824
+ response = att.ATT_Read_Blob_Response(
840
825
  part_attribute_value=value[
841
826
  request.value_offset : request.value_offset + part_size
842
827
  ]
843
828
  )
844
829
  else:
845
- response = ATT_Error_Response(
830
+ response = att.ATT_Error_Response(
846
831
  request_opcode_in_error=request.op_code,
847
832
  attribute_handle_in_error=request.attribute_handle,
848
- error_code=ATT_INVALID_HANDLE_ERROR,
833
+ error_code=att.ATT_INVALID_HANDLE_ERROR,
849
834
  )
850
835
  self.send_response(connection, response)
851
836
 
852
837
  @utils.AsyncRunner.run_in_task()
853
- async def on_att_read_by_group_type_request(self, connection, request):
838
+ async def on_att_read_by_group_type_request(
839
+ self, connection: Connection, request: att.ATT_Read_By_Group_Type_Request
840
+ ):
854
841
  '''
855
842
  See Bluetooth spec Vol 3, Part F - 3.4.4.9 Read by Group Type Request
856
843
  '''
844
+ response: att.ATT_PDU
857
845
  if request.attribute_group_type not in (
858
846
  GATT_PRIMARY_SERVICE_ATTRIBUTE_TYPE,
859
847
  GATT_SECONDARY_SERVICE_ATTRIBUTE_TYPE,
860
848
  ):
861
- response = ATT_Error_Response(
849
+ response = att.ATT_Error_Response(
862
850
  request_opcode_in_error=request.op_code,
863
851
  attribute_handle_in_error=request.starting_handle,
864
- error_code=ATT_UNSUPPORTED_GROUP_TYPE_ERROR,
852
+ error_code=att.ATT_UNSUPPORTED_GROUP_TYPE_ERROR,
865
853
  )
866
854
  self.send_response(connection, response)
867
855
  return
868
856
 
869
857
  pdu_space_available = connection.att_mtu - 2
870
- attributes = []
858
+ attributes: list[tuple[int, int, bytes]] = []
871
859
  for attribute in (
872
860
  attribute
873
861
  for attribute in self.attributes
@@ -904,21 +892,23 @@ class Server(utils.EventEmitter):
904
892
  struct.pack('<HH', handle, end_group_handle) + value
905
893
  for handle, end_group_handle, value in attributes
906
894
  ]
907
- response = ATT_Read_By_Group_Type_Response(
895
+ response = att.ATT_Read_By_Group_Type_Response(
908
896
  length=len(attribute_data_list[0]),
909
897
  attribute_data_list=b''.join(attribute_data_list),
910
898
  )
911
899
  else:
912
- response = ATT_Error_Response(
900
+ response = att.ATT_Error_Response(
913
901
  request_opcode_in_error=request.op_code,
914
902
  attribute_handle_in_error=request.starting_handle,
915
- error_code=ATT_ATTRIBUTE_NOT_FOUND_ERROR,
903
+ error_code=att.ATT_ATTRIBUTE_NOT_FOUND_ERROR,
916
904
  )
917
905
 
918
906
  self.send_response(connection, response)
919
907
 
920
908
  @utils.AsyncRunner.run_in_task()
921
- async def on_att_write_request(self, connection, request):
909
+ async def on_att_write_request(
910
+ self, connection: Connection, request: att.ATT_Write_Request
911
+ ):
922
912
  '''
923
913
  See Bluetooth spec Vol 3, Part F - 3.4.5.1 Write Request
924
914
  '''
@@ -928,10 +918,10 @@ class Server(utils.EventEmitter):
928
918
  if attribute is None:
929
919
  self.send_response(
930
920
  connection,
931
- ATT_Error_Response(
921
+ att.ATT_Error_Response(
932
922
  request_opcode_in_error=request.op_code,
933
923
  attribute_handle_in_error=request.attribute_handle,
934
- error_code=ATT_INVALID_HANDLE_ERROR,
924
+ error_code=att.ATT_INVALID_HANDLE_ERROR,
935
925
  ),
936
926
  )
937
927
  return
@@ -942,30 +932,33 @@ class Server(utils.EventEmitter):
942
932
  if len(request.attribute_value) > GATT_MAX_ATTRIBUTE_VALUE_SIZE:
943
933
  self.send_response(
944
934
  connection,
945
- ATT_Error_Response(
935
+ att.ATT_Error_Response(
946
936
  request_opcode_in_error=request.op_code,
947
937
  attribute_handle_in_error=request.attribute_handle,
948
- error_code=ATT_INVALID_ATTRIBUTE_LENGTH_ERROR,
938
+ error_code=att.ATT_INVALID_ATTRIBUTE_LENGTH_ERROR,
949
939
  ),
950
940
  )
951
941
  return
952
942
 
943
+ response: att.ATT_PDU
953
944
  try:
954
945
  # Accept the value
955
946
  await attribute.write_value(connection, request.attribute_value)
956
- except ATT_Error as error:
957
- response = ATT_Error_Response(
947
+ except att.ATT_Error as error:
948
+ response = att.ATT_Error_Response(
958
949
  request_opcode_in_error=request.op_code,
959
950
  attribute_handle_in_error=request.attribute_handle,
960
951
  error_code=error.error_code,
961
952
  )
962
953
  else:
963
954
  # Done
964
- response = ATT_Write_Response()
955
+ response = att.ATT_Write_Response()
965
956
  self.send_response(connection, response)
966
957
 
967
958
  @utils.AsyncRunner.run_in_task()
968
- async def on_att_write_command(self, connection, request):
959
+ async def on_att_write_command(
960
+ self, connection: Connection, request: att.ATT_Write_Command
961
+ ):
969
962
  '''
970
963
  See Bluetooth spec Vol 3, Part F - 3.4.5.3 Write Command
971
964
  '''
@@ -984,18 +977,25 @@ class Server(utils.EventEmitter):
984
977
  # Accept the value
985
978
  try:
986
979
  await attribute.write_value(connection, request.attribute_value)
987
- except Exception as error:
988
- logger.exception(f'!!! ignoring exception: {error}')
980
+ except Exception:
981
+ logger.exception('!!! ignoring exception')
989
982
 
990
- def on_att_handle_value_confirmation(self, connection, _confirmation):
983
+ def on_att_handle_value_confirmation(
984
+ self,
985
+ connection: Connection,
986
+ confirmation: att.ATT_Handle_Value_Confirmation,
987
+ ):
991
988
  '''
992
989
  See Bluetooth spec Vol 3, Part F - 3.4.7.3 Handle Value Confirmation
993
990
  '''
994
- if self.pending_confirmations[connection.handle] is None:
991
+ del confirmation # Unused.
992
+ if (
993
+ pending_confirmation := self.pending_confirmations[connection.handle]
994
+ ) is None:
995
995
  # Not expected!
996
996
  logger.warning(
997
997
  '!!! unexpected confirmation, there is no pending indication'
998
998
  )
999
999
  return
1000
1000
 
1001
- self.pending_confirmations[connection.handle].set_result(None)
1001
+ pending_confirmation.set_result(None)