2023-07-19 22:33:28 +02:00
|
|
|
from __future__ import annotations
|
|
|
|
|
2022-10-30 23:38:24 +01:00
|
|
|
import re
|
|
|
|
|
|
|
|
from aioesphomeapi.model import BluetoothGATTError
|
|
|
|
|
2021-06-30 17:00:22 +02:00
|
|
|
from .api_pb2 import ( # type: ignore
|
2023-06-12 00:39:49 +02:00
|
|
|
AlarmControlPanelCommandRequest,
|
|
|
|
AlarmControlPanelStateResponse,
|
2021-06-18 17:57:02 +02:00
|
|
|
BinarySensorStateResponse,
|
2022-09-28 18:50:37 +02:00
|
|
|
BluetoothConnectionsFreeResponse,
|
2023-03-26 23:47:21 +02:00
|
|
|
BluetoothDeviceClearCacheResponse,
|
2022-09-28 18:50:37 +02:00
|
|
|
BluetoothDeviceConnectionResponse,
|
2023-03-06 19:07:58 +01:00
|
|
|
BluetoothDevicePairingResponse,
|
2022-09-28 18:50:37 +02:00
|
|
|
BluetoothDeviceRequest,
|
2023-03-06 19:07:58 +01:00
|
|
|
BluetoothDeviceUnpairingResponse,
|
2022-10-30 23:38:24 +01:00
|
|
|
BluetoothGATTErrorResponse,
|
2022-09-28 18:50:37 +02:00
|
|
|
BluetoothGATTGetServicesDoneResponse,
|
|
|
|
BluetoothGATTGetServicesRequest,
|
|
|
|
BluetoothGATTGetServicesResponse,
|
|
|
|
BluetoothGATTNotifyDataResponse,
|
|
|
|
BluetoothGATTNotifyRequest,
|
2022-10-30 23:38:24 +01:00
|
|
|
BluetoothGATTNotifyResponse,
|
2022-09-28 18:50:37 +02:00
|
|
|
BluetoothGATTReadDescriptorRequest,
|
|
|
|
BluetoothGATTReadRequest,
|
|
|
|
BluetoothGATTReadResponse,
|
|
|
|
BluetoothGATTWriteDescriptorRequest,
|
|
|
|
BluetoothGATTWriteRequest,
|
2022-10-30 23:38:24 +01:00
|
|
|
BluetoothGATTWriteResponse,
|
2022-08-22 05:27:46 +02:00
|
|
|
BluetoothLEAdvertisementResponse,
|
2023-06-07 07:42:57 +02:00
|
|
|
BluetoothLERawAdvertisementsResponse,
|
2021-11-29 01:59:23 +01:00
|
|
|
ButtonCommandRequest,
|
2021-06-18 17:57:02 +02:00
|
|
|
CameraImageRequest,
|
|
|
|
CameraImageResponse,
|
|
|
|
ClimateCommandRequest,
|
|
|
|
ClimateStateResponse,
|
|
|
|
ConnectRequest,
|
|
|
|
ConnectResponse,
|
|
|
|
CoverCommandRequest,
|
|
|
|
CoverStateResponse,
|
|
|
|
DeviceInfoRequest,
|
|
|
|
DeviceInfoResponse,
|
|
|
|
DisconnectRequest,
|
|
|
|
DisconnectResponse,
|
|
|
|
ExecuteServiceRequest,
|
|
|
|
FanCommandRequest,
|
|
|
|
FanStateResponse,
|
|
|
|
GetTimeRequest,
|
|
|
|
GetTimeResponse,
|
|
|
|
HelloRequest,
|
|
|
|
HelloResponse,
|
|
|
|
HomeassistantServiceResponse,
|
|
|
|
HomeAssistantStateResponse,
|
|
|
|
LightCommandRequest,
|
|
|
|
LightStateResponse,
|
2023-06-12 00:39:49 +02:00
|
|
|
ListEntitiesAlarmControlPanelResponse,
|
2021-06-18 17:57:02 +02:00
|
|
|
ListEntitiesBinarySensorResponse,
|
2021-11-29 01:59:23 +01:00
|
|
|
ListEntitiesButtonResponse,
|
2021-06-18 17:57:02 +02:00
|
|
|
ListEntitiesCameraResponse,
|
|
|
|
ListEntitiesClimateResponse,
|
|
|
|
ListEntitiesCoverResponse,
|
|
|
|
ListEntitiesDoneResponse,
|
|
|
|
ListEntitiesFanResponse,
|
|
|
|
ListEntitiesLightResponse,
|
2022-01-11 02:29:19 +01:00
|
|
|
ListEntitiesLockResponse,
|
2022-05-18 03:28:40 +02:00
|
|
|
ListEntitiesMediaPlayerResponse,
|
2021-06-29 12:42:38 +02:00
|
|
|
ListEntitiesNumberResponse,
|
2021-06-18 17:57:02 +02:00
|
|
|
ListEntitiesRequest,
|
2021-07-26 20:51:12 +02:00
|
|
|
ListEntitiesSelectResponse,
|
2021-06-18 17:57:02 +02:00
|
|
|
ListEntitiesSensorResponse,
|
|
|
|
ListEntitiesServicesResponse,
|
2021-09-09 03:11:51 +02:00
|
|
|
ListEntitiesSirenResponse,
|
2021-06-18 17:57:02 +02:00
|
|
|
ListEntitiesSwitchResponse,
|
2023-10-25 04:35:04 +02:00
|
|
|
ListEntitiesTextResponse,
|
2021-06-18 17:57:02 +02:00
|
|
|
ListEntitiesTextSensorResponse,
|
2022-01-11 02:29:19 +01:00
|
|
|
LockCommandRequest,
|
|
|
|
LockStateResponse,
|
2022-05-18 03:28:40 +02:00
|
|
|
MediaPlayerCommandRequest,
|
|
|
|
MediaPlayerStateResponse,
|
2021-06-29 12:42:38 +02:00
|
|
|
NumberCommandRequest,
|
|
|
|
NumberStateResponse,
|
2021-06-18 17:57:02 +02:00
|
|
|
PingRequest,
|
|
|
|
PingResponse,
|
2021-07-26 20:51:12 +02:00
|
|
|
SelectCommandRequest,
|
|
|
|
SelectStateResponse,
|
2021-06-18 17:57:02 +02:00
|
|
|
SensorStateResponse,
|
2021-09-09 03:11:51 +02:00
|
|
|
SirenCommandRequest,
|
|
|
|
SirenStateResponse,
|
2022-09-28 18:50:37 +02:00
|
|
|
SubscribeBluetoothConnectionsFreeRequest,
|
2022-08-22 05:27:46 +02:00
|
|
|
SubscribeBluetoothLEAdvertisementsRequest,
|
2021-06-18 17:57:02 +02:00
|
|
|
SubscribeHomeassistantServicesRequest,
|
|
|
|
SubscribeHomeAssistantStateResponse,
|
|
|
|
SubscribeHomeAssistantStatesRequest,
|
|
|
|
SubscribeLogsRequest,
|
|
|
|
SubscribeLogsResponse,
|
|
|
|
SubscribeStatesRequest,
|
2023-04-11 05:57:35 +02:00
|
|
|
SubscribeVoiceAssistantRequest,
|
2021-06-18 17:57:02 +02:00
|
|
|
SwitchCommandRequest,
|
|
|
|
SwitchStateResponse,
|
2023-10-25 04:35:04 +02:00
|
|
|
TextCommandRequest,
|
2021-06-18 17:57:02 +02:00
|
|
|
TextSensorStateResponse,
|
2023-10-25 04:35:04 +02:00
|
|
|
TextStateResponse,
|
2023-03-26 22:35:11 +02:00
|
|
|
UnsubscribeBluetoothLEAdvertisementsRequest,
|
2023-04-11 05:57:35 +02:00
|
|
|
VoiceAssistantEventResponse,
|
|
|
|
VoiceAssistantRequest,
|
|
|
|
VoiceAssistantResponse,
|
2021-06-18 17:57:02 +02:00
|
|
|
)
|
2019-04-07 19:03:26 +02:00
|
|
|
|
2022-10-30 23:38:24 +01:00
|
|
|
TWO_CHAR = re.compile(r".{2}")
|
|
|
|
|
2022-10-31 21:32:40 +01:00
|
|
|
# Taken from esp_gatt_status_t in esp_gatt_defs.h
|
|
|
|
ESPHOME_GATT_ERRORS = {
|
|
|
|
-1: "Not connected", # Custom ESPHome error
|
|
|
|
1: "Invalid handle",
|
|
|
|
2: "Read not permitted",
|
|
|
|
3: "Write not permitted",
|
|
|
|
4: "Invalid PDU",
|
|
|
|
5: "Insufficient authentication",
|
|
|
|
6: "Request not supported",
|
|
|
|
7: "Invalid offset",
|
|
|
|
8: "Insufficient authorization",
|
|
|
|
9: "Prepare queue full",
|
|
|
|
10: "Attribute not found",
|
|
|
|
11: "Attribute not long",
|
|
|
|
12: "Insufficient key size",
|
|
|
|
13: "Invalid attribute length",
|
|
|
|
14: "Unlikely error",
|
|
|
|
15: "Insufficient encryption",
|
|
|
|
16: "Unsupported group type",
|
|
|
|
17: "Insufficient resources",
|
|
|
|
128: "Application error",
|
|
|
|
129: "Internal error",
|
|
|
|
130: "Wrong state",
|
|
|
|
131: "Database full",
|
|
|
|
132: "Busy",
|
|
|
|
133: "Error",
|
|
|
|
134: "Command started",
|
|
|
|
135: "Illegal parameter",
|
|
|
|
136: "Pending",
|
|
|
|
137: "Auth fail",
|
|
|
|
138: "More",
|
|
|
|
139: "Invalid configuration",
|
|
|
|
140: "Service started",
|
|
|
|
141: "Encrypted no mitm",
|
|
|
|
142: "Not encrypted",
|
|
|
|
143: "Congested",
|
|
|
|
144: "Duplicate registration",
|
|
|
|
145: "Already open",
|
|
|
|
146: "Cancel",
|
|
|
|
224: "Stack RSP",
|
|
|
|
225: "App RSP",
|
|
|
|
239: "Unknown error",
|
|
|
|
253: "CCC config error",
|
|
|
|
254: "Procedure already in progress",
|
|
|
|
255: "Out of range",
|
|
|
|
}
|
|
|
|
|
2019-04-07 19:03:26 +02:00
|
|
|
|
|
|
|
class APIConnectionError(Exception):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
2023-11-25 16:33:43 +01:00
|
|
|
class APIConnectionCancelledError(APIConnectionError):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
2021-09-14 12:44:52 +02:00
|
|
|
class InvalidAuthAPIError(APIConnectionError):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
class ResolveAPIError(APIConnectionError):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
class ProtocolAPIError(APIConnectionError):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
class RequiresEncryptionAPIError(ProtocolAPIError):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
class SocketAPIError(APIConnectionError):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
2021-10-04 12:12:43 +02:00
|
|
|
class SocketClosedAPIError(SocketAPIError):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
2021-09-14 12:44:52 +02:00
|
|
|
class HandshakeAPIError(APIConnectionError):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
2023-06-24 17:47:24 +02:00
|
|
|
class ConnectionNotEstablishedAPIError(APIConnectionError):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
2022-01-20 12:03:36 +01:00
|
|
|
class BadNameAPIError(APIConnectionError):
|
|
|
|
"""Raised when a name received from the remote but does not much the expected name."""
|
|
|
|
|
|
|
|
def __init__(self, msg: str, received_name: str) -> None:
|
2023-07-01 18:12:38 +02:00
|
|
|
super().__init__(f"{msg}: received_name={received_name}")
|
2022-01-20 12:03:36 +01:00
|
|
|
self.received_name = received_name
|
|
|
|
|
|
|
|
|
2021-09-14 12:44:52 +02:00
|
|
|
class InvalidEncryptionKeyAPIError(HandshakeAPIError):
|
2023-07-01 18:12:38 +02:00
|
|
|
def __init__(
|
2023-07-19 22:33:28 +02:00
|
|
|
self, msg: str | None = None, received_name: str | None = None
|
2023-07-01 18:12:38 +02:00
|
|
|
) -> None:
|
|
|
|
super().__init__(f"{msg}: received_name={received_name}")
|
|
|
|
self.received_name = received_name
|
2021-09-14 12:44:52 +02:00
|
|
|
|
|
|
|
|
2021-10-04 12:12:43 +02:00
|
|
|
class PingFailedAPIError(APIConnectionError):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
class TimeoutAPIError(APIConnectionError):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
class ReadFailedAPIError(APIConnectionError):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
2023-10-15 04:03:12 +02:00
|
|
|
class UnhandledAPIConnectionError(APIConnectionError):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
2022-10-30 23:38:24 +01:00
|
|
|
def to_human_readable_address(address: int) -> str:
|
|
|
|
"""Convert a MAC address to a human readable format."""
|
|
|
|
return ":".join(TWO_CHAR.findall(f"{address:012X}"))
|
|
|
|
|
|
|
|
|
2022-10-31 21:32:40 +01:00
|
|
|
def to_human_readable_gatt_error(error: int) -> str:
|
|
|
|
"""Convert a GATT error to a human readable format."""
|
|
|
|
return ESPHOME_GATT_ERRORS.get(error, "Unknown error")
|
|
|
|
|
|
|
|
|
2022-10-30 23:38:24 +01:00
|
|
|
class BluetoothGATTAPIError(APIConnectionError):
|
|
|
|
def __init__(self, error: BluetoothGATTError) -> None:
|
|
|
|
super().__init__(
|
2022-10-31 21:32:40 +01:00
|
|
|
f"Bluetooth GATT Error "
|
|
|
|
f"address={to_human_readable_address(error.address)} "
|
|
|
|
f"handle={error.handle} "
|
|
|
|
f"error={error.error} "
|
|
|
|
f"description={to_human_readable_gatt_error(error.error)}"
|
2022-10-30 23:38:24 +01:00
|
|
|
)
|
|
|
|
self.error = error
|
|
|
|
|
|
|
|
|
2019-04-07 19:03:26 +02:00
|
|
|
MESSAGE_TYPE_TO_PROTO = {
|
2021-06-18 17:57:02 +02:00
|
|
|
1: HelloRequest,
|
|
|
|
2: HelloResponse,
|
|
|
|
3: ConnectRequest,
|
|
|
|
4: ConnectResponse,
|
|
|
|
5: DisconnectRequest,
|
|
|
|
6: DisconnectResponse,
|
|
|
|
7: PingRequest,
|
|
|
|
8: PingResponse,
|
|
|
|
9: DeviceInfoRequest,
|
|
|
|
10: DeviceInfoResponse,
|
|
|
|
11: ListEntitiesRequest,
|
|
|
|
12: ListEntitiesBinarySensorResponse,
|
|
|
|
13: ListEntitiesCoverResponse,
|
|
|
|
14: ListEntitiesFanResponse,
|
|
|
|
15: ListEntitiesLightResponse,
|
|
|
|
16: ListEntitiesSensorResponse,
|
|
|
|
17: ListEntitiesSwitchResponse,
|
|
|
|
18: ListEntitiesTextSensorResponse,
|
|
|
|
19: ListEntitiesDoneResponse,
|
|
|
|
20: SubscribeStatesRequest,
|
|
|
|
21: BinarySensorStateResponse,
|
|
|
|
22: CoverStateResponse,
|
|
|
|
23: FanStateResponse,
|
|
|
|
24: LightStateResponse,
|
|
|
|
25: SensorStateResponse,
|
|
|
|
26: SwitchStateResponse,
|
|
|
|
27: TextSensorStateResponse,
|
|
|
|
28: SubscribeLogsRequest,
|
|
|
|
29: SubscribeLogsResponse,
|
|
|
|
30: CoverCommandRequest,
|
|
|
|
31: FanCommandRequest,
|
|
|
|
32: LightCommandRequest,
|
|
|
|
33: SwitchCommandRequest,
|
|
|
|
34: SubscribeHomeassistantServicesRequest,
|
|
|
|
35: HomeassistantServiceResponse,
|
|
|
|
36: GetTimeRequest,
|
|
|
|
37: GetTimeResponse,
|
|
|
|
38: SubscribeHomeAssistantStatesRequest,
|
|
|
|
39: SubscribeHomeAssistantStateResponse,
|
|
|
|
40: HomeAssistantStateResponse,
|
|
|
|
41: ListEntitiesServicesResponse,
|
|
|
|
42: ExecuteServiceRequest,
|
|
|
|
43: ListEntitiesCameraResponse,
|
|
|
|
44: CameraImageResponse,
|
|
|
|
45: CameraImageRequest,
|
|
|
|
46: ListEntitiesClimateResponse,
|
|
|
|
47: ClimateStateResponse,
|
|
|
|
48: ClimateCommandRequest,
|
2021-06-29 12:42:38 +02:00
|
|
|
49: ListEntitiesNumberResponse,
|
|
|
|
50: NumberStateResponse,
|
|
|
|
51: NumberCommandRequest,
|
2021-07-26 20:51:12 +02:00
|
|
|
52: ListEntitiesSelectResponse,
|
|
|
|
53: SelectStateResponse,
|
|
|
|
54: SelectCommandRequest,
|
2021-09-09 03:11:51 +02:00
|
|
|
55: ListEntitiesSirenResponse,
|
|
|
|
56: SirenStateResponse,
|
|
|
|
57: SirenCommandRequest,
|
2022-01-11 02:29:19 +01:00
|
|
|
58: ListEntitiesLockResponse,
|
|
|
|
59: LockStateResponse,
|
|
|
|
60: LockCommandRequest,
|
2021-11-29 01:59:23 +01:00
|
|
|
61: ListEntitiesButtonResponse,
|
|
|
|
62: ButtonCommandRequest,
|
2022-05-18 03:28:40 +02:00
|
|
|
63: ListEntitiesMediaPlayerResponse,
|
|
|
|
64: MediaPlayerStateResponse,
|
|
|
|
65: MediaPlayerCommandRequest,
|
2022-08-22 05:27:46 +02:00
|
|
|
66: SubscribeBluetoothLEAdvertisementsRequest,
|
|
|
|
67: BluetoothLEAdvertisementResponse,
|
2022-09-28 18:50:37 +02:00
|
|
|
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,
|
2022-10-30 23:38:24 +01:00
|
|
|
82: BluetoothGATTErrorResponse,
|
|
|
|
83: BluetoothGATTWriteResponse,
|
|
|
|
84: BluetoothGATTNotifyResponse,
|
2023-03-06 19:07:58 +01:00
|
|
|
85: BluetoothDevicePairingResponse,
|
|
|
|
86: BluetoothDeviceUnpairingResponse,
|
2023-03-26 22:35:11 +02:00
|
|
|
87: UnsubscribeBluetoothLEAdvertisementsRequest,
|
2023-03-26 23:47:21 +02:00
|
|
|
88: BluetoothDeviceClearCacheResponse,
|
2023-04-11 05:57:35 +02:00
|
|
|
89: SubscribeVoiceAssistantRequest,
|
|
|
|
90: VoiceAssistantRequest,
|
|
|
|
91: VoiceAssistantResponse,
|
|
|
|
92: VoiceAssistantEventResponse,
|
2023-06-07 07:42:57 +02:00
|
|
|
93: BluetoothLERawAdvertisementsResponse,
|
2023-06-12 00:39:49 +02:00
|
|
|
94: ListEntitiesAlarmControlPanelResponse,
|
|
|
|
95: AlarmControlPanelStateResponse,
|
|
|
|
96: AlarmControlPanelCommandRequest,
|
2023-10-25 04:35:04 +02:00
|
|
|
97: ListEntitiesTextResponse,
|
|
|
|
98: TextStateResponse,
|
|
|
|
99: TextCommandRequest,
|
2019-04-07 19:03:26 +02:00
|
|
|
}
|