bumble 0.0.178__py3-none-any.whl → 0.0.180__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/device.py CHANGED
@@ -23,6 +23,7 @@ import asyncio
23
23
  import logging
24
24
  from contextlib import asynccontextmanager, AsyncExitStack
25
25
  from dataclasses import dataclass
26
+ from collections.abc import Iterable
26
27
  from typing import (
27
28
  Any,
28
29
  Callable,
@@ -32,6 +33,8 @@ from typing import (
32
33
  Optional,
33
34
  Tuple,
34
35
  Type,
36
+ TypeVar,
37
+ Set,
35
38
  Union,
36
39
  cast,
37
40
  overload,
@@ -99,13 +102,20 @@ from .hci import (
99
102
  HCI_LE_Extended_Create_Connection_Command,
100
103
  HCI_LE_Rand_Command,
101
104
  HCI_LE_Read_PHY_Command,
105
+ HCI_LE_Remove_Advertising_Set_Command,
102
106
  HCI_LE_Set_Address_Resolution_Enable_Command,
103
107
  HCI_LE_Set_Advertising_Data_Command,
104
108
  HCI_LE_Set_Advertising_Enable_Command,
105
109
  HCI_LE_Set_Advertising_Parameters_Command,
110
+ HCI_LE_Set_Advertising_Set_Random_Address_Command,
111
+ HCI_LE_Set_Data_Length_Command,
106
112
  HCI_LE_Set_Default_PHY_Command,
107
113
  HCI_LE_Set_Extended_Scan_Enable_Command,
108
114
  HCI_LE_Set_Extended_Scan_Parameters_Command,
115
+ HCI_LE_Set_Extended_Scan_Response_Data_Command,
116
+ HCI_LE_Set_Extended_Advertising_Data_Command,
117
+ HCI_LE_Set_Extended_Advertising_Enable_Command,
118
+ HCI_LE_Set_Extended_Advertising_Parameters_Command,
109
119
  HCI_LE_Set_PHY_Command,
110
120
  HCI_LE_Set_Random_Address_Command,
111
121
  HCI_LE_Set_Scan_Enable_Command,
@@ -154,6 +164,7 @@ from .utils import (
154
164
  setup_event_forwarding,
155
165
  composite_listener,
156
166
  deprecated,
167
+ experimental,
157
168
  )
158
169
  from .keys import (
159
170
  KeyStore,
@@ -188,6 +199,8 @@ DEVICE_MIN_SCAN_WINDOW = 25
188
199
  DEVICE_MAX_SCAN_WINDOW = 10240
189
200
  DEVICE_MIN_LE_RSSI = -127
190
201
  DEVICE_MAX_LE_RSSI = 20
202
+ DEVICE_MIN_EXTENDED_ADVERTISING_SET_HANDLE = 0x00
203
+ DEVICE_MAX_EXTENDED_ADVERTISING_SET_HANDLE = 0xEF
191
204
 
192
205
  DEVICE_DEFAULT_ADDRESS = '00:00:00:00:00:00'
193
206
  DEVICE_DEFAULT_ADVERTISING_INTERVAL = 1000 # ms
@@ -429,8 +442,11 @@ class LePhyOptions:
429
442
 
430
443
 
431
444
  # -----------------------------------------------------------------------------
445
+ _PROXY_CLASS = TypeVar('_PROXY_CLASS', bound=gatt_client.ProfileServiceProxy)
446
+
447
+
432
448
  class Peer:
433
- def __init__(self, connection):
449
+ def __init__(self, connection: Connection) -> None:
434
450
  self.connection = connection
435
451
 
436
452
  # Create a GATT client for the connection
@@ -438,77 +454,113 @@ class Peer:
438
454
  connection.gatt_client = self.gatt_client
439
455
 
440
456
  @property
441
- def services(self):
457
+ def services(self) -> List[gatt_client.ServiceProxy]:
442
458
  return self.gatt_client.services
443
459
 
444
- async def request_mtu(self, mtu):
460
+ async def request_mtu(self, mtu: int) -> int:
445
461
  mtu = await self.gatt_client.request_mtu(mtu)
446
462
  self.connection.emit('connection_att_mtu_update')
447
463
  return mtu
448
464
 
449
- async def discover_service(self, uuid):
465
+ async def discover_service(
466
+ self, uuid: Union[core.UUID, str]
467
+ ) -> List[gatt_client.ServiceProxy]:
450
468
  return await self.gatt_client.discover_service(uuid)
451
469
 
452
- async def discover_services(self, uuids=()):
470
+ async def discover_services(
471
+ self, uuids: Iterable[core.UUID] = ()
472
+ ) -> List[gatt_client.ServiceProxy]:
453
473
  return await self.gatt_client.discover_services(uuids)
454
474
 
455
- async def discover_included_services(self, service):
475
+ async def discover_included_services(
476
+ self, service: gatt_client.ServiceProxy
477
+ ) -> List[gatt_client.ServiceProxy]:
456
478
  return await self.gatt_client.discover_included_services(service)
457
479
 
458
- async def discover_characteristics(self, uuids=(), service=None):
480
+ async def discover_characteristics(
481
+ self,
482
+ uuids: Iterable[Union[core.UUID, str]] = (),
483
+ service: Optional[gatt_client.ServiceProxy] = None,
484
+ ) -> List[gatt_client.CharacteristicProxy]:
459
485
  return await self.gatt_client.discover_characteristics(
460
486
  uuids=uuids, service=service
461
487
  )
462
488
 
463
489
  async def discover_descriptors(
464
- self, characteristic=None, start_handle=None, end_handle=None
490
+ self,
491
+ characteristic: Optional[gatt_client.CharacteristicProxy] = None,
492
+ start_handle: Optional[int] = None,
493
+ end_handle: Optional[int] = None,
465
494
  ):
466
495
  return await self.gatt_client.discover_descriptors(
467
496
  characteristic, start_handle, end_handle
468
497
  )
469
498
 
470
- async def discover_attributes(self):
499
+ async def discover_attributes(self) -> List[gatt_client.AttributeProxy]:
471
500
  return await self.gatt_client.discover_attributes()
472
501
 
473
- async def subscribe(self, characteristic, subscriber=None, prefer_notify=True):
502
+ async def subscribe(
503
+ self,
504
+ characteristic: gatt_client.CharacteristicProxy,
505
+ subscriber: Optional[Callable[[bytes], Any]] = None,
506
+ prefer_notify: bool = True,
507
+ ) -> None:
474
508
  return await self.gatt_client.subscribe(
475
509
  characteristic, subscriber, prefer_notify
476
510
  )
477
511
 
478
- async def unsubscribe(self, characteristic, subscriber=None):
512
+ async def unsubscribe(
513
+ self,
514
+ characteristic: gatt_client.CharacteristicProxy,
515
+ subscriber: Optional[Callable[[bytes], Any]] = None,
516
+ ) -> None:
479
517
  return await self.gatt_client.unsubscribe(characteristic, subscriber)
480
518
 
481
- async def read_value(self, attribute):
519
+ async def read_value(
520
+ self, attribute: Union[int, gatt_client.AttributeProxy]
521
+ ) -> bytes:
482
522
  return await self.gatt_client.read_value(attribute)
483
523
 
484
- async def write_value(self, attribute, value, with_response=False):
524
+ async def write_value(
525
+ self,
526
+ attribute: Union[int, gatt_client.AttributeProxy],
527
+ value: bytes,
528
+ with_response: bool = False,
529
+ ) -> None:
485
530
  return await self.gatt_client.write_value(attribute, value, with_response)
486
531
 
487
- async def read_characteristics_by_uuid(self, uuid, service=None):
532
+ async def read_characteristics_by_uuid(
533
+ self, uuid: core.UUID, service: Optional[gatt_client.ServiceProxy] = None
534
+ ) -> List[bytes]:
488
535
  return await self.gatt_client.read_characteristics_by_uuid(uuid, service)
489
536
 
490
- def get_services_by_uuid(self, uuid):
537
+ def get_services_by_uuid(self, uuid: core.UUID) -> List[gatt_client.ServiceProxy]:
491
538
  return self.gatt_client.get_services_by_uuid(uuid)
492
539
 
493
- def get_characteristics_by_uuid(self, uuid, service=None):
540
+ def get_characteristics_by_uuid(
541
+ self, uuid: core.UUID, service: Optional[gatt_client.ServiceProxy] = None
542
+ ) -> List[gatt_client.CharacteristicProxy]:
494
543
  return self.gatt_client.get_characteristics_by_uuid(uuid, service)
495
544
 
496
- def create_service_proxy(self, proxy_class):
497
- return proxy_class.from_client(self.gatt_client)
545
+ def create_service_proxy(self, proxy_class: Type[_PROXY_CLASS]) -> _PROXY_CLASS:
546
+ return cast(_PROXY_CLASS, proxy_class.from_client(self.gatt_client))
498
547
 
499
- async def discover_service_and_create_proxy(self, proxy_class):
548
+ async def discover_service_and_create_proxy(
549
+ self, proxy_class: Type[_PROXY_CLASS]
550
+ ) -> Optional[_PROXY_CLASS]:
500
551
  # Discover the first matching service and its characteristics
501
552
  services = await self.discover_service(proxy_class.SERVICE_CLASS.UUID)
502
553
  if services:
503
554
  service = services[0]
504
555
  await service.discover_characteristics()
505
556
  return self.create_service_proxy(proxy_class)
557
+ return None
506
558
 
507
- async def sustain(self, timeout=None):
559
+ async def sustain(self, timeout: Optional[float] = None) -> None:
508
560
  await self.connection.sustain(timeout)
509
561
 
510
562
  # [Classic only]
511
- async def request_name(self):
563
+ async def request_name(self) -> str:
512
564
  return await self.connection.request_remote_name()
513
565
 
514
566
  async def __aenter__(self):
@@ -521,7 +573,7 @@ class Peer:
521
573
  async def __aexit__(self, exc_type, exc_value, traceback):
522
574
  pass
523
575
 
524
- def __str__(self):
576
+ def __str__(self) -> str:
525
577
  return f'{self.connection.peer_address} as {self.connection.role_name}'
526
578
 
527
579
 
@@ -721,7 +773,7 @@ class Connection(CompositeEventEmitter):
721
773
  async def switch_role(self, role: int) -> None:
722
774
  return await self.device.switch_role(self, role)
723
775
 
724
- async def sustain(self, timeout=None):
776
+ async def sustain(self, timeout: Optional[float] = None) -> None:
725
777
  """Idles the current task waiting for a disconnect or timeout"""
726
778
 
727
779
  abort = asyncio.get_running_loop().create_future()
@@ -736,6 +788,9 @@ class Connection(CompositeEventEmitter):
736
788
  self.remove_listener('disconnection', abort.set_result)
737
789
  self.remove_listener('disconnection_failure', abort.set_exception)
738
790
 
791
+ async def set_data_length(self, tx_octets, tx_time) -> None:
792
+ return await self.device.set_data_length(self, tx_octets, tx_time)
793
+
739
794
  async def update_parameters(
740
795
  self,
741
796
  connection_interval_min,
@@ -956,6 +1011,7 @@ class Device(CompositeEventEmitter):
956
1011
  ]
957
1012
  advertisement_accumulators: Dict[Address, AdvertisementDataAccumulator]
958
1013
  config: DeviceConfiguration
1014
+ extended_advertising_handles: Set[int]
959
1015
 
960
1016
  @composite_listener
961
1017
  class Listener:
@@ -1054,6 +1110,7 @@ class Device(CompositeEventEmitter):
1054
1110
  self.classic_pending_accepts = {
1055
1111
  Address.ANY: []
1056
1112
  } # Futures, by BD address OR [Futures] for Address.ANY
1113
+ self.extended_advertising_handles = set()
1057
1114
 
1058
1115
  # Own address type cache
1059
1116
  self.advertising_own_address_type = None
@@ -1532,6 +1589,149 @@ class Device(CompositeEventEmitter):
1532
1589
  self.advertising = False
1533
1590
  self.auto_restart_advertising = False
1534
1591
 
1592
+ @experimental('Extended Advertising is still experimental - Might be changed soon.')
1593
+ async def start_extended_advertising(
1594
+ self,
1595
+ advertising_properties: HCI_LE_Set_Extended_Advertising_Parameters_Command.AdvertisingProperties = HCI_LE_Set_Extended_Advertising_Parameters_Command.AdvertisingProperties.CONNECTABLE_ADVERTISING,
1596
+ target: Address = Address.ANY,
1597
+ own_address_type: int = OwnAddressType.RANDOM,
1598
+ scan_response: Optional[bytes] = None,
1599
+ advertising_data: Optional[bytes] = None,
1600
+ ) -> int:
1601
+ """Starts an extended advertising set.
1602
+
1603
+ Args:
1604
+ advertising_properties: Properties to pass in HCI_LE_Set_Extended_Advertising_Parameters_Command
1605
+ target: Directed advertising target. Directed property should be set in advertising_properties arg.
1606
+ own_address_type: own address type to use in the advertising.
1607
+ scan_response: raw scan response. When a non-none value is set, HCI_LE_Set_Extended_Scan_Response_Data_Command will be sent.
1608
+ advertising_data: raw advertising data. When a non-none value is set, HCI_LE_Set_Advertising_Set_Random_Address_Command will be sent.
1609
+
1610
+ Returns:
1611
+ Handle of the new advertising set.
1612
+ """
1613
+
1614
+ adv_handle = -1
1615
+ # Find a free handle
1616
+ for i in range(
1617
+ DEVICE_MIN_EXTENDED_ADVERTISING_SET_HANDLE,
1618
+ DEVICE_MAX_EXTENDED_ADVERTISING_SET_HANDLE + 1,
1619
+ ):
1620
+ if i not in self.extended_advertising_handles:
1621
+ adv_handle = i
1622
+ break
1623
+
1624
+ if adv_handle == -1:
1625
+ raise InvalidStateError('No available advertising set.')
1626
+
1627
+ try:
1628
+ # Set the advertising parameters
1629
+ await self.send_command(
1630
+ HCI_LE_Set_Extended_Advertising_Parameters_Command(
1631
+ advertising_handle=adv_handle,
1632
+ advertising_event_properties=advertising_properties,
1633
+ primary_advertising_interval_min=self.advertising_interval_min,
1634
+ primary_advertising_interval_max=self.advertising_interval_max,
1635
+ primary_advertising_channel_map=(
1636
+ HCI_LE_Set_Extended_Advertising_Parameters_Command.ChannelMap.CHANNEL_37
1637
+ | HCI_LE_Set_Extended_Advertising_Parameters_Command.ChannelMap.CHANNEL_38
1638
+ | HCI_LE_Set_Extended_Advertising_Parameters_Command.ChannelMap.CHANNEL_39
1639
+ ),
1640
+ own_address_type=own_address_type,
1641
+ peer_address_type=target.address_type,
1642
+ peer_address=target,
1643
+ advertising_tx_power=7,
1644
+ advertising_filter_policy=0,
1645
+ primary_advertising_phy=1, # LE 1M
1646
+ secondary_advertising_max_skip=0,
1647
+ secondary_advertising_phy=1, # LE 1M
1648
+ advertising_sid=0,
1649
+ scan_request_notification_enable=0,
1650
+ ), # type: ignore[call-arg]
1651
+ check_result=True,
1652
+ )
1653
+
1654
+ # Set the advertising data if present
1655
+ if advertising_data is not None:
1656
+ await self.send_command(
1657
+ HCI_LE_Set_Extended_Advertising_Data_Command(
1658
+ advertising_handle=adv_handle,
1659
+ operation=HCI_LE_Set_Extended_Advertising_Data_Command.Operation.COMPLETE_DATA,
1660
+ fragment_preference=0x01, # Should not fragment
1661
+ advertising_data=advertising_data,
1662
+ ), # type: ignore[call-arg]
1663
+ check_result=True,
1664
+ )
1665
+
1666
+ # Set the scan response if present
1667
+ if scan_response is not None:
1668
+ await self.send_command(
1669
+ HCI_LE_Set_Extended_Scan_Response_Data_Command(
1670
+ advertising_handle=adv_handle,
1671
+ operation=HCI_LE_Set_Extended_Advertising_Data_Command.Operation.COMPLETE_DATA,
1672
+ fragment_preference=0x01, # Should not fragment
1673
+ scan_response_data=scan_response,
1674
+ ), # type: ignore[call-arg]
1675
+ check_result=True,
1676
+ )
1677
+
1678
+ if own_address_type in (
1679
+ OwnAddressType.RANDOM,
1680
+ OwnAddressType.RESOLVABLE_OR_RANDOM,
1681
+ ):
1682
+ await self.send_command(
1683
+ HCI_LE_Set_Advertising_Set_Random_Address_Command(
1684
+ advertising_handle=adv_handle,
1685
+ random_address=self.random_address,
1686
+ ), # type: ignore[call-arg]
1687
+ check_result=True,
1688
+ )
1689
+
1690
+ # Enable advertising
1691
+ await self.send_command(
1692
+ HCI_LE_Set_Extended_Advertising_Enable_Command(
1693
+ enable=1,
1694
+ advertising_handles=[adv_handle],
1695
+ durations=[0], # Forever
1696
+ max_extended_advertising_events=[0], # Infinite
1697
+ ), # type: ignore[call-arg]
1698
+ check_result=True,
1699
+ )
1700
+ except HCI_Error as error:
1701
+ # When any step fails, cleanup the advertising handle.
1702
+ await self.send_command(
1703
+ HCI_LE_Remove_Advertising_Set_Command(advertising_handle=adv_handle), # type: ignore[call-arg]
1704
+ check_result=False,
1705
+ )
1706
+ raise error
1707
+
1708
+ self.extended_advertising_handles.add(adv_handle)
1709
+ return adv_handle
1710
+
1711
+ @experimental('Extended Advertising is still experimental - Might be changed soon.')
1712
+ async def stop_extended_advertising(self, adv_handle: int) -> None:
1713
+ """Stops an extended advertising set.
1714
+
1715
+ Args:
1716
+ adv_handle: Handle of the advertising set to stop.
1717
+ """
1718
+ # Disable advertising
1719
+ await self.send_command(
1720
+ HCI_LE_Set_Extended_Advertising_Enable_Command(
1721
+ enable=0,
1722
+ advertising_handles=[adv_handle],
1723
+ durations=[0],
1724
+ max_extended_advertising_events=[0],
1725
+ ), # type: ignore[call-arg]
1726
+ check_result=True,
1727
+ )
1728
+ # Remove advertising set
1729
+ await self.send_command(
1730
+ HCI_LE_Remove_Advertising_Set_Command(advertising_handle=adv_handle), # type: ignore[call-arg]
1731
+ check_result=True,
1732
+ )
1733
+ self.extended_advertising_handles.remove(adv_handle)
1734
+
1535
1735
  @property
1536
1736
  def is_advertising(self):
1537
1737
  return self.advertising
@@ -2193,6 +2393,22 @@ class Device(CompositeEventEmitter):
2193
2393
  )
2194
2394
  self.disconnecting = False
2195
2395
 
2396
+ async def set_data_length(self, connection, tx_octets, tx_time) -> None:
2397
+ if tx_octets < 0x001B or tx_octets > 0x00FB:
2398
+ raise ValueError('tx_octets must be between 0x001B and 0x00FB')
2399
+
2400
+ if tx_time < 0x0148 or tx_time > 0x4290:
2401
+ raise ValueError('tx_time must be between 0x0148 and 0x4290')
2402
+
2403
+ return await self.send_command(
2404
+ HCI_LE_Set_Data_Length_Command(
2405
+ connection_handle=connection.handle,
2406
+ tx_octets=tx_octets,
2407
+ tx_time=tx_time,
2408
+ ), # type: ignore[call-arg]
2409
+ check_result=True,
2410
+ )
2411
+
2196
2412
  async def update_connection_parameters(
2197
2413
  self,
2198
2414
  connection,
@@ -3138,10 +3354,18 @@ class Device(CompositeEventEmitter):
3138
3354
  connection.encryption = encryption
3139
3355
  if (
3140
3356
  not connection.authenticated
3357
+ and connection.transport == BT_BR_EDR_TRANSPORT
3141
3358
  and encryption == HCI_Encryption_Change_Event.AES_CCM
3142
3359
  ):
3143
3360
  connection.authenticated = True
3144
3361
  connection.sc = True
3362
+ if (
3363
+ not connection.authenticated
3364
+ and connection.transport == BT_LE_TRANSPORT
3365
+ and encryption == HCI_Encryption_Change_Event.E0_OR_AES_CCM
3366
+ ):
3367
+ connection.authenticated = True
3368
+ connection.sc = True
3145
3369
  connection.emit('connection_encryption_change')
3146
3370
 
3147
3371
  @host_event_handler
bumble/gatt.py CHANGED
@@ -93,20 +93,35 @@ GATT_RECONNECTION_CONFIGURATION_SERVICE = UUID.from_16_bits(0x1829, 'Reconne
93
93
  GATT_INSULIN_DELIVERY_SERVICE = UUID.from_16_bits(0x183A, 'Insulin Delivery')
94
94
  GATT_BINARY_SENSOR_SERVICE = UUID.from_16_bits(0x183B, 'Binary Sensor')
95
95
  GATT_EMERGENCY_CONFIGURATION_SERVICE = UUID.from_16_bits(0x183C, 'Emergency Configuration')
96
+ GATT_AUTHORIZATION_CONTROL_SERVICE = UUID.from_16_bits(0x183D, 'Authorization Control')
96
97
  GATT_PHYSICAL_ACTIVITY_MONITOR_SERVICE = UUID.from_16_bits(0x183E, 'Physical Activity Monitor')
98
+ GATT_ELAPSED_TIME_SERVICE = UUID.from_16_bits(0x183F, 'Elapsed Time')
99
+ GATT_GENERIC_HEALTH_SENSOR_SERVICE = UUID.from_16_bits(0x1840, 'Generic Health Sensor')
97
100
  GATT_AUDIO_INPUT_CONTROL_SERVICE = UUID.from_16_bits(0x1843, 'Audio Input Control')
98
101
  GATT_VOLUME_CONTROL_SERVICE = UUID.from_16_bits(0x1844, 'Volume Control')
99
102
  GATT_VOLUME_OFFSET_CONTROL_SERVICE = UUID.from_16_bits(0x1845, 'Volume Offset Control')
100
- GATT_COORDINATED_SET_IDENTIFICATION_SERVICE = UUID.from_16_bits(0x1846, 'Coordinated Set Identification Service')
103
+ GATT_COORDINATED_SET_IDENTIFICATION_SERVICE = UUID.from_16_bits(0x1846, 'Coordinated Set Identification')
101
104
  GATT_DEVICE_TIME_SERVICE = UUID.from_16_bits(0x1847, 'Device Time')
102
- GATT_MEDIA_CONTROL_SERVICE = UUID.from_16_bits(0x1848, 'Media Control Service')
103
- GATT_GENERIC_MEDIA_CONTROL_SERVICE = UUID.from_16_bits(0x1849, 'Generic Media Control Service')
105
+ GATT_MEDIA_CONTROL_SERVICE = UUID.from_16_bits(0x1848, 'Media Control')
106
+ GATT_GENERIC_MEDIA_CONTROL_SERVICE = UUID.from_16_bits(0x1849, 'Generic Media Control')
104
107
  GATT_CONSTANT_TONE_EXTENSION_SERVICE = UUID.from_16_bits(0x184A, 'Constant Tone Extension')
105
- GATT_TELEPHONE_BEARER_SERVICE = UUID.from_16_bits(0x184B, 'Telephone Bearer Service')
106
- GATT_GENERIC_TELEPHONE_BEARER_SERVICE = UUID.from_16_bits(0x184C, 'Generic Telephone Bearer Service')
108
+ GATT_TELEPHONE_BEARER_SERVICE = UUID.from_16_bits(0x184B, 'Telephone Bearer')
109
+ GATT_GENERIC_TELEPHONE_BEARER_SERVICE = UUID.from_16_bits(0x184C, 'Generic Telephone Bearer')
107
110
  GATT_MICROPHONE_CONTROL_SERVICE = UUID.from_16_bits(0x184D, 'Microphone Control')
108
-
109
- # Types
111
+ GATT_AUDIO_STREAM_CONTROL_SERVICE = UUID.from_16_bits(0x184E, 'Audio Stream Control')
112
+ GATT_BROADCAST_AUDIO_SCAN_SERVICE = UUID.from_16_bits(0x184F, 'Broadcast Audio Scan')
113
+ GATT_PUBLISHED_AUDIO_CAPABILITIES_SERVICE = UUID.from_16_bits(0x1850, 'Published Audio Capabilities')
114
+ GATT_BASIC_AUDIO_ANNOUNCEMENT_SERVICE = UUID.from_16_bits(0x1851, 'Basic Audio Announcement')
115
+ GATT_BROADCAST_AUDIO_ANNOUNCEMENT_SERVICE = UUID.from_16_bits(0x1852, 'Broadcast Audio Announcement')
116
+ GATT_COMMON_AUDIO_SERVICE = UUID.from_16_bits(0x1853, 'Common Audio')
117
+ GATT_HEARING_ACCESS_SERVICE = UUID.from_16_bits(0x1854, 'Hearing Access')
118
+ GATT_TELEPHONY_AND_MEDIA_AUDIO_SERVICE = UUID.from_16_bits(0x1855, 'Telephony and Media Audio')
119
+ GATT_PUBLIC_BROADCAST_ANNOUNCEMENT_SERVICE = UUID.from_16_bits(0x1856, 'Public Broadcast Announcement')
120
+ GATT_ELECTRONIC_SHELF_LABEL_SERVICE = UUID.from_16_bits(0X1857, 'Electronic Shelf Label')
121
+ GATT_GAMING_AUDIO_SERVICE = UUID.from_16_bits(0x1858, 'Gaming Audio')
122
+ GATT_MESH_PROXY_SOLICITATION_SERVICE = UUID.from_16_bits(0x1859, 'Mesh Audio Solicitation')
123
+
124
+ # Attribute Types
110
125
  GATT_PRIMARY_SERVICE_ATTRIBUTE_TYPE = UUID.from_16_bits(0x2800, 'Primary Service')
111
126
  GATT_SECONDARY_SERVICE_ATTRIBUTE_TYPE = UUID.from_16_bits(0x2801, 'Secondary Service')
112
127
  GATT_INCLUDE_ATTRIBUTE_TYPE = UUID.from_16_bits(0x2802, 'Include')
@@ -129,6 +144,8 @@ GATT_ENVIRONMENTAL_SENSING_MEASUREMENT_DESCRIPTOR = UUID.from_16_bits(0x290C,
129
144
  GATT_ENVIRONMENTAL_SENSING_TRIGGER_DESCRIPTOR = UUID.from_16_bits(0x290D, 'Environmental Sensing Trigger Setting')
130
145
  GATT_TIME_TRIGGER_DESCRIPTOR = UUID.from_16_bits(0x290E, 'Time Trigger Setting')
131
146
  GATT_COMPLETE_BR_EDR_TRANSPORT_BLOCK_DATA_DESCRIPTOR = UUID.from_16_bits(0x290F, 'Complete BR-EDR Transport Block Data')
147
+ GATT_OBSERVATION_SCHEDULE_DESCRIPTOR = UUID.from_16_bits(0x290F, 'Observation Schedule')
148
+ GATT_VALID_RANGE_AND_ACCURACY_DESCRIPTOR = UUID.from_16_bits(0x290F, 'Valid Range And Accuracy')
132
149
 
133
150
  # Device Information Service
134
151
  GATT_SYSTEM_ID_CHARACTERISTIC = UUID.from_16_bits(0x2A23, 'System ID')
@@ -156,6 +173,96 @@ GATT_HEART_RATE_CONTROL_POINT_CHARACTERISTIC = UUID.from_16_bits(0x2A39, 'Heart
156
173
  # Battery Service
157
174
  GATT_BATTERY_LEVEL_CHARACTERISTIC = UUID.from_16_bits(0x2A19, 'Battery Level')
158
175
 
176
+ # Telephony And Media Audio Service (TMAS)
177
+ GATT_TMAP_ROLE_CHARACTERISTIC = UUID.from_16_bits(0x2B51, 'TMAP Role')
178
+
179
+ # Audio Input Control Service (AICS)
180
+ GATT_AUDIO_INPUT_STATE_CHARACTERISTIC = UUID.from_16_bits(0x2B77, 'Audio Input State')
181
+ GATT_GAIN_SETTINGS_ATTRIBUTE_CHARACTERISTIC = UUID.from_16_bits(0x2B78, 'Gain Settings Attribute')
182
+ GATT_AUDIO_INPUT_TYPE_CHARACTERISTIC = UUID.from_16_bits(0x2B79, 'Audio Input Type')
183
+ GATT_AUDIO_INPUT_STATUS_CHARACTERISTIC = UUID.from_16_bits(0x2B7A, 'Audio Input Status')
184
+ GATT_AUDIO_INPUT_CONTROL_POINT_CHARACTERISTIC = UUID.from_16_bits(0x2B7B, 'Audio Input Control Point')
185
+ GATT_AUDIO_INPUT_DESCRIPTION_CHARACTERISTIC = UUID.from_16_bits(0x2B7C, 'Audio Input Description')
186
+
187
+ # Volume Control Service (VCS)
188
+ GATT_VOLUME_STATE_CHARACTERISTIC = UUID.from_16_bits(0x2B7D, 'Volume State')
189
+ GATT_VOLUME_CONTROL_POINT_CHARACTERISTIC = UUID.from_16_bits(0x2B7E, 'Volume Control Point')
190
+ GATT_VOLUME_FLAGS_CHARACTERISTIC = UUID.from_16_bits(0x2B7F, 'Volume Flags')
191
+
192
+ # Volume Offset Control Service (VOCS)
193
+ GATT_VOLUME_OFFSET_STATE_CHARACTERISTIC = UUID.from_16_bits(0x2B80, 'Volume Offset State')
194
+ GATT_AUDIO_LOCATION_CHARACTERISTIC = UUID.from_16_bits(0x2B81, 'Audio Location')
195
+ GATT_VOLUME_OFFSET_CONTROL_POINT_CHARACTERISTIC = UUID.from_16_bits(0x2B82, 'Volume Offset Control Point')
196
+ GATT_AUDIO_OUTPUT_DESCRIPTION_CHARACTERISTIC = UUID.from_16_bits(0x2B83, 'Audio Output Description')
197
+
198
+ # Coordinated Set Identification Service (CSIS)
199
+ GATT_SET_IDENTITY_RESOLVING_KEY_CHARACTERISTIC = UUID.from_16_bits(0x2B84, 'Set Identity Resolving Key')
200
+ GATT_COORDINATED_SET_SIZE_CHARACTERISTIC = UUID.from_16_bits(0x2B85, 'Coordinated Set Size')
201
+ GATT_SET_MEMBER_LOCK_CHARACTERISTIC = UUID.from_16_bits(0x2B86, 'Set Member Lock')
202
+ GATT_SET_MEMBER_RANK_CHARACTERISTIC = UUID.from_16_bits(0x2B87, 'Set Member Rank')
203
+
204
+ # Media Control Service (MCS)
205
+ GATT_MEDIA_PLAYER_NAME_CHARACTERISTIC = UUID.from_16_bits(0x2B93, 'Media Player Name')
206
+ GATT_MEDIA_PLAYER_ICON_OBJECT_ID_CHARACTERISTIC = UUID.from_16_bits(0x2B94, 'Media Player Icon Object ID')
207
+ GATT_MEDIA_PLAYER_ICON_URL_CHARACTERISTIC = UUID.from_16_bits(0x2B95, 'Media Player Icon URL')
208
+ GATT_TRACK_CHANGED_CHARACTERISTIC = UUID.from_16_bits(0x2B96, 'Track Changed')
209
+ GATT_TRACK_TITLE_CHARACTERISTIC = UUID.from_16_bits(0x2B97, 'Track Title')
210
+ GATT_TRACK_DURATION_CHARACTERISTIC = UUID.from_16_bits(0x2B98, 'Track Duration')
211
+ GATT_TRACK_POSITION_CHARACTERISTIC = UUID.from_16_bits(0x2B99, 'Track Position')
212
+ GATT_PLAYBACK_SPEED_CHARACTERISTIC = UUID.from_16_bits(0x2B9A, 'Playback Speed')
213
+ GATT_SEEKING_SPEED_CHARACTERISTIC = UUID.from_16_bits(0x2B9B, 'Seeking Speed')
214
+ GATT_CURRENT_TRACK_SEGMENTS_OBJECT_ID_CHARACTERISTIC = UUID.from_16_bits(0x2B9C, 'Current Track Segments Object ID')
215
+ GATT_CURRENT_TRACK_OBJECT_ID_CHARACTERISTIC = UUID.from_16_bits(0x2B9D, 'Current Track Object ID')
216
+ GATT_NEXT_TRACK_OBJECT_ID_CHARACTERISTIC = UUID.from_16_bits(0x2B9E, 'Next Track Object ID')
217
+ GATT_PARENT_GROUP_OBJECT_ID_CHARACTERISTIC = UUID.from_16_bits(0x2B9F, 'Parent Group Object ID')
218
+ GATT_CURRENT_GROUP_OBJECT_ID_CHARACTERISTIC = UUID.from_16_bits(0x2BA0, 'Current Group Object ID')
219
+ GATT_PLAYING_ORDER_CHARACTERISTIC = UUID.from_16_bits(0x2BA1, 'Playing Order')
220
+ GATT_PLAYING_ORDERS_SUPPORTED_CHARACTERISTIC = UUID.from_16_bits(0x2BA2, 'Playing Orders Supported')
221
+ GATT_MEDIA_STATE_CHARACTERISTIC = UUID.from_16_bits(0x2BA3, 'Media State')
222
+ GATT_MEDIA_CONTROL_POINT_CHARACTERISTIC = UUID.from_16_bits(0x2BA4, 'Media Control Point')
223
+ GATT_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED_CHARACTERISTIC = UUID.from_16_bits(0x2BA5, 'Media Control Point Opcodes Supported')
224
+ GATT_SEARCH_RESULTS_OBJECT_ID_CHARACTERISTIC = UUID.from_16_bits(0x2BA6, 'Search Results Object ID')
225
+ GATT_SEARCH_CONTROL_POINT_CHARACTERISTIC = UUID.from_16_bits(0x2BA7, 'Search Control Point')
226
+ GATT_CONTENT_CONTROL_ID_CHARACTERISTIC = UUID.from_16_bits(0x2BBA, 'Content Control Id')
227
+
228
+ # Telephone Bearer Service (TBS)
229
+ GATT_BEARER_PROVIDER_NAME_CHARACTERISTIC = UUID.from_16_bits(0x2BB4, 'Bearer Provider Name')
230
+ GATT_BEARER_UCI_CHARACTERISTIC = UUID.from_16_bits(0x2BB5, 'Bearer UCI')
231
+ GATT_BEARER_TECHNOLOGY_CHARACTERISTIC = UUID.from_16_bits(0x2BB6, 'Bearer Technology')
232
+ GATT_BEARER_URI_SCHEMES_SUPPORTED_LIST_CHARACTERISTIC = UUID.from_16_bits(0x2BB7, 'Bearer URI Schemes Supported List')
233
+ GATT_BEARER_SIGNAL_STRENGTH_CHARACTERISTIC = UUID.from_16_bits(0x2BB8, 'Bearer Signal Strength')
234
+ GATT_BEARER_SIGNAL_STRENGTH_REPORTING_INTERVAL_CHARACTERISTIC = UUID.from_16_bits(0x2BB9, 'Bearer Signal Strength Reporting Interval')
235
+ GATT_BEARER_LIST_CURRENT_CALLS_CHARACTERISTIC = UUID.from_16_bits(0x2BBA, 'Bearer List Current Calls')
236
+ GATT_CONTENT_CONTROL_ID_CHARACTERISTIC = UUID.from_16_bits(0x2BBB, 'Content Control ID')
237
+ GATT_STATUS_FLAGS_CHARACTERISTIC = UUID.from_16_bits(0x2BBC, 'Status Flags')
238
+ GATT_INCOMING_CALL_TARGET_BEARER_URI_CHARACTERISTIC = UUID.from_16_bits(0x2BBD, 'Incoming Call Target Bearer URI')
239
+ GATT_CALL_STATE_CHARACTERISTIC = UUID.from_16_bits(0x2BBE, 'Call State')
240
+ GATT_CALL_CONTROL_POINT_CHARACTERISTIC = UUID.from_16_bits(0x2BBF, 'Call Control Point')
241
+ GATT_CALL_CONTROL_POINT_OPTIONAL_OPCODES_CHARACTERISTIC = UUID.from_16_bits(0x2BC0, 'Call Control Point Optional Opcodes')
242
+ GATT_TERMINATION_REASON_CHARACTERISTIC = UUID.from_16_bits(0x2BC1, 'Termination Reason')
243
+ GATT_INCOMING_CALL_CHARACTERISTIC = UUID.from_16_bits(0x2BC2, 'Incoming Call')
244
+ GATT_CALL_FRIENDLY_NAME_CHARACTERISTIC = UUID.from_16_bits(0x2BC3, 'Call Friendly Name')
245
+
246
+ # Microphone Control Service (MICS)
247
+ GATT_MUTE_CHARACTERISTIC = UUID.from_16_bits(0x2BC3, 'Mute')
248
+
249
+ # Audio Stream Control Service (ASCS)
250
+ GATT_SINK_ASE_CHARACTERISTIC = UUID.from_16_bits(0x2BC4, 'Sink ASE')
251
+ GATT_SOURCE_ASE_CHARACTERISTIC = UUID.from_16_bits(0x2BC5, 'Source ASE')
252
+ GATT_ASE_CONTROL_POINT_CHARACTERISTIC = UUID.from_16_bits(0x2BC6, 'ASE Control Point')
253
+
254
+ # Broadcast Audio Scan Service (BASS)
255
+ GATT_BROADCAST_AUDIO_SCAN_CONTROL_POINT_CHARACTERISTIC = UUID.from_16_bits(0x2BC7, 'Broadcast Audio Scan Control Point')
256
+ GATT_BROADCAST_RECEIVE_STATE_CHARACTERISTIC = UUID.from_16_bits(0x2BC8, 'Broadcast Receive State')
257
+
258
+ # Published Audio Capabilities Service (PACS)
259
+ GATT_SINK_PAC_CHARACTERISTIC = UUID.from_16_bits(0x2BC9, 'Sink PAC')
260
+ GATT_SINK_AUDIO_LOCATION_CHARACTERISTIC = UUID.from_16_bits(0x2BCA, 'Sink Audio Location')
261
+ GATT_SOURCE_PAC_CHARACTERISTIC = UUID.from_16_bits(0x2BCB, 'Source PAC')
262
+ GATT_SOURCE_AUDIO_LOCATION_CHARACTERISTIC = UUID.from_16_bits(0x2BCC, 'Source Audio Location')
263
+ GATT_AVAILABLE_AUDIO_CONTEXTS_CHARACTERISTIC = UUID.from_16_bits(0x2BCD, 'Available Audio Contexts')
264
+ GATT_SUPPORTED_AUDIO_CONTEXTS_CHARACTERISTIC = UUID.from_16_bits(0x2BCE, 'Supported Audio Contexts')
265
+
159
266
  # ASHA Service
160
267
  GATT_ASHA_SERVICE = UUID.from_16_bits(0xFDF0, 'Audio Streaming for Hearing Aid')
161
268
  GATT_ASHA_READ_ONLY_PROPERTIES_CHARACTERISTIC = UUID('6333651e-c481-4a3e-9169-7c902aad37bb', 'ReadOnlyProperties')
@@ -177,6 +284,9 @@ GATT_BOOT_KEYBOARD_INPUT_REPORT_CHARACTERISTIC = UUID.from_16_bi
177
284
  GATT_CURRENT_TIME_CHARACTERISTIC = UUID.from_16_bits(0x2A2B, 'Current Time')
178
285
  GATT_BOOT_KEYBOARD_OUTPUT_REPORT_CHARACTERISTIC = UUID.from_16_bits(0x2A32, 'Boot Keyboard Output Report')
179
286
  GATT_CENTRAL_ADDRESS_RESOLUTION__CHARACTERISTIC = UUID.from_16_bits(0x2AA6, 'Central Address Resolution')
287
+ GATT_CLIENT_SUPPORTED_FEATURES_CHARACTERISTIC = UUID.from_16_bits(0x2B29, 'Client Supported Features')
288
+ GATT_DATABASE_HASH_CHARACTERISTIC = UUID.from_16_bits(0x2B2A, 'Database Hash')
289
+ GATT_SERVER_SUPPORTED_FEATURES_CHARACTERISTIC = UUID.from_16_bits(0x2B3A, 'Server Supported Features')
180
290
 
181
291
  # fmt: on
182
292
  # pylint: enable=line-too-long