Add select entities (#75)

This commit is contained in:
Jesse Hills 2021-07-27 06:51:12 +12:00 committed by GitHub
parent 4fe818b95c
commit 551a1acd0d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 311 additions and 31 deletions

View File

@ -39,6 +39,7 @@ service APIConnection {
rpc camera_image (CameraImageRequest) returns (void) {} rpc camera_image (CameraImageRequest) returns (void) {}
rpc climate_command (ClimateCommandRequest) returns (void) {} rpc climate_command (ClimateCommandRequest) returns (void) {}
rpc number_command (NumberCommandRequest) returns (void) {} rpc number_command (NumberCommandRequest) returns (void) {}
rpc select_command (SelectCommandRequest) returns (void) {}
} }
@ -841,3 +842,39 @@ message NumberCommandRequest {
fixed32 key = 1; fixed32 key = 1;
float state = 2; float state = 2;
} }
// ==================== SELECT ====================
message ListEntitiesSelectResponse {
option (id) = 52;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_SELECT";
string object_id = 1;
fixed32 key = 2;
string name = 3;
string unique_id = 4;
string icon = 5;
repeated string options = 6;
}
message SelectStateResponse {
option (id) = 53;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_SELECT";
option (no_delay) = true;
fixed32 key = 1;
string state = 2;
// If the select does not have a valid state yet.
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
bool missing_state = 3;
}
message SelectCommandRequest {
option (id) = 54;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_SELECT";
option (no_delay) = true;
fixed32 key = 1;
string state = 2;
}

File diff suppressed because one or more lines are too long

View File

@ -42,12 +42,15 @@ from .api_pb2 import ( # type: ignore
ListEntitiesLightResponse, ListEntitiesLightResponse,
ListEntitiesNumberResponse, ListEntitiesNumberResponse,
ListEntitiesRequest, ListEntitiesRequest,
ListEntitiesSelectResponse,
ListEntitiesSensorResponse, ListEntitiesSensorResponse,
ListEntitiesServicesResponse, ListEntitiesServicesResponse,
ListEntitiesSwitchResponse, ListEntitiesSwitchResponse,
ListEntitiesTextSensorResponse, ListEntitiesTextSensorResponse,
NumberCommandRequest, NumberCommandRequest,
NumberStateResponse, NumberStateResponse,
SelectCommandRequest,
SelectStateResponse,
SensorStateResponse, SensorStateResponse,
SubscribeHomeassistantServicesRequest, SubscribeHomeassistantServicesRequest,
SubscribeHomeAssistantStateResponse, SubscribeHomeAssistantStateResponse,
@ -90,6 +93,8 @@ from .model import (
LogLevel, LogLevel,
NumberInfo, NumberInfo,
NumberState, NumberState,
SelectInfo,
SelectState,
SensorInfo, SensorInfo,
SensorState, SensorState,
SwitchInfo, SwitchInfo,
@ -219,6 +224,7 @@ class APIClient:
ListEntitiesFanResponse: FanInfo, ListEntitiesFanResponse: FanInfo,
ListEntitiesLightResponse: LightInfo, ListEntitiesLightResponse: LightInfo,
ListEntitiesNumberResponse: NumberInfo, ListEntitiesNumberResponse: NumberInfo,
ListEntitiesSelectResponse: SelectInfo,
ListEntitiesSensorResponse: SensorInfo, ListEntitiesSensorResponse: SensorInfo,
ListEntitiesSwitchResponse: SwitchInfo, ListEntitiesSwitchResponse: SwitchInfo,
ListEntitiesTextSensorResponse: TextSensorInfo, ListEntitiesTextSensorResponse: TextSensorInfo,
@ -262,6 +268,7 @@ class APIClient:
FanStateResponse: FanState, FanStateResponse: FanState,
LightStateResponse: LightState, LightStateResponse: LightState,
NumberStateResponse: NumberState, NumberStateResponse: NumberState,
SelectStateResponse: SelectState,
SensorStateResponse: SensorState, SensorStateResponse: SensorState,
SwitchStateResponse: SwitchState, SwitchStateResponse: SwitchState,
TextSensorStateResponse: TextSensorState, TextSensorStateResponse: TextSensorState,
@ -533,6 +540,15 @@ class APIClient:
assert self._connection is not None assert self._connection is not None
await self._connection.send_message(req) await self._connection.send_message(req)
async def select_command(self, key: int, state: str) -> None:
self._check_authenticated()
req = SelectCommandRequest()
req.key = key
req.state = state
assert self._connection is not None
await self._connection.send_message(req)
async def execute_service( async def execute_service(
self, service: UserService, data: ExecuteServiceDataType self, service: UserService, data: ExecuteServiceDataType
) -> None: ) -> None:

View File

@ -32,6 +32,7 @@ from .api_pb2 import ( # type: ignore
ListEntitiesLightResponse, ListEntitiesLightResponse,
ListEntitiesNumberResponse, ListEntitiesNumberResponse,
ListEntitiesRequest, ListEntitiesRequest,
ListEntitiesSelectResponse,
ListEntitiesSensorResponse, ListEntitiesSensorResponse,
ListEntitiesServicesResponse, ListEntitiesServicesResponse,
ListEntitiesSwitchResponse, ListEntitiesSwitchResponse,
@ -40,6 +41,8 @@ from .api_pb2 import ( # type: ignore
NumberStateResponse, NumberStateResponse,
PingRequest, PingRequest,
PingResponse, PingResponse,
SelectCommandRequest,
SelectStateResponse,
SensorStateResponse, SensorStateResponse,
SubscribeHomeassistantServicesRequest, SubscribeHomeassistantServicesRequest,
SubscribeHomeAssistantStateResponse, SubscribeHomeAssistantStateResponse,
@ -109,4 +112,7 @@ MESSAGE_TYPE_TO_PROTO = {
49: ListEntitiesNumberResponse, 49: ListEntitiesNumberResponse,
50: NumberStateResponse, 50: NumberStateResponse,
51: NumberCommandRequest, 51: NumberCommandRequest,
52: ListEntitiesSelectResponse,
53: SelectStateResponse,
54: SelectCommandRequest,
} }

View File

@ -432,6 +432,19 @@ class NumberState(EntityState):
missing_state: bool = False missing_state: bool = False
# ==================== SELECT ====================
@dataclass(frozen=True)
class SelectInfo(EntityInfo):
icon: str = ""
options: List[str] = converter_field(default_factory=list, converter=list)
@dataclass(frozen=True)
class SelectState(EntityState):
state: str = ""
missing_state: bool = False
COMPONENT_TYPE_TO_INFO: Dict[str, Type[EntityInfo]] = { COMPONENT_TYPE_TO_INFO: Dict[str, Type[EntityInfo]] = {
"binary_sensor": BinarySensorInfo, "binary_sensor": BinarySensorInfo,
"cover": CoverInfo, "cover": CoverInfo,
@ -443,6 +456,7 @@ COMPONENT_TYPE_TO_INFO: Dict[str, Type[EntityInfo]] = {
"camera": CameraInfo, "camera": CameraInfo,
"climate": ClimateInfo, "climate": ClimateInfo,
"number": NumberInfo, "number": NumberInfo,
"select": SelectInfo,
} }

View File

@ -17,6 +17,7 @@ from aioesphomeapi.api_pb2 import (
ListEntitiesDoneResponse, ListEntitiesDoneResponse,
ListEntitiesServicesResponse, ListEntitiesServicesResponse,
NumberCommandRequest, NumberCommandRequest,
SelectCommandRequest,
SwitchCommandRequest, SwitchCommandRequest,
) )
from aioesphomeapi.client import APIClient from aioesphomeapi.client import APIClient
@ -356,6 +357,21 @@ async def test_number_command(auth_client, cmd, req):
send.assert_called_once_with(NumberCommandRequest(**req)) send.assert_called_once_with(NumberCommandRequest(**req))
@pytest.mark.asyncio
@pytest.mark.parametrize(
"cmd, req",
[
(dict(key=1, state="One"), dict(key=1, state="One")),
(dict(key=1, state="Two"), dict(key=1, state="Two")),
],
)
async def test_select_command(auth_client, cmd, req):
send = patch_send(auth_client)
await auth_client.select_command(**cmd)
send.assert_called_once_with(SelectCommandRequest(**req))
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_execute_service(auth_client): async def test_execute_service(auth_client):
send = patch_send(auth_client) send = patch_send(auth_client)

View File

@ -18,12 +18,14 @@ from aioesphomeapi.api_pb2 import (
ListEntitiesFanResponse, ListEntitiesFanResponse,
ListEntitiesLightResponse, ListEntitiesLightResponse,
ListEntitiesNumberResponse, ListEntitiesNumberResponse,
ListEntitiesSelectResponse,
ListEntitiesSensorResponse, ListEntitiesSensorResponse,
ListEntitiesServicesArgument, ListEntitiesServicesArgument,
ListEntitiesServicesResponse, ListEntitiesServicesResponse,
ListEntitiesSwitchResponse, ListEntitiesSwitchResponse,
ListEntitiesTextSensorResponse, ListEntitiesTextSensorResponse,
NumberStateResponse, NumberStateResponse,
SelectStateResponse,
SensorStateResponse, SensorStateResponse,
ServiceArgType, ServiceArgType,
SwitchStateResponse, SwitchStateResponse,
@ -49,6 +51,8 @@ from aioesphomeapi.model import (
LightState, LightState,
NumberInfo, NumberInfo,
NumberState, NumberState,
SelectInfo,
SelectState,
SensorInfo, SensorInfo,
SensorState, SensorState,
SwitchInfo, SwitchInfo,
@ -208,6 +212,8 @@ def test_api_version_ord():
(ClimateState, ClimateStateResponse), (ClimateState, ClimateStateResponse),
(NumberInfo, ListEntitiesNumberResponse), (NumberInfo, ListEntitiesNumberResponse),
(NumberState, NumberStateResponse), (NumberState, NumberStateResponse),
(SelectInfo, ListEntitiesSelectResponse),
(SelectState, SelectStateResponse),
(HomeassistantServiceCall, HomeassistantServiceResponse), (HomeassistantServiceCall, HomeassistantServiceResponse),
(UserServiceArg, ListEntitiesServicesArgument), (UserServiceArg, ListEntitiesServicesArgument),
(UserService, ListEntitiesServicesResponse), (UserService, ListEntitiesServicesResponse),