bumble 0.0.219__py3-none-any.whl → 0.0.221__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 (104) hide show
  1. bumble/_version.py +2 -2
  2. bumble/a2dp.py +5 -5
  3. bumble/apps/auracast.py +746 -479
  4. bumble/apps/bench.py +4 -5
  5. bumble/apps/console.py +5 -10
  6. bumble/apps/controller_info.py +12 -7
  7. bumble/apps/controller_loopback.py +1 -2
  8. bumble/apps/device_info.py +2 -3
  9. bumble/apps/gatt_dump.py +0 -1
  10. bumble/apps/lea_unicast/app.py +1 -1
  11. bumble/apps/pair.py +49 -46
  12. bumble/apps/pandora_server.py +2 -2
  13. bumble/apps/player/player.py +10 -12
  14. bumble/apps/rfcomm_bridge.py +10 -11
  15. bumble/apps/scan.py +1 -3
  16. bumble/apps/speaker/speaker.py +3 -4
  17. bumble/at.py +4 -5
  18. bumble/att.py +91 -25
  19. bumble/audio/io.py +8 -6
  20. bumble/avc.py +1 -2
  21. bumble/avctp.py +2 -3
  22. bumble/avdtp.py +53 -57
  23. bumble/avrcp.py +25 -27
  24. bumble/codecs.py +15 -15
  25. bumble/colors.py +7 -8
  26. bumble/controller.py +1201 -643
  27. bumble/core.py +41 -49
  28. bumble/crypto/__init__.py +2 -1
  29. bumble/crypto/builtin.py +2 -8
  30. bumble/data_types.py +2 -1
  31. bumble/decoder.py +2 -3
  32. bumble/device.py +278 -325
  33. bumble/drivers/__init__.py +3 -2
  34. bumble/drivers/intel.py +6 -8
  35. bumble/drivers/rtk.py +1 -1
  36. bumble/gatt.py +9 -9
  37. bumble/gatt_adapters.py +6 -6
  38. bumble/gatt_client.py +110 -60
  39. bumble/gatt_server.py +209 -139
  40. bumble/hci.py +87 -74
  41. bumble/helpers.py +5 -5
  42. bumble/hfp.py +27 -26
  43. bumble/hid.py +9 -9
  44. bumble/host.py +44 -50
  45. bumble/keys.py +17 -17
  46. bumble/l2cap.py +1015 -218
  47. bumble/link.py +54 -284
  48. bumble/ll.py +200 -0
  49. bumble/lmp.py +324 -0
  50. bumble/pairing.py +14 -15
  51. bumble/pandora/__init__.py +2 -2
  52. bumble/pandora/device.py +6 -4
  53. bumble/pandora/host.py +19 -10
  54. bumble/pandora/l2cap.py +8 -9
  55. bumble/pandora/security.py +18 -16
  56. bumble/pandora/utils.py +4 -4
  57. bumble/profiles/aics.py +6 -8
  58. bumble/profiles/ams.py +3 -5
  59. bumble/profiles/ancs.py +11 -11
  60. bumble/profiles/ascs.py +5 -5
  61. bumble/profiles/asha.py +10 -9
  62. bumble/profiles/bass.py +9 -3
  63. bumble/profiles/battery_service.py +1 -2
  64. bumble/profiles/csip.py +9 -10
  65. bumble/profiles/device_information_service.py +16 -17
  66. bumble/profiles/gap.py +3 -4
  67. bumble/profiles/gatt_service.py +0 -1
  68. bumble/profiles/gmap.py +12 -13
  69. bumble/profiles/hap.py +3 -3
  70. bumble/profiles/heart_rate_service.py +7 -8
  71. bumble/profiles/le_audio.py +1 -1
  72. bumble/profiles/mcp.py +28 -28
  73. bumble/profiles/pacs.py +13 -17
  74. bumble/profiles/pbp.py +16 -0
  75. bumble/profiles/vcs.py +2 -2
  76. bumble/profiles/vocs.py +6 -9
  77. bumble/rfcomm.py +19 -18
  78. bumble/sdp.py +12 -11
  79. bumble/smp.py +20 -30
  80. bumble/snoop.py +12 -5
  81. bumble/tools/generate_company_id_list.py +1 -1
  82. bumble/tools/intel_util.py +2 -2
  83. bumble/tools/rtk_fw_download.py +1 -1
  84. bumble/tools/rtk_util.py +1 -1
  85. bumble/transport/__init__.py +1 -2
  86. bumble/transport/android_emulator.py +2 -3
  87. bumble/transport/android_netsim.py +49 -40
  88. bumble/transport/common.py +9 -9
  89. bumble/transport/file.py +1 -2
  90. bumble/transport/hci_socket.py +2 -3
  91. bumble/transport/pty.py +3 -5
  92. bumble/transport/pyusb.py +8 -5
  93. bumble/transport/serial.py +1 -2
  94. bumble/transport/vhci.py +1 -2
  95. bumble/transport/ws_server.py +2 -3
  96. bumble/utils.py +23 -14
  97. bumble/vendor/android/hci.py +4 -2
  98. {bumble-0.0.219.dist-info → bumble-0.0.221.dist-info}/METADATA +4 -3
  99. bumble-0.0.221.dist-info/RECORD +185 -0
  100. bumble-0.0.219.dist-info/RECORD +0 -183
  101. {bumble-0.0.219.dist-info → bumble-0.0.221.dist-info}/WHEEL +0 -0
  102. {bumble-0.0.219.dist-info → bumble-0.0.221.dist-info}/entry_points.txt +0 -0
  103. {bumble-0.0.219.dist-info → bumble-0.0.221.dist-info}/licenses/LICENSE +0 -0
  104. {bumble-0.0.219.dist-info → bumble-0.0.221.dist-info}/top_level.txt +0 -0
bumble/pandora/utils.py CHANGED
@@ -18,7 +18,8 @@ import contextlib
18
18
  import functools
19
19
  import inspect
20
20
  import logging
21
- from typing import Any, Generator, MutableMapping, Optional
21
+ from collections.abc import Generator, MutableMapping
22
+ from typing import Any
22
23
 
23
24
  import grpc
24
25
  from google.protobuf.message import Message # pytype: disable=pyi-error
@@ -34,7 +35,7 @@ ADDRESS_TYPES: dict[str, AddressType] = {
34
35
  }
35
36
 
36
37
 
37
- def address_from_request(request: Message, field: Optional[str]) -> Address:
38
+ def address_from_request(request: Message, field: str | None) -> Address:
38
39
  if field is None:
39
40
  return Address.ANY
40
41
  return Address(bytes(reversed(getattr(request, field))), ADDRESS_TYPES[field])
@@ -95,8 +96,7 @@ def rpc(func: Any) -> Any:
95
96
  @functools.wraps(func)
96
97
  def gen_wrapper(self: Any, request: Any, context: grpc.ServicerContext) -> Any:
97
98
  with exception_to_rpc_error(context):
98
- for v in func(self, request, context):
99
- yield v
99
+ yield from func(self, request, context)
100
100
 
101
101
  @functools.wraps(func)
102
102
  def wrapper(self: Any, request: Any, context: grpc.ServicerContext) -> Any:
bumble/profiles/aics.py CHANGED
@@ -22,7 +22,6 @@ from __future__ import annotations
22
22
  import logging
23
23
  import struct
24
24
  from dataclasses import dataclass
25
- from typing import Optional
26
25
 
27
26
  from bumble import utils
28
27
  from bumble.att import ATT_Error
@@ -129,7 +128,7 @@ class AudioInputState:
129
128
  mute: Mute = Mute.NOT_MUTED
130
129
  gain_mode: GainMode = GainMode.MANUAL
131
130
  change_counter: int = 0
132
- attribute: Optional[Attribute] = None
131
+ attribute: Attribute | None = None
133
132
 
134
133
  def __bytes__(self) -> bytes:
135
134
  return bytes(
@@ -199,7 +198,6 @@ class AudioInputControlPoint:
199
198
  gain_settings_properties: GainSettingsProperties
200
199
 
201
200
  async def on_write(self, connection: Connection, value: bytes) -> None:
202
-
203
201
  opcode = AudioInputControlPointOpCode(value[0])
204
202
 
205
203
  if opcode == AudioInputControlPointOpCode.SET_GAIN_SETTING:
@@ -317,7 +315,7 @@ class AudioInputDescription:
317
315
  '''
318
316
 
319
317
  audio_input_description: str = "Bluetooth"
320
- attribute: Optional[Attribute] = None
318
+ attribute: Attribute | None = None
321
319
 
322
320
  def on_read(self, _connection: Connection) -> str:
323
321
  return self.audio_input_description
@@ -340,11 +338,11 @@ class AICSService(TemplateService):
340
338
 
341
339
  def __init__(
342
340
  self,
343
- audio_input_state: Optional[AudioInputState] = None,
344
- gain_settings_properties: Optional[GainSettingsProperties] = None,
341
+ audio_input_state: AudioInputState | None = None,
342
+ gain_settings_properties: GainSettingsProperties | None = None,
345
343
  audio_input_type: str = "local",
346
- audio_input_status: Optional[AudioInputStatus] = None,
347
- audio_input_description: Optional[AudioInputDescription] = None,
344
+ audio_input_status: AudioInputStatus | None = None,
345
+ audio_input_description: AudioInputDescription | None = None,
348
346
  ):
349
347
  self.audio_input_state = (
350
348
  AudioInputState() if audio_input_state is None else audio_input_state
bumble/profiles/ams.py CHANGED
@@ -25,7 +25,7 @@ import asyncio
25
25
  import dataclasses
26
26
  import enum
27
27
  import logging
28
- from typing import Iterable, Optional, Union
28
+ from collections.abc import Iterable
29
29
 
30
30
  from bumble import utils
31
31
  from bumble.device import Peer
@@ -230,7 +230,7 @@ class AmsClient(utils.EventEmitter):
230
230
  self.supported_commands = set()
231
231
 
232
232
  @classmethod
233
- async def for_peer(cls, peer: Peer) -> Optional[AmsClient]:
233
+ async def for_peer(cls, peer: Peer) -> AmsClient | None:
234
234
  ams_proxy = await peer.discover_service_and_create_proxy(AmsProxy)
235
235
  if ams_proxy is None:
236
236
  return None
@@ -263,9 +263,7 @@ class AmsClient(utils.EventEmitter):
263
263
  async def observe(
264
264
  self,
265
265
  entity: EntityId,
266
- attributes: Iterable[
267
- Union[PlayerAttributeId, QueueAttributeId, TrackAttributeId]
268
- ],
266
+ attributes: Iterable[PlayerAttributeId | QueueAttributeId | TrackAttributeId],
269
267
  ) -> None:
270
268
  await self._ams_proxy.entity_update.write_value(
271
269
  bytes([entity] + list(attributes)), with_response=True
bumble/profiles/ancs.py CHANGED
@@ -27,7 +27,7 @@ import datetime
27
27
  import enum
28
28
  import logging
29
29
  import struct
30
- from typing import Optional, Sequence, Union
30
+ from collections.abc import Sequence
31
31
 
32
32
  from bumble import utils
33
33
  from bumble.att import ATT_Error
@@ -116,7 +116,7 @@ class NotificationAttributeId(utils.OpenIntEnum):
116
116
  @dataclasses.dataclass
117
117
  class NotificationAttribute:
118
118
  attribute_id: NotificationAttributeId
119
- value: Union[str, int, datetime.datetime]
119
+ value: str | int | datetime.datetime
120
120
 
121
121
 
122
122
  @dataclasses.dataclass
@@ -242,10 +242,10 @@ class AncsProxy(ProfileServiceProxy):
242
242
 
243
243
 
244
244
  class AncsClient(utils.EventEmitter):
245
- _expected_response_command_id: Optional[CommandId]
246
- _expected_response_notification_uid: Optional[int]
247
- _expected_response_app_identifier: Optional[str]
248
- _expected_app_identifier: Optional[str]
245
+ _expected_response_command_id: CommandId | None
246
+ _expected_response_notification_uid: int | None
247
+ _expected_response_app_identifier: str | None
248
+ _expected_app_identifier: str | None
249
249
  _expected_response_tuples: int
250
250
  _response_accumulator: bytes
251
251
 
@@ -255,12 +255,12 @@ class AncsClient(utils.EventEmitter):
255
255
  super().__init__()
256
256
  self._ancs_proxy = ancs_proxy
257
257
  self._command_semaphore = asyncio.Semaphore()
258
- self._response: Optional[asyncio.Future] = None
258
+ self._response: asyncio.Future | None = None
259
259
  self._reset_response()
260
260
  self._started = False
261
261
 
262
262
  @classmethod
263
- async def for_peer(cls, peer: Peer) -> Optional[AncsClient]:
263
+ async def for_peer(cls, peer: Peer) -> AncsClient | None:
264
264
  ancs_proxy = await peer.discover_service_and_create_proxy(AncsProxy)
265
265
  if ancs_proxy is None:
266
266
  return None
@@ -316,7 +316,7 @@ class AncsClient(utils.EventEmitter):
316
316
  # Not enough data yet.
317
317
  return
318
318
 
319
- attributes: list[Union[NotificationAttribute, AppAttribute]] = []
319
+ attributes: list[NotificationAttribute | AppAttribute] = []
320
320
 
321
321
  if command_id == CommandId.GET_NOTIFICATION_ATTRIBUTES:
322
322
  (notification_uid,) = struct.unpack_from(
@@ -342,7 +342,7 @@ class AncsClient(utils.EventEmitter):
342
342
  str_value = attribute_data[3 : 3 + attribute_data_length].decode(
343
343
  "utf-8"
344
344
  )
345
- value: Union[str, int, datetime.datetime]
345
+ value: str | int | datetime.datetime
346
346
  if attribute_id == NotificationAttributeId.MESSAGE_SIZE:
347
347
  value = int(str_value)
348
348
  elif attribute_id == NotificationAttributeId.DATE:
@@ -415,7 +415,7 @@ class AncsClient(utils.EventEmitter):
415
415
  self,
416
416
  notification_uid: int,
417
417
  attributes: Sequence[
418
- Union[NotificationAttributeId, tuple[NotificationAttributeId, int]]
418
+ NotificationAttributeId | tuple[NotificationAttributeId, int]
419
419
  ],
420
420
  ) -> list[NotificationAttribute]:
421
421
  if not self._started:
bumble/profiles/ascs.py CHANGED
@@ -24,7 +24,7 @@ import logging
24
24
  import struct
25
25
  from collections.abc import Sequence
26
26
  from dataclasses import dataclass, field
27
- from typing import Any, Optional, TypeVar, Union
27
+ from typing import Any, TypeVar
28
28
 
29
29
  from bumble import colors, device, gatt, gatt_client, hci, utils
30
30
  from bumble.profiles import le_audio
@@ -49,7 +49,7 @@ class ASE_Operation:
49
49
  classes: dict[int, type[ASE_Operation]] = {}
50
50
  op_code: Opcode
51
51
  name: str
52
- fields: Optional[Sequence[Any]] = None
52
+ fields: Sequence[Any] | None = None
53
53
  ase_id: Sequence[int]
54
54
 
55
55
  class Opcode(enum.IntEnum):
@@ -278,7 +278,7 @@ class AseStateMachine(gatt.Characteristic):
278
278
 
279
279
  EVENT_STATE_CHANGE = "state_change"
280
280
 
281
- cis_link: Optional[device.CisLink] = None
281
+ cis_link: device.CisLink | None = None
282
282
 
283
283
  # Additional parameters in CODEC_CONFIGURED State
284
284
  preferred_framing = 0 # Unframed PDU supported
@@ -290,7 +290,7 @@ class AseStateMachine(gatt.Characteristic):
290
290
  preferred_presentation_delay_min = 0
291
291
  preferred_presentation_delay_max = 0
292
292
  codec_id = hci.CodingFormat(hci.CodecID.LC3)
293
- codec_specific_configuration: Union[CodecSpecificConfiguration, bytes] = b''
293
+ codec_specific_configuration: CodecSpecificConfiguration | bytes = b''
294
294
 
295
295
  # Additional parameters in QOS_CONFIGURED State
296
296
  cig_id = 0
@@ -610,7 +610,7 @@ class AudioStreamControlService(gatt.TemplateService):
610
610
 
611
611
  ase_state_machines: dict[int, AseStateMachine]
612
612
  ase_control_point: gatt.Characteristic[bytes]
613
- _active_client: Optional[device.Connection] = None
613
+ _active_client: device.Connection | None = None
614
614
 
615
615
  def __init__(
616
616
  self,
bumble/profiles/asha.py CHANGED
@@ -19,7 +19,8 @@
19
19
  import enum
20
20
  import logging
21
21
  import struct
22
- from typing import Any, Callable, Optional, Union
22
+ from collections.abc import Callable
23
+ from typing import Any
23
24
 
24
25
  from bumble import data_types, gatt, gatt_client, l2cap, utils
25
26
  from bumble.core import AdvertisingData
@@ -90,20 +91,20 @@ class AshaService(gatt.TemplateService):
90
91
  EVENT_DISCONNECTED = "disconnected"
91
92
  EVENT_VOLUME_CHANGED = "volume_changed"
92
93
 
93
- audio_sink: Optional[Callable[[bytes], Any]]
94
- active_codec: Optional[Codec] = None
95
- audio_type: Optional[AudioType] = None
96
- volume: Optional[int] = None
97
- other_state: Optional[int] = None
98
- connection: Optional[Connection] = None
94
+ audio_sink: Callable[[bytes], Any] | None
95
+ active_codec: Codec | None = None
96
+ audio_type: AudioType | None = None
97
+ volume: int | None = None
98
+ other_state: int | None = None
99
+ connection: Connection | None = None
99
100
 
100
101
  def __init__(
101
102
  self,
102
103
  capability: int,
103
- hisyncid: Union[list[int], bytes],
104
+ hisyncid: list[int] | bytes,
104
105
  device: Device,
105
106
  psm: int = 0,
106
- audio_sink: Optional[Callable[[bytes], Any]] = None,
107
+ audio_sink: Callable[[bytes], Any] | None = None,
107
108
  feature_map: int = FeatureMap.LE_COC_AUDIO_OUTPUT_STREAMING_SUPPORTED,
108
109
  protocol_version: int = 0x01,
109
110
  render_delay_milliseconds: int = 0,
bumble/profiles/bass.py CHANGED
@@ -21,7 +21,8 @@ from __future__ import annotations
21
21
  import dataclasses
22
22
  import logging
23
23
  import struct
24
- from typing import ClassVar, Optional, Sequence
24
+ from collections.abc import Sequence
25
+ from typing import ClassVar
25
26
 
26
27
  from bumble import core, device, gatt, gatt_adapters, gatt_client, hci, utils
27
28
 
@@ -337,7 +338,12 @@ class BroadcastAudioScanService(gatt.TemplateService):
337
338
  b"12", # TEST
338
339
  )
339
340
 
340
- super().__init__([self.battery_level_characteristic])
341
+ super().__init__(
342
+ [
343
+ self.broadcast_audio_scan_control_point_characteristic,
344
+ self.broadcast_receive_state_characteristic,
345
+ ]
346
+ )
341
347
 
342
348
  def on_broadcast_audio_scan_control_point_write(
343
349
  self, connection: device.Connection, value: bytes
@@ -351,7 +357,7 @@ class BroadcastAudioScanServiceProxy(gatt_client.ProfileServiceProxy):
351
357
 
352
358
  broadcast_audio_scan_control_point: gatt_client.CharacteristicProxy[bytes]
353
359
  broadcast_receive_states: list[
354
- gatt_client.CharacteristicProxy[Optional[BroadcastReceiveState]]
360
+ gatt_client.CharacteristicProxy[BroadcastReceiveState | None]
355
361
  ]
356
362
 
357
363
  def __init__(self, service_proxy: gatt_client.ServiceProxy):
@@ -16,7 +16,6 @@
16
16
  # -----------------------------------------------------------------------------
17
17
  # Imports
18
18
  # -----------------------------------------------------------------------------
19
- from typing import Optional
20
19
 
21
20
  from bumble.gatt import (
22
21
  GATT_BATTERY_LEVEL_CHARACTERISTIC,
@@ -56,7 +55,7 @@ class BatteryService(TemplateService):
56
55
  class BatteryServiceProxy(ProfileServiceProxy):
57
56
  SERVICE_CLASS = BatteryService
58
57
 
59
- battery_level: Optional[CharacteristicProxy[int]]
58
+ battery_level: CharacteristicProxy[int] | None
60
59
 
61
60
  def __init__(self, service_proxy):
62
61
  self.service_proxy = service_proxy
bumble/profiles/csip.py CHANGED
@@ -20,7 +20,6 @@ from __future__ import annotations
20
20
 
21
21
  import enum
22
22
  import struct
23
- from typing import Optional
24
23
 
25
24
  from bumble import core, crypto, device, gatt, gatt_client
26
25
 
@@ -96,17 +95,17 @@ class CoordinatedSetIdentificationService(gatt.TemplateService):
96
95
 
97
96
  set_identity_resolving_key: bytes
98
97
  set_identity_resolving_key_characteristic: gatt.Characteristic[bytes]
99
- coordinated_set_size_characteristic: Optional[gatt.Characteristic[bytes]] = None
100
- set_member_lock_characteristic: Optional[gatt.Characteristic[bytes]] = None
101
- set_member_rank_characteristic: Optional[gatt.Characteristic[bytes]] = None
98
+ coordinated_set_size_characteristic: gatt.Characteristic[bytes] | None = None
99
+ set_member_lock_characteristic: gatt.Characteristic[bytes] | None = None
100
+ set_member_rank_characteristic: gatt.Characteristic[bytes] | None = None
102
101
 
103
102
  def __init__(
104
103
  self,
105
104
  set_identity_resolving_key: bytes,
106
105
  set_identity_resolving_key_type: SirkType,
107
- coordinated_set_size: Optional[int] = None,
108
- set_member_lock: Optional[MemberLock] = None,
109
- set_member_rank: Optional[int] = None,
106
+ coordinated_set_size: int | None = None,
107
+ set_member_lock: MemberLock | None = None,
108
+ set_member_rank: int | None = None,
110
109
  ) -> None:
111
110
  if len(set_identity_resolving_key) != SET_IDENTITY_RESOLVING_KEY_LENGTH:
112
111
  raise core.InvalidArgumentError(
@@ -198,9 +197,9 @@ class CoordinatedSetIdentificationProxy(gatt_client.ProfileServiceProxy):
198
197
  SERVICE_CLASS = CoordinatedSetIdentificationService
199
198
 
200
199
  set_identity_resolving_key: gatt_client.CharacteristicProxy[bytes]
201
- coordinated_set_size: Optional[gatt_client.CharacteristicProxy[bytes]] = None
202
- set_member_lock: Optional[gatt_client.CharacteristicProxy[bytes]] = None
203
- set_member_rank: Optional[gatt_client.CharacteristicProxy[bytes]] = None
200
+ coordinated_set_size: gatt_client.CharacteristicProxy[bytes] | None = None
201
+ set_member_lock: gatt_client.CharacteristicProxy[bytes] | None = None
202
+ set_member_rank: gatt_client.CharacteristicProxy[bytes] | None = None
204
203
 
205
204
  def __init__(self, service_proxy: gatt_client.ServiceProxy) -> None:
206
205
  self.service_proxy = service_proxy
@@ -17,7 +17,6 @@
17
17
  # Imports
18
18
  # -----------------------------------------------------------------------------
19
19
  import struct
20
- from typing import Optional
21
20
 
22
21
  from bumble.gatt import (
23
22
  GATT_DEVICE_INFORMATION_SERVICE,
@@ -54,14 +53,14 @@ class DeviceInformationService(TemplateService):
54
53
 
55
54
  def __init__(
56
55
  self,
57
- manufacturer_name: Optional[str] = None,
58
- model_number: Optional[str] = None,
59
- serial_number: Optional[str] = None,
60
- hardware_revision: Optional[str] = None,
61
- firmware_revision: Optional[str] = None,
62
- software_revision: Optional[str] = None,
63
- system_id: Optional[tuple[int, int]] = None, # (OUI, Manufacturer ID)
64
- ieee_regulatory_certification_data_list: Optional[bytes] = None,
56
+ manufacturer_name: str | None = None,
57
+ model_number: str | None = None,
58
+ serial_number: str | None = None,
59
+ hardware_revision: str | None = None,
60
+ firmware_revision: str | None = None,
61
+ software_revision: str | None = None,
62
+ system_id: tuple[int, int] | None = None, # (OUI, Manufacturer ID)
63
+ ieee_regulatory_certification_data_list: bytes | None = None,
65
64
  # TODO: pnp_id
66
65
  ):
67
66
  characteristics: list[Characteristic[bytes]] = [
@@ -109,14 +108,14 @@ class DeviceInformationService(TemplateService):
109
108
  class DeviceInformationServiceProxy(ProfileServiceProxy):
110
109
  SERVICE_CLASS = DeviceInformationService
111
110
 
112
- manufacturer_name: Optional[CharacteristicProxy[str]]
113
- model_number: Optional[CharacteristicProxy[str]]
114
- serial_number: Optional[CharacteristicProxy[str]]
115
- hardware_revision: Optional[CharacteristicProxy[str]]
116
- firmware_revision: Optional[CharacteristicProxy[str]]
117
- software_revision: Optional[CharacteristicProxy[str]]
118
- system_id: Optional[CharacteristicProxy[tuple[int, int]]]
119
- ieee_regulatory_certification_data_list: Optional[CharacteristicProxy[bytes]]
111
+ manufacturer_name: CharacteristicProxy[str] | None
112
+ model_number: CharacteristicProxy[str] | None
113
+ serial_number: CharacteristicProxy[str] | None
114
+ hardware_revision: CharacteristicProxy[str] | None
115
+ firmware_revision: CharacteristicProxy[str] | None
116
+ software_revision: CharacteristicProxy[str] | None
117
+ system_id: CharacteristicProxy[tuple[int, int]] | None
118
+ ieee_regulatory_certification_data_list: CharacteristicProxy[bytes] | None
120
119
 
121
120
  def __init__(self, service_proxy: ServiceProxy):
122
121
  self.service_proxy = service_proxy
bumble/profiles/gap.py CHANGED
@@ -19,7 +19,6 @@
19
19
  # -----------------------------------------------------------------------------
20
20
  import logging
21
21
  import struct
22
- from typing import Optional, Union
23
22
 
24
23
  from bumble.core import Appearance
25
24
  from bumble.gatt import (
@@ -54,7 +53,7 @@ class GenericAccessService(TemplateService):
54
53
  appearance_characteristic: Characteristic[bytes]
55
54
 
56
55
  def __init__(
57
- self, device_name: str, appearance: Union[Appearance, tuple[int, int], int] = 0
56
+ self, device_name: str, appearance: Appearance | tuple[int, int] | int = 0
58
57
  ):
59
58
  if isinstance(appearance, int):
60
59
  appearance_int = appearance
@@ -88,8 +87,8 @@ class GenericAccessService(TemplateService):
88
87
  class GenericAccessServiceProxy(ProfileServiceProxy):
89
88
  SERVICE_CLASS = GenericAccessService
90
89
 
91
- device_name: Optional[CharacteristicProxy[str]]
92
- appearance: Optional[CharacteristicProxy[Appearance]]
90
+ device_name: CharacteristicProxy[str] | None
91
+ appearance: CharacteristicProxy[Appearance] | None
93
92
 
94
93
  def __init__(self, service_proxy: ServiceProxy):
95
94
  self.service_proxy = service_proxy
@@ -40,7 +40,6 @@ class GenericAttributeProfileService(gatt.TemplateService):
40
40
  database_hash_enabled: bool = True,
41
41
  service_change_enabled: bool = True,
42
42
  ) -> None:
43
-
44
43
  if server_supported_features is not None:
45
44
  self.server_supported_features_characteristic = gatt.Characteristic(
46
45
  uuid=gatt.GATT_SERVER_SUPPORTED_FEATURES_CHARACTERISTIC,
bumble/profiles/gmap.py CHANGED
@@ -19,7 +19,6 @@
19
19
  # -----------------------------------------------------------------------------
20
20
  import struct
21
21
  from enum import IntFlag
22
- from typing import Optional
23
22
 
24
23
  from bumble.gatt import (
25
24
  GATT_BGR_FEATURES_CHARACTERISTIC,
@@ -77,18 +76,18 @@ class GamingAudioService(TemplateService):
77
76
  UUID = GATT_GAMING_AUDIO_SERVICE
78
77
 
79
78
  gmap_role: Characteristic
80
- ugg_features: Optional[Characteristic] = None
81
- ugt_features: Optional[Characteristic] = None
82
- bgs_features: Optional[Characteristic] = None
83
- bgr_features: Optional[Characteristic] = None
79
+ ugg_features: Characteristic | None = None
80
+ ugt_features: Characteristic | None = None
81
+ bgs_features: Characteristic | None = None
82
+ bgr_features: Characteristic | None = None
84
83
 
85
84
  def __init__(
86
85
  self,
87
86
  gmap_role: GmapRole,
88
- ugg_features: Optional[UggFeatures] = None,
89
- ugt_features: Optional[UgtFeatures] = None,
90
- bgs_features: Optional[BgsFeatures] = None,
91
- bgr_features: Optional[BgrFeatures] = None,
87
+ ugg_features: UggFeatures | None = None,
88
+ ugt_features: UgtFeatures | None = None,
89
+ bgs_features: BgsFeatures | None = None,
90
+ bgr_features: BgrFeatures | None = None,
92
91
  ) -> None:
93
92
  characteristics = []
94
93
 
@@ -150,10 +149,10 @@ class GamingAudioService(TemplateService):
150
149
  class GamingAudioServiceProxy(ProfileServiceProxy):
151
150
  SERVICE_CLASS = GamingAudioService
152
151
 
153
- ugg_features: Optional[CharacteristicProxy[UggFeatures]] = None
154
- ugt_features: Optional[CharacteristicProxy[UgtFeatures]] = None
155
- bgs_features: Optional[CharacteristicProxy[BgsFeatures]] = None
156
- bgr_features: Optional[CharacteristicProxy[BgrFeatures]] = None
152
+ ugg_features: CharacteristicProxy[UggFeatures] | None = None
153
+ ugt_features: CharacteristicProxy[UgtFeatures] | None = None
154
+ bgs_features: CharacteristicProxy[BgsFeatures] | None = None
155
+ bgr_features: CharacteristicProxy[BgrFeatures] | None = None
157
156
 
158
157
  def __init__(self, service_proxy: ServiceProxy) -> None:
159
158
  self.service_proxy = service_proxy
bumble/profiles/hap.py CHANGED
@@ -20,7 +20,7 @@ from __future__ import annotations
20
20
  import asyncio
21
21
  import logging
22
22
  from dataclasses import dataclass, field
23
- from typing import Any, Optional, Union
23
+ from typing import Any
24
24
 
25
25
  from bumble import att, gatt, gatt_adapters, gatt_client, utils
26
26
  from bumble.core import InvalidArgumentError, InvalidStateError
@@ -145,7 +145,7 @@ class PresetChangedOperation:
145
145
  return bytes([self.prev_index]) + bytes(self.preset_record)
146
146
 
147
147
  change_id: ChangeId
148
- additional_parameters: Union[Generic, int]
148
+ additional_parameters: Generic | int
149
149
 
150
150
  def to_bytes(self, is_last: bool) -> bytes:
151
151
  if isinstance(self.additional_parameters, PresetChangedOperation.Generic):
@@ -235,7 +235,7 @@ class HearingAccessService(gatt.TemplateService):
235
235
  preset_records: dict[int, PresetRecord] # key is the preset index
236
236
  read_presets_request_in_progress: bool
237
237
 
238
- other_server_in_binaural_set: Optional[HearingAccessService] = None
238
+ other_server_in_binaural_set: HearingAccessService | None = None
239
239
 
240
240
  preset_changed_operations_history_per_device: dict[
241
241
  Address, list[PresetChangedOperation]
@@ -20,7 +20,6 @@ from __future__ import annotations
20
20
 
21
21
  import struct
22
22
  from enum import IntEnum
23
- from typing import Optional
24
23
 
25
24
  from bumble import core
26
25
  from bumble.att import ATT_Error
@@ -207,13 +206,13 @@ class HeartRateService(TemplateService):
207
206
  class HeartRateServiceProxy(ProfileServiceProxy):
208
207
  SERVICE_CLASS = HeartRateService
209
208
 
210
- heart_rate_measurement: Optional[
211
- CharacteristicProxy[HeartRateService.HeartRateMeasurement]
212
- ]
213
- body_sensor_location: Optional[
214
- CharacteristicProxy[HeartRateService.BodySensorLocation]
215
- ]
216
- heart_rate_control_point: Optional[CharacteristicProxy[int]]
209
+ heart_rate_measurement: (
210
+ CharacteristicProxy[HeartRateService.HeartRateMeasurement] | None
211
+ )
212
+ body_sensor_location: (
213
+ CharacteristicProxy[HeartRateService.BodySensorLocation] | None
214
+ )
215
+ heart_rate_control_point: CharacteristicProxy[int] | None
217
216
 
218
217
  def __init__(self, service_proxy):
219
218
  self.service_proxy = service_proxy
@@ -137,7 +137,7 @@ class Metadata:
137
137
  values.append(str(decoded))
138
138
 
139
139
  return '\n'.join(
140
- f'{indent}{key}: {" " * (max_key_length-len(key))}{value}'
140
+ f'{indent}{key}: {" " * (max_key_length - len(key))}{value}'
141
141
  for key, value in zip(keys, values)
142
142
  )
143
143
 
bumble/profiles/mcp.py CHANGED
@@ -22,7 +22,7 @@ import asyncio
22
22
  import dataclasses
23
23
  import enum
24
24
  import struct
25
- from typing import TYPE_CHECKING, ClassVar, Optional
25
+ from typing import TYPE_CHECKING, ClassVar
26
26
 
27
27
  from typing_extensions import Self
28
28
 
@@ -196,7 +196,7 @@ class MediaControlService(gatt.TemplateService):
196
196
 
197
197
  UUID = gatt.GATT_MEDIA_CONTROL_SERVICE
198
198
 
199
- def __init__(self, media_player_name: Optional[str] = None) -> None:
199
+ def __init__(self, media_player_name: str | None = None) -> None:
200
200
  self.track_position = 0
201
201
 
202
202
  self.media_player_name_characteristic = gatt.Characteristic(
@@ -337,32 +337,32 @@ class MediaControlServiceProxy(
337
337
  EVENT_TRACK_DURATION = "track_duration"
338
338
  EVENT_TRACK_POSITION = "track_position"
339
339
 
340
- media_player_name: Optional[gatt_client.CharacteristicProxy[bytes]] = None
341
- media_player_icon_object_id: Optional[gatt_client.CharacteristicProxy[bytes]] = None
342
- media_player_icon_url: Optional[gatt_client.CharacteristicProxy[bytes]] = None
343
- track_changed: Optional[gatt_client.CharacteristicProxy[bytes]] = None
344
- track_title: Optional[gatt_client.CharacteristicProxy[bytes]] = None
345
- track_duration: Optional[gatt_client.CharacteristicProxy[bytes]] = None
346
- track_position: Optional[gatt_client.CharacteristicProxy[bytes]] = None
347
- playback_speed: Optional[gatt_client.CharacteristicProxy[bytes]] = None
348
- seeking_speed: Optional[gatt_client.CharacteristicProxy[bytes]] = None
349
- current_track_segments_object_id: Optional[
350
- gatt_client.CharacteristicProxy[bytes]
351
- ] = None
352
- current_track_object_id: Optional[gatt_client.CharacteristicProxy[bytes]] = None
353
- next_track_object_id: Optional[gatt_client.CharacteristicProxy[bytes]] = None
354
- parent_group_object_id: Optional[gatt_client.CharacteristicProxy[bytes]] = None
355
- current_group_object_id: Optional[gatt_client.CharacteristicProxy[bytes]] = None
356
- playing_order: Optional[gatt_client.CharacteristicProxy[bytes]] = None
357
- playing_orders_supported: Optional[gatt_client.CharacteristicProxy[bytes]] = None
358
- media_state: Optional[gatt_client.CharacteristicProxy[bytes]] = None
359
- media_control_point: Optional[gatt_client.CharacteristicProxy[bytes]] = None
360
- media_control_point_opcodes_supported: Optional[
361
- gatt_client.CharacteristicProxy[bytes]
362
- ] = None
363
- search_control_point: Optional[gatt_client.CharacteristicProxy[bytes]] = None
364
- search_results_object_id: Optional[gatt_client.CharacteristicProxy[bytes]] = None
365
- content_control_id: Optional[gatt_client.CharacteristicProxy[bytes]] = None
340
+ media_player_name: gatt_client.CharacteristicProxy[bytes] | None = None
341
+ media_player_icon_object_id: gatt_client.CharacteristicProxy[bytes] | None = None
342
+ media_player_icon_url: gatt_client.CharacteristicProxy[bytes] | None = None
343
+ track_changed: gatt_client.CharacteristicProxy[bytes] | None = None
344
+ track_title: gatt_client.CharacteristicProxy[bytes] | None = None
345
+ track_duration: gatt_client.CharacteristicProxy[bytes] | None = None
346
+ track_position: gatt_client.CharacteristicProxy[bytes] | None = None
347
+ playback_speed: gatt_client.CharacteristicProxy[bytes] | None = None
348
+ seeking_speed: gatt_client.CharacteristicProxy[bytes] | None = None
349
+ current_track_segments_object_id: gatt_client.CharacteristicProxy[bytes] | None = (
350
+ None
351
+ )
352
+ current_track_object_id: gatt_client.CharacteristicProxy[bytes] | None = None
353
+ next_track_object_id: gatt_client.CharacteristicProxy[bytes] | None = None
354
+ parent_group_object_id: gatt_client.CharacteristicProxy[bytes] | None = None
355
+ current_group_object_id: gatt_client.CharacteristicProxy[bytes] | None = None
356
+ playing_order: gatt_client.CharacteristicProxy[bytes] | None = None
357
+ playing_orders_supported: gatt_client.CharacteristicProxy[bytes] | None = None
358
+ media_state: gatt_client.CharacteristicProxy[bytes] | None = None
359
+ media_control_point: gatt_client.CharacteristicProxy[bytes] | None = None
360
+ media_control_point_opcodes_supported: (
361
+ gatt_client.CharacteristicProxy[bytes] | None
362
+ ) = None
363
+ search_control_point: gatt_client.CharacteristicProxy[bytes] | None = None
364
+ search_results_object_id: gatt_client.CharacteristicProxy[bytes] | None = None
365
+ content_control_id: gatt_client.CharacteristicProxy[bytes] | None = None
366
366
 
367
367
  if TYPE_CHECKING:
368
368
  media_control_point_notifications: asyncio.Queue[bytes]