mirror of
https://github.com/esphome/aioesphomeapi.git
synced 2024-12-27 17:37:39 +01:00
396 lines
11 KiB
Python
396 lines
11 KiB
Python
from __future__ import annotations
|
|
|
|
import re
|
|
|
|
from aioesphomeapi.model import BluetoothGATTError
|
|
|
|
from .api_pb2 import ( # type: ignore
|
|
AlarmControlPanelCommandRequest,
|
|
AlarmControlPanelStateResponse,
|
|
BinarySensorStateResponse,
|
|
BluetoothConnectionsFreeResponse,
|
|
BluetoothDeviceClearCacheResponse,
|
|
BluetoothDeviceConnectionResponse,
|
|
BluetoothDevicePairingResponse,
|
|
BluetoothDeviceRequest,
|
|
BluetoothDeviceUnpairingResponse,
|
|
BluetoothGATTErrorResponse,
|
|
BluetoothGATTGetServicesDoneResponse,
|
|
BluetoothGATTGetServicesRequest,
|
|
BluetoothGATTGetServicesResponse,
|
|
BluetoothGATTNotifyDataResponse,
|
|
BluetoothGATTNotifyRequest,
|
|
BluetoothGATTNotifyResponse,
|
|
BluetoothGATTReadDescriptorRequest,
|
|
BluetoothGATTReadRequest,
|
|
BluetoothGATTReadResponse,
|
|
BluetoothGATTWriteDescriptorRequest,
|
|
BluetoothGATTWriteRequest,
|
|
BluetoothGATTWriteResponse,
|
|
BluetoothLEAdvertisementResponse,
|
|
BluetoothLERawAdvertisementsResponse,
|
|
ButtonCommandRequest,
|
|
CameraImageRequest,
|
|
CameraImageResponse,
|
|
ClimateCommandRequest,
|
|
ClimateStateResponse,
|
|
ConnectRequest,
|
|
ConnectResponse,
|
|
CoverCommandRequest,
|
|
CoverStateResponse,
|
|
DateCommandRequest,
|
|
DateStateResponse,
|
|
DateTimeCommandRequest,
|
|
DateTimeStateResponse,
|
|
DeviceInfoRequest,
|
|
DeviceInfoResponse,
|
|
DisconnectRequest,
|
|
DisconnectResponse,
|
|
EventResponse,
|
|
ExecuteServiceRequest,
|
|
FanCommandRequest,
|
|
FanStateResponse,
|
|
GetTimeRequest,
|
|
GetTimeResponse,
|
|
HelloRequest,
|
|
HelloResponse,
|
|
HomeassistantServiceResponse,
|
|
HomeAssistantStateResponse,
|
|
LightCommandRequest,
|
|
LightStateResponse,
|
|
ListEntitiesAlarmControlPanelResponse,
|
|
ListEntitiesBinarySensorResponse,
|
|
ListEntitiesButtonResponse,
|
|
ListEntitiesCameraResponse,
|
|
ListEntitiesClimateResponse,
|
|
ListEntitiesCoverResponse,
|
|
ListEntitiesDateResponse,
|
|
ListEntitiesDateTimeResponse,
|
|
ListEntitiesDoneResponse,
|
|
ListEntitiesEventResponse,
|
|
ListEntitiesFanResponse,
|
|
ListEntitiesLightResponse,
|
|
ListEntitiesLockResponse,
|
|
ListEntitiesMediaPlayerResponse,
|
|
ListEntitiesNumberResponse,
|
|
ListEntitiesRequest,
|
|
ListEntitiesSelectResponse,
|
|
ListEntitiesSensorResponse,
|
|
ListEntitiesServicesResponse,
|
|
ListEntitiesSirenResponse,
|
|
ListEntitiesSwitchResponse,
|
|
ListEntitiesTextResponse,
|
|
ListEntitiesTextSensorResponse,
|
|
ListEntitiesTimeResponse,
|
|
ListEntitiesUpdateResponse,
|
|
ListEntitiesValveResponse,
|
|
LockCommandRequest,
|
|
LockStateResponse,
|
|
MediaPlayerCommandRequest,
|
|
MediaPlayerStateResponse,
|
|
NumberCommandRequest,
|
|
NumberStateResponse,
|
|
PingRequest,
|
|
PingResponse,
|
|
SelectCommandRequest,
|
|
SelectStateResponse,
|
|
SensorStateResponse,
|
|
SirenCommandRequest,
|
|
SirenStateResponse,
|
|
SubscribeBluetoothConnectionsFreeRequest,
|
|
SubscribeBluetoothLEAdvertisementsRequest,
|
|
SubscribeHomeassistantServicesRequest,
|
|
SubscribeHomeAssistantStateResponse,
|
|
SubscribeHomeAssistantStatesRequest,
|
|
SubscribeLogsRequest,
|
|
SubscribeLogsResponse,
|
|
SubscribeStatesRequest,
|
|
SubscribeVoiceAssistantRequest,
|
|
SwitchCommandRequest,
|
|
SwitchStateResponse,
|
|
TextCommandRequest,
|
|
TextSensorStateResponse,
|
|
TextStateResponse,
|
|
TimeCommandRequest,
|
|
TimeStateResponse,
|
|
UnsubscribeBluetoothLEAdvertisementsRequest,
|
|
UpdateCommandRequest,
|
|
UpdateStateResponse,
|
|
ValveCommandRequest,
|
|
ValveStateResponse,
|
|
VoiceAssistantAudio,
|
|
VoiceAssistantEventResponse,
|
|
VoiceAssistantRequest,
|
|
VoiceAssistantResponse,
|
|
VoiceAssistantTimerEventResponse,
|
|
)
|
|
|
|
TWO_CHAR = re.compile(r".{2}")
|
|
|
|
# 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",
|
|
}
|
|
|
|
|
|
class APIConnectionError(Exception):
|
|
pass
|
|
|
|
|
|
class APIConnectionCancelledError(APIConnectionError):
|
|
pass
|
|
|
|
|
|
class InvalidAuthAPIError(APIConnectionError):
|
|
pass
|
|
|
|
|
|
class ResolveAPIError(APIConnectionError):
|
|
pass
|
|
|
|
|
|
class ProtocolAPIError(APIConnectionError):
|
|
pass
|
|
|
|
|
|
class RequiresEncryptionAPIError(ProtocolAPIError):
|
|
pass
|
|
|
|
|
|
class SocketAPIError(APIConnectionError):
|
|
pass
|
|
|
|
|
|
class SocketClosedAPIError(SocketAPIError):
|
|
pass
|
|
|
|
|
|
class HandshakeAPIError(APIConnectionError):
|
|
pass
|
|
|
|
|
|
class ConnectionNotEstablishedAPIError(APIConnectionError):
|
|
pass
|
|
|
|
|
|
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:
|
|
super().__init__(f"{msg}: received_name={received_name}")
|
|
self.received_name = received_name
|
|
|
|
|
|
class InvalidEncryptionKeyAPIError(HandshakeAPIError):
|
|
def __init__(
|
|
self, msg: str | None = None, received_name: str | None = None
|
|
) -> None:
|
|
super().__init__(f"{msg}: received_name={received_name}")
|
|
self.received_name = received_name
|
|
|
|
|
|
class PingFailedAPIError(APIConnectionError):
|
|
pass
|
|
|
|
|
|
class TimeoutAPIError(APIConnectionError):
|
|
pass
|
|
|
|
|
|
class ReadFailedAPIError(APIConnectionError):
|
|
pass
|
|
|
|
|
|
class UnhandledAPIConnectionError(APIConnectionError):
|
|
pass
|
|
|
|
|
|
class BluetoothConnectionDroppedError(APIConnectionError):
|
|
"""Raised when a Bluetooth connection is dropped."""
|
|
|
|
|
|
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}"))
|
|
|
|
|
|
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")
|
|
|
|
|
|
class BluetoothGATTAPIError(APIConnectionError):
|
|
def __init__(self, error: BluetoothGATTError) -> None:
|
|
super().__init__(
|
|
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)}"
|
|
)
|
|
self.error = error
|
|
|
|
|
|
MESSAGE_TYPE_TO_PROTO = {
|
|
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,
|
|
49: ListEntitiesNumberResponse,
|
|
50: NumberStateResponse,
|
|
51: NumberCommandRequest,
|
|
52: ListEntitiesSelectResponse,
|
|
53: SelectStateResponse,
|
|
54: SelectCommandRequest,
|
|
55: ListEntitiesSirenResponse,
|
|
56: SirenStateResponse,
|
|
57: SirenCommandRequest,
|
|
58: ListEntitiesLockResponse,
|
|
59: LockStateResponse,
|
|
60: LockCommandRequest,
|
|
61: ListEntitiesButtonResponse,
|
|
62: ButtonCommandRequest,
|
|
63: ListEntitiesMediaPlayerResponse,
|
|
64: MediaPlayerStateResponse,
|
|
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,
|
|
82: BluetoothGATTErrorResponse,
|
|
83: BluetoothGATTWriteResponse,
|
|
84: BluetoothGATTNotifyResponse,
|
|
85: BluetoothDevicePairingResponse,
|
|
86: BluetoothDeviceUnpairingResponse,
|
|
87: UnsubscribeBluetoothLEAdvertisementsRequest,
|
|
88: BluetoothDeviceClearCacheResponse,
|
|
89: SubscribeVoiceAssistantRequest,
|
|
90: VoiceAssistantRequest,
|
|
91: VoiceAssistantResponse,
|
|
92: VoiceAssistantEventResponse,
|
|
93: BluetoothLERawAdvertisementsResponse,
|
|
94: ListEntitiesAlarmControlPanelResponse,
|
|
95: AlarmControlPanelStateResponse,
|
|
96: AlarmControlPanelCommandRequest,
|
|
97: ListEntitiesTextResponse,
|
|
98: TextStateResponse,
|
|
99: TextCommandRequest,
|
|
100: ListEntitiesDateResponse,
|
|
101: DateStateResponse,
|
|
102: DateCommandRequest,
|
|
103: ListEntitiesTimeResponse,
|
|
104: TimeStateResponse,
|
|
105: TimeCommandRequest,
|
|
106: VoiceAssistantAudio,
|
|
107: ListEntitiesEventResponse,
|
|
108: EventResponse,
|
|
109: ListEntitiesValveResponse,
|
|
110: ValveStateResponse,
|
|
111: ValveCommandRequest,
|
|
112: ListEntitiesDateTimeResponse,
|
|
113: DateTimeStateResponse,
|
|
114: DateTimeCommandRequest,
|
|
115: VoiceAssistantTimerEventResponse,
|
|
116: ListEntitiesUpdateResponse,
|
|
117: UpdateStateResponse,
|
|
118: UpdateCommandRequest,
|
|
}
|