mirror of
https://github.com/google/bumble.git
synced 2026-05-08 03:58:01 +00:00
Merge pull request #160 from AlanRosenthal/alan/types
Add some missing types to apps/console.py, bumble/gatt_client.py
This commit is contained in:
@@ -24,6 +24,7 @@ import logging
|
|||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
import re
|
import re
|
||||||
|
from typing import Optional
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
import click
|
import click
|
||||||
@@ -58,6 +59,7 @@ from bumble.device import ConnectionParametersPreferences, Device, Connection, P
|
|||||||
from bumble.utils import AsyncRunner
|
from bumble.utils import AsyncRunner
|
||||||
from bumble.transport import open_transport_or_link
|
from bumble.transport import open_transport_or_link
|
||||||
from bumble.gatt import Characteristic, Service, CharacteristicDeclaration, Descriptor
|
from bumble.gatt import Characteristic, Service, CharacteristicDeclaration, Descriptor
|
||||||
|
from bumble.gatt_client import CharacteristicProxy
|
||||||
from bumble.hci import (
|
from bumble.hci import (
|
||||||
HCI_Constant,
|
HCI_Constant,
|
||||||
HCI_LE_1M_PHY,
|
HCI_LE_1M_PHY,
|
||||||
@@ -119,6 +121,8 @@ def parse_phys(phys):
|
|||||||
# Console App
|
# Console App
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
class ConsoleApp:
|
class ConsoleApp:
|
||||||
|
connected_peer: Optional[Peer]
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.known_addresses = set()
|
self.known_addresses = set()
|
||||||
self.known_attributes = []
|
self.known_attributes = []
|
||||||
@@ -490,7 +494,9 @@ class ConsoleApp:
|
|||||||
|
|
||||||
self.show_attributes(attributes)
|
self.show_attributes(attributes)
|
||||||
|
|
||||||
def find_characteristic(self, param):
|
def find_characteristic(self, param) -> Optional[CharacteristicProxy]:
|
||||||
|
if not self.connected_peer:
|
||||||
|
return None
|
||||||
parts = param.split('.')
|
parts = param.split('.')
|
||||||
if len(parts) == 2:
|
if len(parts) == 2:
|
||||||
service_uuid = UUID(parts[0]) if parts[0] != '*' else None
|
service_uuid = UUID(parts[0]) if parts[0] != '*' else None
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ import struct
|
|||||||
from pyee import EventEmitter
|
from pyee import EventEmitter
|
||||||
from typing import Dict, Type, TYPE_CHECKING
|
from typing import Dict, Type, TYPE_CHECKING
|
||||||
|
|
||||||
from bumble.core import UUID, name_or_number, get_dict_key_by_value
|
from bumble.core import UUID, name_or_number, get_dict_key_by_value, ProtocolError
|
||||||
from bumble.hci import HCI_Object, key_with_value
|
from bumble.hci import HCI_Object, key_with_value, HCI_Constant
|
||||||
from bumble.colors import color
|
from bumble.colors import color
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@@ -185,13 +185,18 @@ UUID_2_FIELD_SPEC = lambda x, y: UUID.parse_uuid_2(x, y) # noqa: E731
|
|||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# Exceptions
|
# Exceptions
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
class ATT_Error(Exception):
|
class ATT_Error(ProtocolError):
|
||||||
def __init__(self, error_code, att_handle=0x0000):
|
def __init__(self, error_code, att_handle=0x0000, message=''):
|
||||||
self.error_code = error_code
|
super().__init__(
|
||||||
|
error_code,
|
||||||
|
error_namespace='att',
|
||||||
|
error_name=ATT_PDU.error_name(self.error_code),
|
||||||
|
)
|
||||||
self.att_handle = att_handle
|
self.att_handle = att_handle
|
||||||
|
self.message = message
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f'ATT_Error({ATT_PDU.error_name(self.error_code)})'
|
return f'ATT_Error(error={self.error_name}, handle={self.att_handle:04X}): {self.message}'
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -23,9 +23,11 @@
|
|||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# Imports
|
# Imports
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
from __future__ import annotations
|
||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
import struct
|
import struct
|
||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
from pyee import EventEmitter
|
from pyee import EventEmitter
|
||||||
|
|
||||||
@@ -50,6 +52,7 @@ from .att import (
|
|||||||
ATT_Read_Request,
|
ATT_Read_Request,
|
||||||
ATT_Write_Command,
|
ATT_Write_Command,
|
||||||
ATT_Write_Request,
|
ATT_Write_Request,
|
||||||
|
ATT_Error,
|
||||||
)
|
)
|
||||||
from . import core
|
from . import core
|
||||||
from .core import UUID, InvalidStateError, ProtocolError
|
from .core import UUID, InvalidStateError, ProtocolError
|
||||||
@@ -59,6 +62,7 @@ from .gatt import (
|
|||||||
GATT_PRIMARY_SERVICE_ATTRIBUTE_TYPE,
|
GATT_PRIMARY_SERVICE_ATTRIBUTE_TYPE,
|
||||||
GATT_REQUEST_TIMEOUT,
|
GATT_REQUEST_TIMEOUT,
|
||||||
GATT_SECONDARY_SERVICE_ATTRIBUTE_TYPE,
|
GATT_SECONDARY_SERVICE_ATTRIBUTE_TYPE,
|
||||||
|
Service,
|
||||||
Characteristic,
|
Characteristic,
|
||||||
ClientCharacteristicConfigurationBits,
|
ClientCharacteristicConfigurationBits,
|
||||||
)
|
)
|
||||||
@@ -73,6 +77,8 @@ logger = logging.getLogger(__name__)
|
|||||||
# Proxies
|
# Proxies
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
class AttributeProxy(EventEmitter):
|
class AttributeProxy(EventEmitter):
|
||||||
|
client: Client
|
||||||
|
|
||||||
def __init__(self, client, handle, end_group_handle, attribute_type):
|
def __init__(self, client, handle, end_group_handle, attribute_type):
|
||||||
EventEmitter.__init__(self)
|
EventEmitter.__init__(self)
|
||||||
self.client = client
|
self.client = client
|
||||||
@@ -101,6 +107,9 @@ class AttributeProxy(EventEmitter):
|
|||||||
|
|
||||||
|
|
||||||
class ServiceProxy(AttributeProxy):
|
class ServiceProxy(AttributeProxy):
|
||||||
|
uuid: UUID
|
||||||
|
characteristics: List[CharacteristicProxy]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_client(service_class, client, service_uuid):
|
def from_client(service_class, client, service_uuid):
|
||||||
# The service and its characteristics are considered to have already been
|
# The service and its characteristics are considered to have already been
|
||||||
@@ -130,6 +139,8 @@ class ServiceProxy(AttributeProxy):
|
|||||||
|
|
||||||
|
|
||||||
class CharacteristicProxy(AttributeProxy):
|
class CharacteristicProxy(AttributeProxy):
|
||||||
|
descriptors: List[DescriptorProxy]
|
||||||
|
|
||||||
def __init__(self, client, handle, end_group_handle, uuid, properties):
|
def __init__(self, client, handle, end_group_handle, uuid, properties):
|
||||||
super().__init__(client, handle, end_group_handle, uuid)
|
super().__init__(client, handle, end_group_handle, uuid)
|
||||||
self.uuid = uuid
|
self.uuid = uuid
|
||||||
@@ -201,6 +212,8 @@ class ProfileServiceProxy:
|
|||||||
# GATT Client
|
# GATT Client
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
class Client:
|
class Client:
|
||||||
|
services: List[ServiceProxy]
|
||||||
|
|
||||||
def __init__(self, connection):
|
def __init__(self, connection):
|
||||||
self.connection = connection
|
self.connection = connection
|
||||||
self.mtu_exchange_done = False
|
self.mtu_exchange_done = False
|
||||||
@@ -306,7 +319,7 @@ class Client:
|
|||||||
if not already_known:
|
if not already_known:
|
||||||
self.services.append(service)
|
self.services.append(service)
|
||||||
|
|
||||||
async def discover_services(self, uuids=None):
|
async def discover_services(self, uuids=None) -> List[ServiceProxy]:
|
||||||
'''
|
'''
|
||||||
See Vol 3, Part G - 4.4.1 Discover All Primary Services
|
See Vol 3, Part G - 4.4.1 Discover All Primary Services
|
||||||
'''
|
'''
|
||||||
@@ -332,8 +345,10 @@ class Client:
|
|||||||
'!!! unexpected error while discovering services: '
|
'!!! unexpected error while discovering services: '
|
||||||
f'{HCI_Constant.error_name(response.error_code)}'
|
f'{HCI_Constant.error_name(response.error_code)}'
|
||||||
)
|
)
|
||||||
# TODO raise appropriate exception
|
raise ATT_Error(
|
||||||
return
|
error_code=response.error_code,
|
||||||
|
message='Unexpected error while discovering services',
|
||||||
|
)
|
||||||
break
|
break
|
||||||
|
|
||||||
for (
|
for (
|
||||||
@@ -349,7 +364,7 @@ class Client:
|
|||||||
logger.warning(
|
logger.warning(
|
||||||
f'bogus handle values: {attribute_handle} {end_group_handle}'
|
f'bogus handle values: {attribute_handle} {end_group_handle}'
|
||||||
)
|
)
|
||||||
return
|
return []
|
||||||
|
|
||||||
# Create a service proxy for this service
|
# Create a service proxy for this service
|
||||||
service = ServiceProxy(
|
service = ServiceProxy(
|
||||||
@@ -452,7 +467,9 @@ class Client:
|
|||||||
# TODO
|
# TODO
|
||||||
return []
|
return []
|
||||||
|
|
||||||
async def discover_characteristics(self, uuids, service):
|
async def discover_characteristics(
|
||||||
|
self, uuids, service: Optional[ServiceProxy]
|
||||||
|
) -> List[CharacteristicProxy]:
|
||||||
'''
|
'''
|
||||||
See Vol 3, Part G - 4.6.1 Discover All Characteristics of a Service and 4.6.2
|
See Vol 3, Part G - 4.6.1 Discover All Characteristics of a Service and 4.6.2
|
||||||
Discover Characteristics by UUID
|
Discover Characteristics by UUID
|
||||||
@@ -465,12 +482,12 @@ class Client:
|
|||||||
services = [service] if service else self.services
|
services = [service] if service else self.services
|
||||||
|
|
||||||
# Perform characteristic discovery for each service
|
# Perform characteristic discovery for each service
|
||||||
discovered_characteristics = []
|
discovered_characteristics: List[CharacteristicProxy] = []
|
||||||
for service in services:
|
for service in services:
|
||||||
starting_handle = service.handle
|
starting_handle = service.handle
|
||||||
ending_handle = service.end_group_handle
|
ending_handle = service.end_group_handle
|
||||||
|
|
||||||
characteristics = []
|
characteristics: List[CharacteristicProxy] = []
|
||||||
while starting_handle <= ending_handle:
|
while starting_handle <= ending_handle:
|
||||||
response = await self.send_request(
|
response = await self.send_request(
|
||||||
ATT_Read_By_Type_Request(
|
ATT_Read_By_Type_Request(
|
||||||
@@ -491,8 +508,10 @@ class Client:
|
|||||||
'!!! unexpected error while discovering characteristics: '
|
'!!! unexpected error while discovering characteristics: '
|
||||||
f'{HCI_Constant.error_name(response.error_code)}'
|
f'{HCI_Constant.error_name(response.error_code)}'
|
||||||
)
|
)
|
||||||
# TODO raise appropriate exception
|
raise ATT_Error(
|
||||||
return
|
error_code=response.error_code,
|
||||||
|
message='Unexpected error while discovering characteristics',
|
||||||
|
)
|
||||||
break
|
break
|
||||||
|
|
||||||
# Stop if for some reason the list was empty
|
# Stop if for some reason the list was empty
|
||||||
@@ -535,8 +554,11 @@ class Client:
|
|||||||
return discovered_characteristics
|
return discovered_characteristics
|
||||||
|
|
||||||
async def discover_descriptors(
|
async def discover_descriptors(
|
||||||
self, characteristic=None, start_handle=None, end_handle=None
|
self,
|
||||||
):
|
characteristic: Optional[CharacteristicProxy] = None,
|
||||||
|
start_handle=None,
|
||||||
|
end_handle=None,
|
||||||
|
) -> List[DescriptorProxy]:
|
||||||
'''
|
'''
|
||||||
See Vol 3, Part G - 4.7.1 Discover All Characteristic Descriptors
|
See Vol 3, Part G - 4.7.1 Discover All Characteristic Descriptors
|
||||||
'''
|
'''
|
||||||
@@ -549,7 +571,7 @@ class Client:
|
|||||||
else:
|
else:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
descriptors = []
|
descriptors: List[DescriptorProxy] = []
|
||||||
while starting_handle <= ending_handle:
|
while starting_handle <= ending_handle:
|
||||||
response = await self.send_request(
|
response = await self.send_request(
|
||||||
ATT_Find_Information_Request(
|
ATT_Find_Information_Request(
|
||||||
|
|||||||
Reference in New Issue
Block a user