mirror of
https://github.com/esphome/aioesphomeapi.git
synced 2024-11-23 12:15:13 +01:00
Add Bluetooth GATT calls (#259)
This commit is contained in:
parent
0e1ae31667
commit
6a82766553
@ -27,7 +27,6 @@ service APIConnection {
|
||||
rpc subscribe_logs (SubscribeLogsRequest) returns (void) {}
|
||||
rpc subscribe_homeassistant_services (SubscribeHomeassistantServicesRequest) returns (void) {}
|
||||
rpc subscribe_home_assistant_states (SubscribeHomeAssistantStatesRequest) returns (void) {}
|
||||
rpc subscribe_bluetooth_le_advertisements (SubscribeBluetoothLEAdvertisementsRequest) returns (void) {}
|
||||
rpc get_time (GetTimeRequest) returns (GetTimeResponse) {
|
||||
option (needs_authentication) = false;
|
||||
}
|
||||
@ -45,6 +44,15 @@ service APIConnection {
|
||||
rpc button_command (ButtonCommandRequest) returns (void) {}
|
||||
rpc lock_command (LockCommandRequest) returns (void) {}
|
||||
rpc media_player_command (MediaPlayerCommandRequest) returns (void) {}
|
||||
|
||||
rpc subscribe_bluetooth_le_advertisements (SubscribeBluetoothLEAdvertisementsRequest) returns (void) {}
|
||||
rpc bluetooth_device_request(BluetoothDeviceRequest) returns (void) {}
|
||||
rpc bluetooth_gatt_get_services(BluetoothGATTGetServicesRequest) returns (void) {}
|
||||
rpc bluetooth_gatt_read(BluetoothGATTReadRequest) returns (void) {}
|
||||
rpc bluetooth_gatt_write(BluetoothGATTWriteRequest) returns (void) {}
|
||||
rpc bluetooth_gatt_read_descriptor(BluetoothGATTReadDescriptorRequest) returns (void) {}
|
||||
rpc bluetooth_gatt_write_descriptor(BluetoothGATTWriteDescriptorRequest) returns (void) {}
|
||||
rpc bluetooth_gatt_notify(BluetoothGATTNotifyRequest) returns (void) {}
|
||||
}
|
||||
|
||||
|
||||
@ -1138,7 +1146,7 @@ message SubscribeBluetoothLEAdvertisementsRequest {
|
||||
|
||||
message BluetoothServiceData {
|
||||
string uuid = 1;
|
||||
repeated uint32 data = 2 [packed=false];
|
||||
repeated uint32 data = 2 [packed=true];
|
||||
}
|
||||
message BluetoothLEAdvertisementResponse {
|
||||
option (id) = 67;
|
||||
@ -1154,3 +1162,163 @@ message BluetoothLEAdvertisementResponse {
|
||||
repeated BluetoothServiceData service_data = 5;
|
||||
repeated BluetoothServiceData manufacturer_data = 6;
|
||||
}
|
||||
|
||||
enum BluetoothDeviceRequestType {
|
||||
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT = 0;
|
||||
BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT = 1;
|
||||
BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR = 2;
|
||||
BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR = 3;
|
||||
}
|
||||
|
||||
message BluetoothDeviceRequest {
|
||||
option (id) = 68;
|
||||
option (source) = SOURCE_CLIENT;
|
||||
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||
|
||||
uint64 address = 1;
|
||||
BluetoothDeviceRequestType request_type = 2;
|
||||
}
|
||||
|
||||
message BluetoothDeviceConnectionResponse {
|
||||
option (id) = 69;
|
||||
option (source) = SOURCE_SERVER;
|
||||
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||
|
||||
uint64 address = 1;
|
||||
bool connected = 2;
|
||||
uint32 mtu = 3;
|
||||
int32 error = 4;
|
||||
}
|
||||
|
||||
message BluetoothGATTGetServicesRequest {
|
||||
option (id) = 70;
|
||||
option (source) = SOURCE_CLIENT;
|
||||
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||
|
||||
uint64 address = 1;
|
||||
}
|
||||
|
||||
message BluetoothGATTDescriptor {
|
||||
string uuid = 1;
|
||||
uint32 handle = 2;
|
||||
string description = 3;
|
||||
}
|
||||
|
||||
message BluetoothGATTCharacteristic {
|
||||
string uuid = 1;
|
||||
uint32 handle = 2;
|
||||
uint32 properties = 3;
|
||||
repeated BluetoothGATTDescriptor descriptors = 4;
|
||||
}
|
||||
|
||||
message BluetoothGATTService {
|
||||
string uuid = 1;
|
||||
uint32 handle = 2;
|
||||
repeated BluetoothGATTCharacteristic characteristics = 3;
|
||||
}
|
||||
|
||||
message BluetoothGATTGetServicesResponse {
|
||||
option (id) = 71;
|
||||
option (source) = SOURCE_SERVER;
|
||||
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||
|
||||
uint64 address = 1;
|
||||
repeated BluetoothGATTService services = 2;
|
||||
}
|
||||
|
||||
message BluetoothGATTGetServicesDoneResponse {
|
||||
option (id) = 72;
|
||||
option (source) = SOURCE_SERVER;
|
||||
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||
|
||||
uint64 address = 1;
|
||||
}
|
||||
|
||||
message BluetoothGATTReadRequest {
|
||||
option (id) = 73;
|
||||
option (source) = SOURCE_CLIENT;
|
||||
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||
|
||||
uint64 address = 1;
|
||||
uint32 handle = 2;
|
||||
}
|
||||
|
||||
message BluetoothGATTReadResponse {
|
||||
option (id) = 74;
|
||||
option (source) = SOURCE_SERVER;
|
||||
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||
|
||||
uint64 address = 1;
|
||||
uint32 handle = 2;
|
||||
|
||||
bytes data = 3;
|
||||
|
||||
}
|
||||
|
||||
message BluetoothGATTWriteRequest {
|
||||
option (id) = 75;
|
||||
option (source) = SOURCE_CLIENT;
|
||||
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||
|
||||
uint64 address = 1;
|
||||
uint32 handle = 2;
|
||||
bool response = 3;
|
||||
|
||||
bytes data = 4;
|
||||
}
|
||||
|
||||
message BluetoothGATTReadDescriptorRequest {
|
||||
option (id) = 76;
|
||||
option (source) = SOURCE_CLIENT;
|
||||
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||
|
||||
uint64 address = 1;
|
||||
uint32 handle = 2;
|
||||
}
|
||||
|
||||
message BluetoothGATTWriteDescriptorRequest {
|
||||
option (id) = 77;
|
||||
option (source) = SOURCE_CLIENT;
|
||||
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||
|
||||
uint64 address = 1;
|
||||
uint32 handle = 2;
|
||||
|
||||
bytes data = 3;
|
||||
}
|
||||
|
||||
message BluetoothGATTNotifyRequest {
|
||||
option (id) = 78;
|
||||
option (source) = SOURCE_CLIENT;
|
||||
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||
|
||||
uint64 address = 1;
|
||||
uint32 handle = 2;
|
||||
bool enable = 3;
|
||||
}
|
||||
|
||||
message BluetoothGATTNotifyDataResponse {
|
||||
option (id) = 79;
|
||||
option (source) = SOURCE_SERVER;
|
||||
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||
|
||||
uint64 address = 1;
|
||||
uint32 handle = 2;
|
||||
|
||||
bytes data = 3;
|
||||
}
|
||||
|
||||
message SubscribeBluetoothConnectionsFreeRequest {
|
||||
option (id) = 80;
|
||||
option (source) = SOURCE_CLIENT;
|
||||
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||
}
|
||||
|
||||
message BluetoothConnectionsFreeResponse {
|
||||
option (id) = 81;
|
||||
option (source) = SOURCE_SERVER;
|
||||
option (ifdef) = "USE_BLUETOOTH_PROXY";
|
||||
|
||||
uint32 free = 1;
|
||||
uint32 limit = 2;
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
@ -1,8 +1,11 @@
|
||||
# pylint: disable=too-many-lines
|
||||
import asyncio
|
||||
import logging
|
||||
from typing import (
|
||||
Any,
|
||||
Awaitable,
|
||||
Callable,
|
||||
Coroutine,
|
||||
Dict,
|
||||
List,
|
||||
Optional,
|
||||
@ -12,10 +15,24 @@ from typing import (
|
||||
cast,
|
||||
)
|
||||
|
||||
import async_timeout
|
||||
from google.protobuf import message
|
||||
|
||||
from .api_pb2 import ( # type: ignore
|
||||
BinarySensorStateResponse,
|
||||
BluetoothConnectionsFreeResponse,
|
||||
BluetoothDeviceConnectionResponse,
|
||||
BluetoothDeviceRequest,
|
||||
BluetoothGATTGetServicesDoneResponse,
|
||||
BluetoothGATTGetServicesRequest,
|
||||
BluetoothGATTGetServicesResponse,
|
||||
BluetoothGATTNotifyDataResponse,
|
||||
BluetoothGATTNotifyRequest,
|
||||
BluetoothGATTReadDescriptorRequest,
|
||||
BluetoothGATTReadRequest,
|
||||
BluetoothGATTReadResponse,
|
||||
BluetoothGATTWriteDescriptorRequest,
|
||||
BluetoothGATTWriteRequest,
|
||||
BluetoothLEAdvertisementResponse,
|
||||
ButtonCommandRequest,
|
||||
CameraImageRequest,
|
||||
@ -63,6 +80,7 @@ from .api_pb2 import ( # type: ignore
|
||||
SensorStateResponse,
|
||||
SirenCommandRequest,
|
||||
SirenStateResponse,
|
||||
SubscribeBluetoothConnectionsFreeRequest,
|
||||
SubscribeBluetoothLEAdvertisementsRequest,
|
||||
SubscribeHomeassistantServicesRequest,
|
||||
SubscribeHomeAssistantStateResponse,
|
||||
@ -75,12 +93,17 @@ from .api_pb2 import ( # type: ignore
|
||||
TextSensorStateResponse,
|
||||
)
|
||||
from .connection import APIConnection, ConnectionParams
|
||||
from .core import APIConnectionError
|
||||
from .core import APIConnectionError, TimeoutAPIError
|
||||
from .host_resolver import ZeroconfInstanceType
|
||||
from .model import (
|
||||
APIVersion,
|
||||
BinarySensorInfo,
|
||||
BinarySensorState,
|
||||
BluetoothConnectionsFree,
|
||||
BluetoothDeviceConnection,
|
||||
BluetoothDeviceRequestType,
|
||||
BluetoothGATTRead,
|
||||
BluetoothGATTServices,
|
||||
BluetoothLEAdvertisement,
|
||||
ButtonInfo,
|
||||
CameraInfo,
|
||||
@ -384,7 +407,7 @@ class APIClient:
|
||||
|
||||
async def subscribe_bluetooth_le_advertisements(
|
||||
self, on_bluetooth_le_advertisement: Callable[[BluetoothLEAdvertisement], None]
|
||||
) -> None:
|
||||
) -> Callable[[], None]:
|
||||
self._check_authenticated()
|
||||
|
||||
def on_msg(msg: message.Message) -> None:
|
||||
@ -396,6 +419,227 @@ class APIClient:
|
||||
SubscribeBluetoothLEAdvertisementsRequest(), on_msg
|
||||
)
|
||||
|
||||
def unsub() -> None:
|
||||
assert self._connection is not None
|
||||
self._connection.remove_message_callback(on_msg)
|
||||
|
||||
return unsub
|
||||
|
||||
async def subscribe_bluetooth_connections_free(
|
||||
self, on_bluetooth_connections_free_update: Callable[[int, int], None]
|
||||
) -> Callable[[], None]:
|
||||
self._check_authenticated()
|
||||
|
||||
def on_msg(msg: message.Message) -> None:
|
||||
if isinstance(msg, BluetoothConnectionsFreeResponse):
|
||||
resp = BluetoothConnectionsFree.from_pb(msg)
|
||||
on_bluetooth_connections_free_update(resp.free, resp.limit)
|
||||
|
||||
assert self._connection is not None
|
||||
await self._connection.send_message_callback_response(
|
||||
SubscribeBluetoothConnectionsFreeRequest(), on_msg
|
||||
)
|
||||
|
||||
def unsub() -> None:
|
||||
assert self._connection is not None
|
||||
self._connection.remove_message_callback(on_msg)
|
||||
|
||||
return unsub
|
||||
|
||||
async def bluetooth_device_connect(
|
||||
self,
|
||||
address: int,
|
||||
on_bluetooth_connection_state: Callable[[bool, int, int], None],
|
||||
timeout: float = 10.0,
|
||||
) -> Callable[[], None]:
|
||||
self._check_authenticated()
|
||||
|
||||
event = asyncio.Event()
|
||||
|
||||
def on_msg(msg: message.Message) -> None:
|
||||
if isinstance(msg, BluetoothDeviceConnectionResponse):
|
||||
resp = BluetoothDeviceConnection.from_pb(msg)
|
||||
if address == resp.address:
|
||||
on_bluetooth_connection_state(resp.connected, resp.mtu, resp.error)
|
||||
event.set()
|
||||
|
||||
assert self._connection is not None
|
||||
await self._connection.send_message_callback_response(
|
||||
BluetoothDeviceRequest(
|
||||
address=address,
|
||||
request_type=BluetoothDeviceRequestType.CONNECT,
|
||||
),
|
||||
on_msg,
|
||||
)
|
||||
|
||||
try:
|
||||
async with async_timeout.timeout(timeout):
|
||||
await event.wait()
|
||||
except asyncio.TimeoutError as err:
|
||||
raise TimeoutAPIError("Timeout waiting for connect response") from err
|
||||
|
||||
def unsub() -> None:
|
||||
assert self._connection is not None
|
||||
self._connection.remove_message_callback(on_msg)
|
||||
|
||||
return unsub
|
||||
|
||||
async def bluetooth_device_disconnect(self, address: int) -> None:
|
||||
self._check_authenticated()
|
||||
|
||||
assert self._connection is not None
|
||||
await self._connection.send_message(
|
||||
BluetoothDeviceRequest(
|
||||
address=address,
|
||||
request_type=BluetoothDeviceRequestType.DISCONNECT,
|
||||
)
|
||||
)
|
||||
|
||||
async def bluetooth_gatt_get_services(self, address: int) -> BluetoothGATTServices:
|
||||
self._check_authenticated()
|
||||
|
||||
def do_append(msg: message.Message) -> bool:
|
||||
return isinstance(msg, BluetoothGATTGetServicesResponse)
|
||||
|
||||
def do_stop(msg: message.Message) -> bool:
|
||||
return isinstance(msg, BluetoothGATTGetServicesDoneResponse)
|
||||
|
||||
assert self._connection is not None
|
||||
resp = await self._connection.send_message_await_response_complex(
|
||||
BluetoothGATTGetServicesRequest(address=address), do_append, do_stop
|
||||
)
|
||||
services = []
|
||||
for msg in resp:
|
||||
services.extend(BluetoothGATTServices.from_pb(msg).services)
|
||||
return BluetoothGATTServices(address=address, services=services)
|
||||
|
||||
async def bluetooth_gatt_read(
|
||||
self, address: int, characteristic_handle: int, timeout: float = 10.0
|
||||
) -> bytearray:
|
||||
self._check_authenticated()
|
||||
|
||||
req = BluetoothGATTReadRequest()
|
||||
req.address = address
|
||||
req.handle = characteristic_handle
|
||||
|
||||
def is_response(msg: message.Message) -> bool:
|
||||
if isinstance(msg, BluetoothGATTReadResponse):
|
||||
read = BluetoothGATTRead.from_pb(msg)
|
||||
|
||||
if read.address == address and read.handle == characteristic_handle:
|
||||
return True
|
||||
return False
|
||||
|
||||
assert self._connection is not None
|
||||
resp = await self._connection.send_message_await_response_complex(
|
||||
req, is_response, is_response, timeout=timeout
|
||||
)
|
||||
|
||||
if len(resp) != 1:
|
||||
raise APIConnectionError(f"Expected one result, got {len(resp)}")
|
||||
|
||||
read_response = BluetoothGATTRead.from_pb(resp[0])
|
||||
|
||||
return bytearray(read_response.data)
|
||||
|
||||
async def bluetooth_gatt_write(
|
||||
self,
|
||||
address: int,
|
||||
characteristic_handle: int,
|
||||
data: bytes,
|
||||
response: bool,
|
||||
) -> None:
|
||||
self._check_authenticated()
|
||||
|
||||
req = BluetoothGATTWriteRequest()
|
||||
req.address = address
|
||||
req.handle = characteristic_handle
|
||||
req.response = response
|
||||
req.data = data
|
||||
|
||||
assert self._connection is not None
|
||||
await self._connection.send_message(req)
|
||||
|
||||
async def bluetooth_gatt_read_descriptor(
|
||||
self,
|
||||
address: int,
|
||||
handle: int,
|
||||
timeout: float = 10.0,
|
||||
) -> bytearray:
|
||||
self._check_authenticated()
|
||||
|
||||
req = BluetoothGATTReadDescriptorRequest()
|
||||
req.address = address
|
||||
req.handle = handle
|
||||
|
||||
def is_response(msg: message.Message) -> bool:
|
||||
if isinstance(msg, BluetoothGATTReadResponse):
|
||||
read = BluetoothGATTRead.from_pb(msg)
|
||||
|
||||
if read.address == address and read.handle == handle:
|
||||
return True
|
||||
return False
|
||||
|
||||
assert self._connection is not None
|
||||
resp = await self._connection.send_message_await_response_complex(
|
||||
req, is_response, is_response, timeout=timeout
|
||||
)
|
||||
|
||||
if len(resp) != 1:
|
||||
raise APIConnectionError(f"Expected one result, got {len(resp)}")
|
||||
|
||||
read_response = BluetoothGATTRead.from_pb(resp[0])
|
||||
|
||||
return bytearray(read_response.data)
|
||||
|
||||
async def bluetooth_gatt_write_descriptor(
|
||||
self,
|
||||
address: int,
|
||||
handle: int,
|
||||
data: bytes,
|
||||
) -> None:
|
||||
self._check_authenticated()
|
||||
|
||||
req = BluetoothGATTWriteDescriptorRequest()
|
||||
req.address = address
|
||||
req.handle = handle
|
||||
req.data = data
|
||||
|
||||
assert self._connection is not None
|
||||
await self._connection.send_message(req)
|
||||
|
||||
async def bluetooth_gatt_start_notify(
|
||||
self,
|
||||
address: int,
|
||||
handle: int,
|
||||
on_bluetooth_gatt_notify: Callable[[int, bytearray], None],
|
||||
) -> Callable[[], Coroutine[Any, Any, None]]:
|
||||
self._check_authenticated()
|
||||
|
||||
def on_msg(msg: message.Message) -> None:
|
||||
if isinstance(msg, BluetoothGATTNotifyDataResponse):
|
||||
notify = BluetoothGATTRead.from_pb(msg)
|
||||
if address == notify.address and handle == notify.handle:
|
||||
on_bluetooth_gatt_notify(handle, bytearray(notify.data))
|
||||
|
||||
assert self._connection is not None
|
||||
await self._connection.send_message_callback_response(
|
||||
BluetoothGATTNotifyRequest(address=address, handle=handle, enable=True),
|
||||
on_msg,
|
||||
)
|
||||
|
||||
async def stop_notify() -> None:
|
||||
assert self._connection is not None
|
||||
self._connection.remove_message_callback(on_msg)
|
||||
|
||||
self._check_authenticated()
|
||||
|
||||
await self._connection.send_message(
|
||||
BluetoothGATTNotifyRequest(address=address, handle=handle, enable=False)
|
||||
)
|
||||
|
||||
return stop_notify
|
||||
|
||||
async def subscribe_home_assistant_states(
|
||||
self, on_state_sub: Callable[[str, Optional[str]], None]
|
||||
) -> None:
|
||||
|
@ -362,6 +362,10 @@ class APIConnection:
|
||||
await self._report_fatal_error(err)
|
||||
raise
|
||||
|
||||
def remove_message_callback(self, on_message: Callable[[Any], None]) -> None:
|
||||
"""Remove a message callback."""
|
||||
self._message_handlers.remove(on_message)
|
||||
|
||||
async def send_message_callback_response(
|
||||
self, send_msg: message.Message, on_message: Callable[[Any], None]
|
||||
) -> None:
|
||||
|
@ -1,5 +1,18 @@
|
||||
from .api_pb2 import ( # type: ignore
|
||||
BinarySensorStateResponse,
|
||||
BluetoothConnectionsFreeResponse,
|
||||
BluetoothDeviceConnectionResponse,
|
||||
BluetoothDeviceRequest,
|
||||
BluetoothGATTGetServicesDoneResponse,
|
||||
BluetoothGATTGetServicesRequest,
|
||||
BluetoothGATTGetServicesResponse,
|
||||
BluetoothGATTNotifyDataResponse,
|
||||
BluetoothGATTNotifyRequest,
|
||||
BluetoothGATTReadDescriptorRequest,
|
||||
BluetoothGATTReadRequest,
|
||||
BluetoothGATTReadResponse,
|
||||
BluetoothGATTWriteDescriptorRequest,
|
||||
BluetoothGATTWriteRequest,
|
||||
BluetoothLEAdvertisementResponse,
|
||||
ButtonCommandRequest,
|
||||
CameraImageRequest,
|
||||
@ -56,6 +69,7 @@ from .api_pb2 import ( # type: ignore
|
||||
SensorStateResponse,
|
||||
SirenCommandRequest,
|
||||
SirenStateResponse,
|
||||
SubscribeBluetoothConnectionsFreeRequest,
|
||||
SubscribeBluetoothLEAdvertisementsRequest,
|
||||
SubscribeHomeassistantServicesRequest,
|
||||
SubscribeHomeAssistantStateResponse,
|
||||
@ -193,4 +207,18 @@ MESSAGE_TYPE_TO_PROTO = {
|
||||
65: MediaPlayerCommandRequest,
|
||||
66: SubscribeBluetoothLEAdvertisementsRequest,
|
||||
67: BluetoothLEAdvertisementResponse,
|
||||
68: BluetoothDeviceRequest,
|
||||
69: BluetoothDeviceConnectionResponse,
|
||||
70: BluetoothGATTGetServicesRequest,
|
||||
71: BluetoothGATTGetServicesResponse,
|
||||
72: BluetoothGATTGetServicesDoneResponse,
|
||||
73: BluetoothGATTReadRequest,
|
||||
74: BluetoothGATTReadResponse,
|
||||
75: BluetoothGATTWriteRequest,
|
||||
76: BluetoothGATTReadDescriptorRequest,
|
||||
77: BluetoothGATTWriteDescriptorRequest,
|
||||
78: BluetoothGATTNotifyRequest,
|
||||
79: BluetoothGATTNotifyDataResponse,
|
||||
80: SubscribeBluetoothConnectionsFreeRequest,
|
||||
81: BluetoothConnectionsFreeResponse,
|
||||
}
|
||||
|
@ -759,7 +759,7 @@ def _long_uuid(uuid: str) -> str:
|
||||
"""Convert a UUID to a long UUID."""
|
||||
return (
|
||||
f"0000{uuid[2:].lower()}-0000-1000-8000-00805f9b34fb" if len(uuid) < 8 else uuid
|
||||
)
|
||||
).lower()
|
||||
|
||||
|
||||
def _convert_bluetooth_le_service_uuids(value: List[str]) -> List[str]:
|
||||
@ -771,6 +771,7 @@ def _convert_bluetooth_le_service_data(
|
||||
) -> Dict[str, bytes]:
|
||||
if isinstance(value, dict):
|
||||
return value
|
||||
|
||||
return {_long_uuid(v.uuid): bytes(v.data) for v in value} # type: ignore
|
||||
|
||||
|
||||
@ -799,6 +800,100 @@ class BluetoothLEAdvertisement(APIModelBase):
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class BluetoothDeviceConnection(APIModelBase):
|
||||
address: int = 0
|
||||
connected: bool = False
|
||||
mtu: int = 0
|
||||
error: int = 0
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class BluetoothGATTRead(APIModelBase):
|
||||
address: int = 0
|
||||
handle: int = 0
|
||||
|
||||
data: bytes = b""
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class BluetoothGATTDescriptor(APIModelBase):
|
||||
uuid: str = converter_field(default="", converter=_long_uuid)
|
||||
handle: int = 0
|
||||
description: str = ""
|
||||
|
||||
@classmethod
|
||||
def convert_list(cls, value: List[Any]) -> List["BluetoothGATTDescriptor"]:
|
||||
ret = []
|
||||
for x in value:
|
||||
if isinstance(x, dict):
|
||||
ret.append(cls.from_dict(x))
|
||||
else:
|
||||
ret.append(cls.from_pb(x))
|
||||
return ret
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class BluetoothGATTCharacteristic(APIModelBase):
|
||||
uuid: str = converter_field(default="", converter=_long_uuid)
|
||||
handle: int = 0
|
||||
properties: int = 0
|
||||
|
||||
descriptors: List[BluetoothGATTDescriptor] = converter_field(
|
||||
default_factory=list, converter=BluetoothGATTDescriptor.convert_list
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def convert_list(cls, value: List[Any]) -> List["BluetoothGATTCharacteristic"]:
|
||||
ret = []
|
||||
for x in value:
|
||||
if isinstance(x, dict):
|
||||
ret.append(cls.from_dict(x))
|
||||
else:
|
||||
ret.append(cls.from_pb(x))
|
||||
return ret
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class BluetoothGATTService(APIModelBase):
|
||||
uuid: str = converter_field(default="", converter=_long_uuid)
|
||||
handle: int = 0
|
||||
characteristics: List[BluetoothGATTCharacteristic] = converter_field(
|
||||
default_factory=list, converter=BluetoothGATTCharacteristic.convert_list
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def convert_list(cls, value: List[Any]) -> List["BluetoothGATTService"]:
|
||||
ret = []
|
||||
for x in value:
|
||||
if isinstance(x, dict):
|
||||
ret.append(cls.from_dict(x))
|
||||
else:
|
||||
ret.append(cls.from_pb(x))
|
||||
return ret
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class BluetoothGATTServices(APIModelBase):
|
||||
address: int = 0
|
||||
services: List[BluetoothGATTService] = converter_field(
|
||||
default_factory=list, converter=BluetoothGATTService.convert_list
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class BluetoothConnectionsFree(APIModelBase):
|
||||
free: int = 0
|
||||
limit: int = 0
|
||||
|
||||
|
||||
class BluetoothDeviceRequestType(APIIntEnum):
|
||||
CONNECT = 0
|
||||
DISCONNECT = 1
|
||||
PAIR = 2
|
||||
UNPAIR = 3
|
||||
|
||||
|
||||
class LogLevel(APIIntEnum):
|
||||
LOG_LEVEL_NONE = 0
|
||||
LOG_LEVEL_ERROR = 1
|
||||
|
Loading…
Reference in New Issue
Block a user