Improve performance of converting raw BLE advertisements (#462)

This commit is contained in:
J. Nick Koston 2023-07-09 13:06:06 -10:00 committed by GitHub
parent b81fe760ba
commit 8ac62a321f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 51 additions and 32 deletions

View File

@ -134,7 +134,6 @@ from .model import (
BluetoothGATTServices, BluetoothGATTServices,
BluetoothLEAdvertisement, BluetoothLEAdvertisement,
BluetoothLERawAdvertisement, BluetoothLERawAdvertisement,
BluetoothLERawAdvertisements,
BluetoothProxyFeature, BluetoothProxyFeature,
BluetoothProxySubscriptionFlag, BluetoothProxySubscriptionFlag,
ButtonInfo, ButtonInfo,
@ -183,6 +182,7 @@ from .model import (
UserServiceArgType, UserServiceArgType,
VoiceAssistantCommand, VoiceAssistantCommand,
VoiceAssistantEventType, VoiceAssistantEventType,
make_ble_raw_advertisement_processor,
) )
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -409,7 +409,7 @@ class APIClient:
} }
msg_types = (*response_types, CameraImageResponse) msg_types = (*response_types, CameraImageResponse)
def on_msg(msg: message.Message) -> None: def _on_state_msg(msg: message.Message) -> None:
msg_type = type(msg) msg_type = type(msg)
cls = response_types.get(msg_type) cls = response_types.get(msg_type)
if cls: if cls:
@ -432,7 +432,7 @@ class APIClient:
assert self._connection is not None assert self._connection is not None
self._connection.send_message_callback_response( self._connection.send_message_callback_response(
SubscribeStatesRequest(), on_msg, msg_types SubscribeStatesRequest(), _on_state_msg, msg_types
) )
async def subscribe_logs( async def subscribe_logs(
@ -457,13 +457,15 @@ class APIClient:
) -> None: ) -> None:
self._check_authenticated() self._check_authenticated()
def on_msg(msg: HomeassistantServiceResponse) -> None: def _on_home_assistant_service_response(
msg: HomeassistantServiceResponse,
) -> None:
on_service_call(HomeassistantServiceCall.from_pb(msg)) on_service_call(HomeassistantServiceCall.from_pb(msg))
assert self._connection is not None assert self._connection is not None
self._connection.send_message_callback_response( self._connection.send_message_callback_response(
SubscribeHomeassistantServicesRequest(), SubscribeHomeassistantServicesRequest(),
on_msg, _on_home_assistant_service_response,
(HomeassistantServiceResponse,), (HomeassistantServiceResponse,),
) )
@ -501,19 +503,23 @@ class APIClient:
self._check_authenticated() self._check_authenticated()
msg_types = (BluetoothLEAdvertisementResponse,) msg_types = (BluetoothLEAdvertisementResponse,)
def on_msg(msg: BluetoothLEAdvertisementResponse) -> None: def _on_bluetooth_le_advertising_response(
msg: BluetoothLEAdvertisementResponse,
) -> None:
on_bluetooth_le_advertisement(BluetoothLEAdvertisement.from_pb(msg)) # type: ignore[misc] on_bluetooth_le_advertisement(BluetoothLEAdvertisement.from_pb(msg)) # type: ignore[misc]
assert self._connection is not None assert self._connection is not None
self._connection.send_message_callback_response( self._connection.send_message_callback_response(
SubscribeBluetoothLEAdvertisementsRequest(flags=0), SubscribeBluetoothLEAdvertisementsRequest(flags=0),
on_msg, _on_bluetooth_le_advertising_response,
msg_types, msg_types,
) )
def unsub() -> None: def unsub() -> None:
if self._connection is not None: if self._connection is not None:
self._connection.remove_message_callback(on_msg, msg_types) self._connection.remove_message_callback(
_on_bluetooth_le_advertising_response, msg_types
)
self._connection.send_message( self._connection.send_message(
UnsubscribeBluetoothLEAdvertisementsRequest() UnsubscribeBluetoothLEAdvertisementsRequest()
) )
@ -526,10 +532,8 @@ class APIClient:
self._check_authenticated() self._check_authenticated()
msg_types = (BluetoothLERawAdvertisementsResponse,) msg_types = (BluetoothLERawAdvertisementsResponse,)
def on_msg(msg: BluetoothLERawAdvertisementsResponse) -> None:
on_advertisements(BluetoothLERawAdvertisements.from_pb(msg).advertisements) # type: ignore[misc]
assert self._connection is not None assert self._connection is not None
on_msg = make_ble_raw_advertisement_processor(on_advertisements)
self._connection.send_message_callback_response( self._connection.send_message_callback_response(
SubscribeBluetoothLEAdvertisementsRequest( SubscribeBluetoothLEAdvertisementsRequest(
flags=BluetoothProxySubscriptionFlag.RAW_ADVERTISEMENTS flags=BluetoothProxySubscriptionFlag.RAW_ADVERTISEMENTS
@ -553,18 +557,24 @@ class APIClient:
self._check_authenticated() self._check_authenticated()
msg_types = (BluetoothConnectionsFreeResponse,) msg_types = (BluetoothConnectionsFreeResponse,)
def on_msg(msg: BluetoothConnectionsFreeResponse) -> None: def _on_bluetooth_connections_free_response(
msg: BluetoothConnectionsFreeResponse,
) -> None:
resp = BluetoothConnectionsFree.from_pb(msg) resp = BluetoothConnectionsFree.from_pb(msg)
on_bluetooth_connections_free_update(resp.free, resp.limit) on_bluetooth_connections_free_update(resp.free, resp.limit)
assert self._connection is not None assert self._connection is not None
self._connection.send_message_callback_response( self._connection.send_message_callback_response(
SubscribeBluetoothConnectionsFreeRequest(), on_msg, msg_types SubscribeBluetoothConnectionsFreeRequest(),
_on_bluetooth_connections_free_response,
msg_types,
) )
def unsub() -> None: def unsub() -> None:
if self._connection is not None: if self._connection is not None:
self._connection.remove_message_callback(on_msg, msg_types) self._connection.remove_message_callback(
_on_bluetooth_connections_free_response, msg_types
)
return unsub return unsub
@ -583,7 +593,9 @@ class APIClient:
event = asyncio.Event() event = asyncio.Event()
def on_msg(msg: BluetoothDeviceConnectionResponse) -> None: def _on_bluetooth_device_connection_response(
msg: BluetoothDeviceConnectionResponse,
) -> None:
resp = BluetoothDeviceConnection.from_pb(msg) resp = BluetoothDeviceConnection.from_pb(msg)
if address == resp.address: if address == resp.address:
on_bluetooth_connection_state(resp.connected, resp.mtu, resp.error) on_bluetooth_connection_state(resp.connected, resp.mtu, resp.error)
@ -614,13 +626,15 @@ class APIClient:
has_address_type=address_type is not None, has_address_type=address_type is not None,
address_type=address_type or 0, address_type=address_type or 0,
), ),
on_msg, _on_bluetooth_device_connection_response,
msg_types, msg_types,
) )
def unsub() -> None: def unsub() -> None:
if self._connection is not None: if self._connection is not None:
self._connection.remove_message_callback(on_msg, msg_types) self._connection.remove_message_callback(
_on_bluetooth_device_connection_response, msg_types
)
try: try:
try: try:
@ -930,14 +944,16 @@ class APIClient:
BluetoothGATTNotifyResponse, BluetoothGATTNotifyResponse,
) )
def on_msg(msg: BluetoothGATTNotifyDataResponse) -> None: def _on_bluetooth_gatt_notify_data_response(
msg: BluetoothGATTNotifyDataResponse,
) -> None:
notify = BluetoothGATTRead.from_pb(msg) notify = BluetoothGATTRead.from_pb(msg)
if address == notify.address and handle == notify.handle: if address == notify.address and handle == notify.handle:
on_bluetooth_gatt_notify(handle, bytearray(notify.data)) on_bluetooth_gatt_notify(handle, bytearray(notify.data))
assert self._connection is not None assert self._connection is not None
remove_callback = self._connection.add_message_callback( remove_callback = self._connection.add_message_callback(
on_msg, (BluetoothGATTNotifyDataResponse,) _on_bluetooth_gatt_notify_data_response, (BluetoothGATTNotifyDataResponse,)
) )
async def stop_notify() -> None: async def stop_notify() -> None:
@ -959,13 +975,15 @@ class APIClient:
) -> None: ) -> None:
self._check_authenticated() self._check_authenticated()
def on_msg(msg: SubscribeHomeAssistantStateResponse) -> None: def _on_subscribe_home_assistant_state_response(
msg: SubscribeHomeAssistantStateResponse,
) -> None:
on_state_sub(msg.entity_id, msg.attribute) on_state_sub(msg.entity_id, msg.attribute)
assert self._connection is not None assert self._connection is not None
self._connection.send_message_callback_response( self._connection.send_message_callback_response(
SubscribeHomeAssistantStatesRequest(), SubscribeHomeAssistantStatesRequest(),
on_msg, _on_subscribe_home_assistant_state_response,
(SubscribeHomeAssistantStateResponse,), (SubscribeHomeAssistantStateResponse,),
) )
@ -1349,7 +1367,7 @@ class APIClient:
_LOGGER.error("Server could not be started") _LOGGER.error("Server could not be started")
self._connection.send_message(VoiceAssistantResponse(error=True)) self._connection.send_message(VoiceAssistantResponse(error=True))
def on_msg(msg: VoiceAssistantRequest) -> None: def _on_voice_assistant_request(msg: VoiceAssistantRequest) -> None:
command = VoiceAssistantCommand.from_pb(msg) command = VoiceAssistantCommand.from_pb(msg)
if command.start: if command.start:
start_task = asyncio.create_task( start_task = asyncio.create_task(
@ -1368,7 +1386,7 @@ class APIClient:
self._connection.send_message(SubscribeVoiceAssistantRequest(subscribe=True)) self._connection.send_message(SubscribeVoiceAssistantRequest(subscribe=True))
remove_callback = self._connection.add_message_callback( remove_callback = self._connection.add_message_callback(
on_msg, (VoiceAssistantRequest,) _on_voice_assistant_request, (VoiceAssistantRequest,)
) )
def unsub() -> None: def unsub() -> None:

View File

@ -935,17 +935,16 @@ class BluetoothLERawAdvertisement:
data: bytes = field(default_factory=bytes) data: bytes = field(default_factory=bytes)
@_dataclass_decorator def make_ble_raw_advertisement_processor(
class BluetoothLERawAdvertisements: on_advertisements: Callable[[List[BluetoothLERawAdvertisement]], None]
advertisements: List[BluetoothLERawAdvertisement] ) -> Callable[["BluetoothLERawAdvertisementsResponse"], None]:
"""Make a processor for BluetoothLERawAdvertisementResponse."""
@classmethod def _on_ble_raw_advertisement_response(
def from_pb( # type: ignore[misc]
cls: "BluetoothLERawAdvertisements",
data: "BluetoothLERawAdvertisementsResponse", data: "BluetoothLERawAdvertisementsResponse",
) -> "BluetoothLERawAdvertisements": ) -> None:
return cls( # type: ignore[operator, no-any-return] on_advertisements(
advertisements=[ [
BluetoothLERawAdvertisement( # type: ignore[call-arg] BluetoothLERawAdvertisement( # type: ignore[call-arg]
adv.address, adv.rssi, adv.address_type, adv.data adv.address, adv.rssi, adv.address_type, adv.data
) )
@ -953,6 +952,8 @@ class BluetoothLERawAdvertisements:
] ]
) )
return _on_ble_raw_advertisement_response
@dataclass(frozen=True) @dataclass(frozen=True)
class BluetoothDeviceConnection(APIModelBase): class BluetoothDeviceConnection(APIModelBase):