aboutsummaryrefslogtreecommitdiff
path: root/avatar
diff options
context:
space:
mode:
authoruael <uael@google.com>2023-04-20 01:00:34 +0000
committeruael <uael@google.com>2023-05-05 04:57:11 +0000
commitd4fbff7cb6223a14f88afbbe93fb4a87ea80f0aa (patch)
treecf0605878992a429226aed6eb6a36edf69b8136b /avatar
parentcbdefa9432d59b89efd67ba25683b93e776ac44a (diff)
downloadavatar-d4fbff7cb6223a14f88afbbe93fb4a87ea80f0aa.tar.gz
overall: update to latest bumble
This commit includes: * Remove the need to override `__repr__` for enums passed through `avatar.parameterized`. * Remove the set of `device.classic_enabled` which has been implemented into bumble. * Fixed `set_discoverable(False)` in the bumble server which should be true. * Normalize string format of UUID. * Add a server configuration class which is shared between a client and it's server. This class is now used to pass all pairing confirguations variables which make pairing configuration a lot easier. * Use mobly asserts instead of `assert` for better error messages, keep `assert` where necessary for the linter to be happy. Change-Id: I6b4a62127f30fc7179c7b8886186c2ba0fa880fe
Diffstat (limited to 'avatar')
-rw-r--r--avatar/__init__.py14
-rw-r--r--avatar/bumble_device.py2
-rw-r--r--avatar/bumble_server/__init__.py39
-rw-r--r--avatar/bumble_server/config.py42
-rw-r--r--avatar/bumble_server/host.py33
-rw-r--r--avatar/bumble_server/security.py48
-rw-r--r--avatar/pandora_client.py9
-rw-r--r--avatar/pandora_server.py11
8 files changed, 136 insertions, 62 deletions
diff --git a/avatar/__init__.py b/avatar/__init__.py
index 8050261..a533502 100644
--- a/avatar/__init__.py
+++ b/avatar/__init__.py
@@ -19,6 +19,7 @@ any Bluetooth test cases virtually and physically.
__version__ = "0.0.1"
+import enum
import functools
import grpc
import grpc.aio
@@ -30,7 +31,7 @@ from avatar.aio import asynchronous
from avatar.pandora_client import BumblePandoraClient as BumblePandoraDevice, PandoraClient as PandoraDevice
from avatar.pandora_server import PandoraServer
from mobly import base_test
-from typing import Any, Callable, Dict, Iterable, Iterator, List, Sized, Tuple, Type, TypeVar
+from typing import Any, Callable, Dict, Iterable, Iterator, List, Optional, Sized, Tuple, Type, TypeVar
# public symbols
__all__ = [
@@ -174,9 +175,18 @@ def parameterized(*inputs: Tuple[Any, ...]) -> Type[Wrapper]:
return wrapper
+ def normalize(a: Any) -> Any:
+ if isinstance(a, enum.Enum):
+ return a.value
+ return a
+
# we need to pass `input` here, otherwise it will be set to the value
# from the last iteration of `inputs`
- setattr(owner, f"{name}{input}".replace(' ', ''), decorate(input))
+ setattr(
+ owner,
+ f"{name}{tuple([normalize(a) for a in input])}".replace(" ", ""),
+ decorate(input),
+ )
delattr(owner, name)
return wrapper
diff --git a/avatar/bumble_device.py b/avatar/bumble_device.py
index 872e013..f688e48 100644
--- a/avatar/bumble_device.py
+++ b/avatar/bumble_device.py
@@ -98,8 +98,6 @@ def _make_device(config: Dict[str, Any]) -> Device:
device_config.load_from_dict(config)
device = Device(config=device_config, host=None)
- # FIXME: add `classic_enabled` to `DeviceConfiguration` ?
- device.classic_enabled = config.get('classic_enabled', False)
# Add fake a2dp service to avoid Android disconnect
device.sdp_service_records = _make_sdp_records(1)
diff --git a/avatar/bumble_server/__init__.py b/avatar/bumble_server/__init__.py
index 184968f..d0e0600 100644
--- a/avatar/bumble_server/__init__.py
+++ b/avatar/bumble_server/__init__.py
@@ -21,48 +21,57 @@ import grpc
import grpc.aio
import logging
+from .config import Config
from avatar.bumble_device import BumbleDevice
from avatar.bumble_server.host import HostService
from avatar.bumble_server.security import SecurityService, SecurityStorageService
-from bumble.smp import PairingDelegate
from pandora.host_grpc_aio import add_HostServicer_to_server
from pandora.security_grpc_aio import add_SecurityServicer_to_server, add_SecurityStorageServicer_to_server
from typing import Callable, List, Optional
+# public symbols
+__all__ = [
+ 'register_servicer_hook',
+ 'serve',
+ 'Config',
+]
+
+
# Add servicers hooks.
-_SERVICERS_HOOKS: List[Callable[[BumbleDevice, grpc.aio.Server], None]] = []
+_SERVICERS_HOOKS: List[Callable[[BumbleDevice, Config, grpc.aio.Server], None]] = []
-def register_servicer_hook(hook: Callable[[BumbleDevice, grpc.aio.Server], None]) -> None:
+def register_servicer_hook(hook: Callable[[BumbleDevice, Config, grpc.aio.Server], None]) -> None:
_SERVICERS_HOOKS.append(hook)
-async def serve_bumble(bumble: BumbleDevice, grpc_server: Optional[grpc.aio.Server] = None, port: int = 0) -> None:
+async def serve(
+ bumble: BumbleDevice, config: Config = Config(), grpc_server: Optional[grpc.aio.Server] = None, port: int = 0
+) -> None:
# initialize a gRPC server if not provided.
server = grpc_server if grpc_server is not None else grpc.aio.server()
port = server.add_insecure_port(f'localhost:{port}')
- # load IO capability from config.
- io_capability_name: str = bumble.config.get('io_capability', 'no_output_no_input').upper()
- io_capability: int = getattr(PairingDelegate, io_capability_name)
-
try:
while True:
+ # load server config from dict.
+ config.load_from_dict(bumble.config.get('server', {}))
+
# add Pandora services to the gRPC server.
- add_HostServicer_to_server(HostService(server, bumble.device), server)
- add_SecurityServicer_to_server(SecurityService(bumble.device, io_capability), server)
- add_SecurityStorageServicer_to_server(SecurityStorageService(bumble.device), server)
+ add_HostServicer_to_server(HostService(server, bumble.device, config), server)
+ add_SecurityServicer_to_server(SecurityService(bumble.device, config), server)
+ add_SecurityStorageServicer_to_server(SecurityStorageService(bumble.device, config), server)
# call hooks if any.
for hook in _SERVICERS_HOOKS:
- hook(bumble, server)
+ hook(bumble, config, server)
# open device.
await bumble.open()
try:
- # Pandora require classic devices to to be discoverable & connectable.
+ # Pandora require classic devices to be discoverable & connectable.
if bumble.device.classic_enabled:
- await bumble.device.set_discoverable(False)
+ await bumble.device.set_discoverable(True)
await bumble.device.set_connectable(True)
# start & serve gRPC server.
@@ -86,4 +95,4 @@ ROOTCANAL_PORT_CUTTLEFISH = 7300
if __name__ == '__main__':
bumble = BumbleDevice({'transport': f'tcp-client:127.0.0.1:{ROOTCANAL_PORT_CUTTLEFISH}', 'classic_enabled': True})
logging.basicConfig(level=logging.DEBUG)
- asyncio.run(serve_bumble(bumble, port=BUMBLE_SERVER_GRPC_PORT))
+ asyncio.run(serve(bumble, port=BUMBLE_SERVER_GRPC_PORT))
diff --git a/avatar/bumble_server/config.py b/avatar/bumble_server/config.py
new file mode 100644
index 0000000..2e5d44e
--- /dev/null
+++ b/avatar/bumble_server/config.py
@@ -0,0 +1,42 @@
+# Copyright 2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from bumble.pairing import PairingDelegate
+from dataclasses import dataclass
+from typing import Any, Dict
+
+
+@dataclass
+class Config:
+ io_capability: PairingDelegate.IoCapability = PairingDelegate.NO_OUTPUT_NO_INPUT
+ pairing_sc_enable: bool = True
+ pairing_mitm_enable: bool = True
+ pairing_bonding_enable: bool = True
+ smp_local_initiator_key_distribution: PairingDelegate.KeyDistribution = PairingDelegate.DEFAULT_KEY_DISTRIBUTION
+ smp_local_responder_key_distribution: PairingDelegate.KeyDistribution = PairingDelegate.DEFAULT_KEY_DISTRIBUTION
+
+ def load_from_dict(self, config: Dict[str, Any]) -> None:
+ io_capability_name: str = config.get('io_capability', 'no_output_no_input').upper()
+ self.io_capability = getattr(PairingDelegate, io_capability_name)
+ self.pairing_sc_enable = config.get('pairing_sc_enable', True)
+ self.pairing_mitm_enable = config.get('pairing_mitm_enable', True)
+ self.pairing_bonding_enable = config.get('pairing_bonding_enable', True)
+ self.smp_local_initiator_key_distribution = config.get(
+ 'smp_local_initiator_key_distribution',
+ PairingDelegate.DEFAULT_KEY_DISTRIBUTION,
+ )
+ self.smp_local_responder_key_distribution = config.get(
+ 'smp_local_responder_key_distribution',
+ PairingDelegate.DEFAULT_KEY_DISTRIBUTION,
+ )
diff --git a/avatar/bumble_server/host.py b/avatar/bumble_server/host.py
index d9d6e4a..4060601 100644
--- a/avatar/bumble_server/host.py
+++ b/avatar/bumble_server/host.py
@@ -20,6 +20,7 @@ import logging
import struct
from . import utils
+from .config import Config
from bumble.core import (
BT_BR_EDR_TRANSPORT,
BT_LE_TRANSPORT,
@@ -93,15 +94,13 @@ SECONDARY_PHY_MAP: Dict[int, SecondaryPhy] = {
class HostService(HostServicer):
- grpc_server: grpc.aio.Server
- device: Device
waited_connections: Set[int]
- def __init__(self, grpc_server: grpc.aio.Server, device: Device) -> None:
- super().__init__()
+ def __init__(self, grpc_server: grpc.aio.Server, device: Device, config: Config) -> None:
self.log = utils.BumbleServerLoggerAdapter(logging.getLogger(), {'service_name': 'Host', 'device': device})
self.grpc_server = grpc_server
self.device = device
+ self.config = config
self.waited_connections = set()
@utils.rpc
@@ -276,7 +275,7 @@ class HostService(HostServicer):
# Retrieve services data
for service in self.device.gatt_server.attributes:
if isinstance(service, Service) and (service_data := service.get_advertising_data()):
- service_uuid = service.uuid.to_hex_str()
+ service_uuid = service.uuid.to_hex_str('-')
if (
service_uuid in request.data.incomplete_service_class_uuids16
or service_uuid in request.data.complete_service_class_uuids16
@@ -630,17 +629,17 @@ class HostService(HostServicer):
data: bytes
if uuids := cast(List[UUID], ad.get(AdvertisingData.INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS)):
- dt.incomplete_service_class_uuids16.extend(list(map(lambda x: x.to_hex_str(), uuids)))
+ dt.incomplete_service_class_uuids16.extend(list(map(lambda x: x.to_hex_str('-'), uuids)))
if uuids := cast(List[UUID], ad.get(AdvertisingData.COMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS)):
- dt.complete_service_class_uuids16.extend(list(map(lambda x: x.to_hex_str(), uuids)))
+ dt.complete_service_class_uuids16.extend(list(map(lambda x: x.to_hex_str('-'), uuids)))
if uuids := cast(List[UUID], ad.get(AdvertisingData.INCOMPLETE_LIST_OF_32_BIT_SERVICE_CLASS_UUIDS)):
- dt.incomplete_service_class_uuids32.extend(list(map(lambda x: x.to_hex_str(), uuids)))
+ dt.incomplete_service_class_uuids32.extend(list(map(lambda x: x.to_hex_str('-'), uuids)))
if uuids := cast(List[UUID], ad.get(AdvertisingData.COMPLETE_LIST_OF_32_BIT_SERVICE_CLASS_UUIDS)):
- dt.complete_service_class_uuids32.extend(list(map(lambda x: x.to_hex_str(), uuids)))
+ dt.complete_service_class_uuids32.extend(list(map(lambda x: x.to_hex_str('-'), uuids)))
if uuids := cast(List[UUID], ad.get(AdvertisingData.INCOMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS)):
- dt.incomplete_service_class_uuids128.extend(list(map(lambda x: x.to_hex_str(), uuids)))
+ dt.incomplete_service_class_uuids128.extend(list(map(lambda x: x.to_hex_str('-'), uuids)))
if uuids := cast(List[UUID], ad.get(AdvertisingData.COMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS)):
- dt.complete_service_class_uuids128.extend(list(map(lambda x: x.to_hex_str(), uuids)))
+ dt.complete_service_class_uuids128.extend(list(map(lambda x: x.to_hex_str('-'), uuids)))
if s := cast(str, ad.get(AdvertisingData.SHORTENED_LOCAL_NAME)):
dt.shortened_local_name = s
if s := cast(str, ad.get(AdvertisingData.COMPLETE_LOCAL_NAME)):
@@ -653,17 +652,17 @@ class HostService(HostServicer):
dt.peripheral_connection_interval_min = ij[0]
dt.peripheral_connection_interval_max = ij[1]
if uuids := cast(List[UUID], ad.get(AdvertisingData.LIST_OF_16_BIT_SERVICE_SOLICITATION_UUIDS)):
- dt.service_solicitation_uuids16.extend(list(map(lambda x: x.to_hex_str(), uuids)))
+ dt.service_solicitation_uuids16.extend(list(map(lambda x: x.to_hex_str('-'), uuids)))
if uuids := cast(List[UUID], ad.get(AdvertisingData.LIST_OF_32_BIT_SERVICE_SOLICITATION_UUIDS)):
- dt.service_solicitation_uuids32.extend(list(map(lambda x: x.to_hex_str(), uuids)))
+ dt.service_solicitation_uuids32.extend(list(map(lambda x: x.to_hex_str('-'), uuids)))
if uuids := cast(List[UUID], ad.get(AdvertisingData.LIST_OF_128_BIT_SERVICE_SOLICITATION_UUIDS)):
- dt.service_solicitation_uuids128.extend(list(map(lambda x: x.to_hex_str(), uuids)))
+ dt.service_solicitation_uuids128.extend(list(map(lambda x: x.to_hex_str('-'), uuids)))
if uuid_data := cast(Tuple[UUID, bytes], ad.get(AdvertisingData.SERVICE_DATA_16_BIT_UUID)):
- dt.service_data_uuid16[uuid_data[0].to_hex_str()] = uuid_data[1]
+ dt.service_data_uuid16[uuid_data[0].to_hex_str('-')] = uuid_data[1]
if uuid_data := cast(Tuple[UUID, bytes], ad.get(AdvertisingData.SERVICE_DATA_32_BIT_UUID)):
- dt.service_data_uuid32[uuid_data[0].to_hex_str()] = uuid_data[1]
+ dt.service_data_uuid32[uuid_data[0].to_hex_str('-')] = uuid_data[1]
if uuid_data := cast(Tuple[UUID, bytes], ad.get(AdvertisingData.SERVICE_DATA_128_BIT_UUID)):
- dt.service_data_uuid128[uuid_data[0].to_hex_str()] = uuid_data[1]
+ dt.service_data_uuid128[uuid_data[0].to_hex_str('-')] = uuid_data[1]
if data := cast(bytes, ad.get(AdvertisingData.PUBLIC_TARGET_ADDRESS, raw=True)):
dt.public_target_addresses.extend([data[i * 6 :: i * 6 + 6] for i in range(int(len(data) / 6))])
if data := cast(bytes, ad.get(AdvertisingData.RANDOM_TARGET_ADDRESS, raw=True)):
diff --git a/avatar/bumble_server/security.py b/avatar/bumble_server/security.py
index 000d49f..279aa42 100644
--- a/avatar/bumble_server/security.py
+++ b/avatar/bumble_server/security.py
@@ -17,11 +17,12 @@ import grpc
import logging
from . import utils
+from .config import Config
from bumble import hci
from bumble.core import BT_BR_EDR_TRANSPORT, BT_LE_TRANSPORT, BT_PERIPHERAL_ROLE, ProtocolError
from bumble.device import Connection as BumbleConnection, Device
from bumble.hci import HCI_Error
-from bumble.smp import PairingConfig, PairingDelegate as BasePairingDelegate
+from bumble.pairing import PairingConfig, PairingDelegate as BasePairingDelegate
from contextlib import suppress
from google.protobuf import any_pb2, empty_pb2, wrappers_pb2 # pytype: disable=pyi-error
from google.protobuf.wrappers_pb2 import BoolValue # pytype: disable=pyi-error
@@ -48,7 +49,7 @@ from pandora.security_pb2 import (
WaitSecurityRequest,
WaitSecurityResponse,
)
-from typing import Any, AsyncGenerator, AsyncIterator, Callable, Dict, Optional, Union, cast
+from typing import Any, AsyncGenerator, AsyncIterator, Callable, Dict, Optional, Union
class PairingDelegate(BasePairingDelegate):
@@ -56,9 +57,9 @@ class PairingDelegate(BasePairingDelegate):
self,
connection: BumbleConnection,
service: "SecurityService",
- io_capability: int = BasePairingDelegate.NO_OUTPUT_NO_INPUT,
- local_initiator_key_distribution: int = BasePairingDelegate.DEFAULT_KEY_DISTRIBUTION,
- local_responder_key_distribution: int = BasePairingDelegate.DEFAULT_KEY_DISTRIBUTION,
+ io_capability: BasePairingDelegate.IoCapability = BasePairingDelegate.NO_OUTPUT_NO_INPUT,
+ local_initiator_key_distribution: BasePairingDelegate.KeyDistribution = BasePairingDelegate.DEFAULT_KEY_DISTRIBUTION,
+ local_responder_key_distribution: BasePairingDelegate.KeyDistribution = BasePairingDelegate.DEFAULT_KEY_DISTRIBUTION,
) -> None:
self.log = utils.BumbleServerLoggerAdapter(
logging.getLogger(), {'service_name': 'Security', 'device': connection.device}
@@ -82,7 +83,7 @@ class PairingDelegate(BasePairingDelegate):
return ev
- async def confirm(self) -> bool:
+ async def confirm(self, auto: bool = False) -> bool:
self.log.info(f"Pairing event: `just_works` (io_capability: {self.io_capability})")
if self.service.event_queue is None or self.service.event_answer is None:
@@ -143,6 +144,12 @@ class PairingDelegate(BasePairingDelegate):
return pin
async def display_number(self, number: int, digits: int = 6) -> None:
+ if (
+ self.connection.transport == BT_BR_EDR_TRANSPORT
+ and self.io_capability == BasePairingDelegate.DISPLAY_OUTPUT_ONLY
+ ):
+ return
+
self.log.info(f"Pairing event: `passkey_entry_notification` (io_capability: {self.io_capability})")
if self.service.event_queue is None:
@@ -177,23 +184,27 @@ LE_LEVEL_REACHED: Dict[LESecurityLevel, Callable[[BumbleConnection], bool]] = {
class SecurityService(SecurityServicer):
- def __init__(self, device: Device, io_capability: int) -> None:
+ def __init__(self, device: Device, config: Config) -> None:
self.log = utils.BumbleServerLoggerAdapter(logging.getLogger(), {'service_name': 'Security', 'device': device})
self.event_queue: Optional[asyncio.Queue[PairingEvent]] = None
self.event_answer: Optional[AsyncIterator[PairingEventAnswer]] = None
self.device = device
+ self.config = config
def pairing_config_factory(connection: BumbleConnection) -> PairingConfig:
return PairingConfig(
- sc=True,
- mitm=True,
- bonding=True,
+ sc=config.pairing_sc_enable,
+ mitm=config.pairing_mitm_enable,
+ bonding=config.pairing_bonding_enable,
delegate=PairingDelegate(
- connection, self, io_capability=cast(int, getattr(self.device, 'io_capability'))
+ connection,
+ self,
+ io_capability=config.io_capability,
+ local_initiator_key_distribution=config.smp_local_initiator_key_distribution,
+ local_responder_key_distribution=config.smp_local_responder_key_distribution,
),
)
- setattr(device, 'io_capability', io_capability)
self.device.pairing_config_factory = pairing_config_factory
@utils.rpc
@@ -253,7 +264,7 @@ class SecurityService(SecurityServicer):
self.log.info('Paired')
except asyncio.CancelledError:
- self.log.warning(f"Connection died during encryption")
+ self.log.warning("Connection died during encryption")
return SecureResponse(connection_died=empty_pb2.Empty())
except (HCI_Error, ProtocolError) as e:
self.log.warning(f"Pairing failure: {e}")
@@ -266,7 +277,7 @@ class SecurityService(SecurityServicer):
await connection.authenticate()
self.log.info('Authenticated')
except asyncio.CancelledError:
- self.log.warning(f"Connection died during authentication")
+ self.log.warning("Connection died during authentication")
return SecureResponse(connection_died=empty_pb2.Empty())
except (HCI_Error, ProtocolError) as e:
self.log.warning(f"Authentication failure: {e}")
@@ -279,7 +290,7 @@ class SecurityService(SecurityServicer):
await connection.encrypt()
self.log.info('Encrypted')
except asyncio.CancelledError:
- self.log.warning(f"Connection died during encryption")
+ self.log.warning("Connection died during encryption")
return SecureResponse(connection_died=empty_pb2.Empty())
except (HCI_Error, ProtocolError) as e:
self.log.warning(f"Encryption failure: {e}")
@@ -334,13 +345,13 @@ class SecurityService(SecurityServicer):
def try_set_success(*_: Any) -> None:
assert connection
if self.reached_security_level(connection, level):
- self.log.info(f'Wait for security: done')
+ self.log.info('Wait for security: done')
wait_for_security.set_result('success')
def on_encryption_change(*_: Any) -> None:
assert connection
if self.reached_security_level(connection, level):
- self.log.info(f'Wait for security: done')
+ self.log.info('Wait for security: done')
wait_for_security.set_result('success')
elif connection.transport == BT_BR_EDR_TRANSPORT and self.need_authentication(connection, level):
nonlocal authenticate_task
@@ -424,11 +435,12 @@ class SecurityService(SecurityServicer):
class SecurityStorageService(SecurityStorageServicer):
- def __init__(self, device: Device) -> None:
+ def __init__(self, device: Device, config: Config) -> None:
self.log = utils.BumbleServerLoggerAdapter(
logging.getLogger(), {'service_name': 'SecurityStorage', 'device': device}
)
self.device = device
+ self.config = config
@utils.rpc
async def IsBonded(self, request: IsBondedRequest, context: grpc.ServicerContext) -> wrappers_pb2.BoolValue:
diff --git a/avatar/pandora_client.py b/avatar/pandora_client.py
index 548e6d1..e603fef 100644
--- a/avatar/pandora_client.py
+++ b/avatar/pandora_client.py
@@ -23,6 +23,7 @@ import grpc
import grpc.aio
import logging
+from avatar import bumble_server
from avatar.bumble_device import BumbleDevice
from bumble.hci import Address as BumbleAddress
from dataclasses import dataclass
@@ -186,10 +187,16 @@ class BumblePandoraClient(PandoraClient):
"""Special Pandora client which also give access to a Bumble device instance."""
_bumble: BumbleDevice # Bumble device wrapper.
+ _server_config: bumble_server.Config # Bumble server config.
- def __init__(self, grpc_target: str, bumble: BumbleDevice) -> None:
+ def __init__(self, grpc_target: str, bumble: BumbleDevice, server_config: bumble_server.Config) -> None:
super().__init__(grpc_target, 'bumble')
self._bumble = bumble
+ self._server_config = server_config
+
+ @property
+ def server_config(self) -> bumble_server.Config:
+ return self._server_config
@property
def config(self) -> Dict[str, Any]:
diff --git a/avatar/pandora_server.py b/avatar/pandora_server.py
index a947ea8..eab92c4 100644
--- a/avatar/pandora_server.py
+++ b/avatar/pandora_server.py
@@ -22,8 +22,8 @@ import grpc.aio
import threading
import types
+from avatar import bumble_server
from avatar.bumble_device import BumbleDevice
-from avatar.bumble_server import serve_bumble
from avatar.controllers import bumble_device, pandora_device
from avatar.pandora_client import BumblePandoraClient, PandoraClient
from contextlib import suppress
@@ -81,15 +81,12 @@ class BumblePandoraServer(PandoraServer[BumbleDevice]):
server = grpc.aio.server()
port = server.add_insecure_port(f'localhost:{0}')
+ config = bumble_server.Config()
self._task = avatar.aio.loop.create_task(
- serve_bumble(
- self.device,
- grpc_server=server,
- port=port,
- )
+ bumble_server.serve(self.device, config=config, grpc_server=server, port=port)
)
- return BumblePandoraClient(f'localhost:{port}', self.device)
+ return BumblePandoraClient(f'localhost:{port}', self.device, config)
def stop(self) -> None:
"""Stops and cleans up the Pandora server on the Bumble device."""