mirror of
https://github.com/esphome/aioesphomeapi.git
synced 2024-12-22 16:48:04 +01:00
Add lock entity (#158)
This commit is contained in:
parent
014d81350a
commit
d0d1e526f5
@ -42,6 +42,7 @@ service APIConnection {
|
|||||||
rpc select_command (SelectCommandRequest) returns (void) {}
|
rpc select_command (SelectCommandRequest) returns (void) {}
|
||||||
rpc siren_command (SirenCommandRequest) returns (void) {}
|
rpc siren_command (SirenCommandRequest) returns (void) {}
|
||||||
rpc button_command (ButtonCommandRequest) returns (void) {}
|
rpc button_command (ButtonCommandRequest) returns (void) {}
|
||||||
|
rpc lock_command (LockCommandRequest) returns (void) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -986,6 +987,58 @@ message SirenCommandRequest {
|
|||||||
float volume = 9;
|
float volume = 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== LOCK ====================
|
||||||
|
enum LockState {
|
||||||
|
LOCK_STATE_NONE = 0;
|
||||||
|
LOCK_STATE_LOCKED = 1;
|
||||||
|
LOCK_STATE_UNLOCKED = 2;
|
||||||
|
LOCK_STATE_JAMMED = 3;
|
||||||
|
LOCK_STATE_LOCKING = 4;
|
||||||
|
LOCK_STATE_UNLOCKING = 5;
|
||||||
|
}
|
||||||
|
enum LockCommand {
|
||||||
|
LOCK_UNLOCK = 0;
|
||||||
|
LOCK_LOCK = 1;
|
||||||
|
LOCK_OPEN = 2;
|
||||||
|
}
|
||||||
|
message ListEntitiesLockResponse {
|
||||||
|
option (id) = 58;
|
||||||
|
option (source) = SOURCE_SERVER;
|
||||||
|
option (ifdef) = "USE_LOCK";
|
||||||
|
|
||||||
|
string object_id = 1;
|
||||||
|
fixed32 key = 2;
|
||||||
|
string name = 3;
|
||||||
|
string unique_id = 4;
|
||||||
|
|
||||||
|
string icon = 5;
|
||||||
|
bool disabled_by_default = 6;
|
||||||
|
EntityCategory entity_category = 7;
|
||||||
|
bool assumed_state = 8;
|
||||||
|
|
||||||
|
bool supports_open = 9;
|
||||||
|
bool requires_code = 10;
|
||||||
|
string code_format = 11;
|
||||||
|
}
|
||||||
|
message LockStateResponse {
|
||||||
|
option (id) = 59;
|
||||||
|
option (source) = SOURCE_SERVER;
|
||||||
|
option (ifdef) = "USE_LOCK";
|
||||||
|
option (no_delay) = true;
|
||||||
|
fixed32 key = 1;
|
||||||
|
LockState state = 2;
|
||||||
|
}
|
||||||
|
message LockCommandRequest {
|
||||||
|
option (id) = 60;
|
||||||
|
option (source) = SOURCE_CLIENT;
|
||||||
|
option (ifdef) = "USE_LOCK";
|
||||||
|
option (no_delay) = true;
|
||||||
|
fixed32 key = 1;
|
||||||
|
LockCommand command = 2;
|
||||||
|
bool has_code = 3;
|
||||||
|
string code = 4;
|
||||||
|
}
|
||||||
|
|
||||||
// ==================== BUTTON ====================
|
// ==================== BUTTON ====================
|
||||||
message ListEntitiesButtonResponse {
|
message ListEntitiesButtonResponse {
|
||||||
option (id) = 61;
|
option (id) = 61;
|
||||||
|
File diff suppressed because one or more lines are too long
@ -41,6 +41,7 @@ from .api_pb2 import ( # type: ignore
|
|||||||
ListEntitiesDoneResponse,
|
ListEntitiesDoneResponse,
|
||||||
ListEntitiesFanResponse,
|
ListEntitiesFanResponse,
|
||||||
ListEntitiesLightResponse,
|
ListEntitiesLightResponse,
|
||||||
|
ListEntitiesLockResponse,
|
||||||
ListEntitiesNumberResponse,
|
ListEntitiesNumberResponse,
|
||||||
ListEntitiesRequest,
|
ListEntitiesRequest,
|
||||||
ListEntitiesSelectResponse,
|
ListEntitiesSelectResponse,
|
||||||
@ -49,6 +50,8 @@ from .api_pb2 import ( # type: ignore
|
|||||||
ListEntitiesSirenResponse,
|
ListEntitiesSirenResponse,
|
||||||
ListEntitiesSwitchResponse,
|
ListEntitiesSwitchResponse,
|
||||||
ListEntitiesTextSensorResponse,
|
ListEntitiesTextSensorResponse,
|
||||||
|
LockCommandRequest,
|
||||||
|
LockStateResponse,
|
||||||
NumberCommandRequest,
|
NumberCommandRequest,
|
||||||
NumberStateResponse,
|
NumberStateResponse,
|
||||||
SelectCommandRequest,
|
SelectCommandRequest,
|
||||||
@ -95,6 +98,9 @@ from .model import (
|
|||||||
LegacyCoverCommand,
|
LegacyCoverCommand,
|
||||||
LightInfo,
|
LightInfo,
|
||||||
LightState,
|
LightState,
|
||||||
|
LockCommand,
|
||||||
|
LockEntityState,
|
||||||
|
LockInfo,
|
||||||
LogLevel,
|
LogLevel,
|
||||||
NumberInfo,
|
NumberInfo,
|
||||||
NumberState,
|
NumberState,
|
||||||
@ -233,6 +239,7 @@ class APIClient:
|
|||||||
ListEntitiesServicesResponse: None,
|
ListEntitiesServicesResponse: None,
|
||||||
ListEntitiesCameraResponse: CameraInfo,
|
ListEntitiesCameraResponse: CameraInfo,
|
||||||
ListEntitiesClimateResponse: ClimateInfo,
|
ListEntitiesClimateResponse: ClimateInfo,
|
||||||
|
ListEntitiesLockResponse: LockInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
def do_append(msg: message.Message) -> bool:
|
def do_append(msg: message.Message) -> bool:
|
||||||
@ -276,6 +283,7 @@ class APIClient:
|
|||||||
SwitchStateResponse: SwitchState,
|
SwitchStateResponse: SwitchState,
|
||||||
TextSensorStateResponse: TextSensorState,
|
TextSensorStateResponse: TextSensorState,
|
||||||
ClimateStateResponse: ClimateState,
|
ClimateStateResponse: ClimateState,
|
||||||
|
LockStateResponse: LockEntityState,
|
||||||
}
|
}
|
||||||
|
|
||||||
image_stream: Dict[int, bytes] = {}
|
image_stream: Dict[int, bytes] = {}
|
||||||
@ -606,6 +614,22 @@ 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 lock_command(
|
||||||
|
self,
|
||||||
|
key: int,
|
||||||
|
command: LockCommand,
|
||||||
|
code: Optional[str] = None,
|
||||||
|
) -> None:
|
||||||
|
self._check_authenticated()
|
||||||
|
|
||||||
|
req = LockCommandRequest()
|
||||||
|
req.key = key
|
||||||
|
req.command = command
|
||||||
|
if code is not None:
|
||||||
|
req.code = code
|
||||||
|
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:
|
||||||
|
@ -32,6 +32,7 @@ from .api_pb2 import ( # type: ignore
|
|||||||
ListEntitiesDoneResponse,
|
ListEntitiesDoneResponse,
|
||||||
ListEntitiesFanResponse,
|
ListEntitiesFanResponse,
|
||||||
ListEntitiesLightResponse,
|
ListEntitiesLightResponse,
|
||||||
|
ListEntitiesLockResponse,
|
||||||
ListEntitiesNumberResponse,
|
ListEntitiesNumberResponse,
|
||||||
ListEntitiesRequest,
|
ListEntitiesRequest,
|
||||||
ListEntitiesSelectResponse,
|
ListEntitiesSelectResponse,
|
||||||
@ -40,6 +41,8 @@ from .api_pb2 import ( # type: ignore
|
|||||||
ListEntitiesSirenResponse,
|
ListEntitiesSirenResponse,
|
||||||
ListEntitiesSwitchResponse,
|
ListEntitiesSwitchResponse,
|
||||||
ListEntitiesTextSensorResponse,
|
ListEntitiesTextSensorResponse,
|
||||||
|
LockCommandRequest,
|
||||||
|
LockStateResponse,
|
||||||
NumberCommandRequest,
|
NumberCommandRequest,
|
||||||
NumberStateResponse,
|
NumberStateResponse,
|
||||||
PingRequest,
|
PingRequest,
|
||||||
@ -167,6 +170,9 @@ MESSAGE_TYPE_TO_PROTO = {
|
|||||||
55: ListEntitiesSirenResponse,
|
55: ListEntitiesSirenResponse,
|
||||||
56: SirenStateResponse,
|
56: SirenStateResponse,
|
||||||
57: SirenCommandRequest,
|
57: SirenCommandRequest,
|
||||||
|
58: ListEntitiesLockResponse,
|
||||||
|
59: LockStateResponse,
|
||||||
|
60: LockCommandRequest,
|
||||||
61: ListEntitiesButtonResponse,
|
61: ListEntitiesButtonResponse,
|
||||||
62: ButtonCommandRequest,
|
62: ButtonCommandRequest,
|
||||||
}
|
}
|
||||||
|
@ -602,6 +602,38 @@ class ButtonInfo(EntityInfo):
|
|||||||
device_class: str = ""
|
device_class: str = ""
|
||||||
|
|
||||||
|
|
||||||
|
# ==================== LOCK ====================
|
||||||
|
class LockState(APIIntEnum):
|
||||||
|
NONE = 0
|
||||||
|
LOCKED = 1
|
||||||
|
UNLOCKED = 3
|
||||||
|
JAMMED = 3
|
||||||
|
LOCKING = 4
|
||||||
|
UNLOCKING = 5
|
||||||
|
|
||||||
|
|
||||||
|
class LockCommand(APIIntEnum):
|
||||||
|
UNLOCK = 0
|
||||||
|
LOCK = 1
|
||||||
|
OPEN = 2
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class LockInfo(EntityInfo):
|
||||||
|
supports_open: bool = False
|
||||||
|
assumed_state: bool = False
|
||||||
|
|
||||||
|
requires_code: bool = False
|
||||||
|
code_format: str = ""
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class LockEntityState(EntityState):
|
||||||
|
state: Optional[LockState] = converter_field(
|
||||||
|
default=LockState.NONE, converter=LockState.convert
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# ==================== INFO MAP ====================
|
# ==================== INFO MAP ====================
|
||||||
|
|
||||||
COMPONENT_TYPE_TO_INFO: Dict[str, Type[EntityInfo]] = {
|
COMPONENT_TYPE_TO_INFO: Dict[str, Type[EntityInfo]] = {
|
||||||
@ -618,6 +650,7 @@ COMPONENT_TYPE_TO_INFO: Dict[str, Type[EntityInfo]] = {
|
|||||||
"select": SelectInfo,
|
"select": SelectInfo,
|
||||||
"siren": SirenInfo,
|
"siren": SirenInfo,
|
||||||
"button": ButtonInfo,
|
"button": ButtonInfo,
|
||||||
|
"lock": LockInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ from aioesphomeapi.api_pb2 import (
|
|||||||
ListEntitiesBinarySensorResponse,
|
ListEntitiesBinarySensorResponse,
|
||||||
ListEntitiesDoneResponse,
|
ListEntitiesDoneResponse,
|
||||||
ListEntitiesServicesResponse,
|
ListEntitiesServicesResponse,
|
||||||
|
LockCommandRequest,
|
||||||
NumberCommandRequest,
|
NumberCommandRequest,
|
||||||
SelectCommandRequest,
|
SelectCommandRequest,
|
||||||
SwitchCommandRequest,
|
SwitchCommandRequest,
|
||||||
@ -33,6 +34,7 @@ from aioesphomeapi.model import (
|
|||||||
FanDirection,
|
FanDirection,
|
||||||
FanSpeed,
|
FanSpeed,
|
||||||
LegacyCoverCommand,
|
LegacyCoverCommand,
|
||||||
|
LockCommand,
|
||||||
UserService,
|
UserService,
|
||||||
UserServiceArg,
|
UserServiceArg,
|
||||||
UserServiceArgType,
|
UserServiceArgType,
|
||||||
@ -356,6 +358,25 @@ 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, command=LockCommand.LOCK), dict(key=1, command=LockCommand.LOCK)),
|
||||||
|
(
|
||||||
|
dict(key=1, command=LockCommand.UNLOCK),
|
||||||
|
dict(key=1, command=LockCommand.UNLOCK),
|
||||||
|
),
|
||||||
|
(dict(key=1, command=LockCommand.OPEN), dict(key=1, command=LockCommand.OPEN)),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_lock_command(auth_client, cmd, req):
|
||||||
|
send = patch_send(auth_client)
|
||||||
|
|
||||||
|
await auth_client.lock_command(**cmd)
|
||||||
|
send.assert_called_once_with(LockCommandRequest(**req))
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"cmd, req",
|
"cmd, req",
|
||||||
|
@ -18,6 +18,7 @@ from aioesphomeapi.api_pb2 import (
|
|||||||
ListEntitiesCoverResponse,
|
ListEntitiesCoverResponse,
|
||||||
ListEntitiesFanResponse,
|
ListEntitiesFanResponse,
|
||||||
ListEntitiesLightResponse,
|
ListEntitiesLightResponse,
|
||||||
|
ListEntitiesLockResponse,
|
||||||
ListEntitiesNumberResponse,
|
ListEntitiesNumberResponse,
|
||||||
ListEntitiesSelectResponse,
|
ListEntitiesSelectResponse,
|
||||||
ListEntitiesSensorResponse,
|
ListEntitiesSensorResponse,
|
||||||
@ -25,6 +26,7 @@ from aioesphomeapi.api_pb2 import (
|
|||||||
ListEntitiesServicesResponse,
|
ListEntitiesServicesResponse,
|
||||||
ListEntitiesSwitchResponse,
|
ListEntitiesSwitchResponse,
|
||||||
ListEntitiesTextSensorResponse,
|
ListEntitiesTextSensorResponse,
|
||||||
|
LockStateResponse,
|
||||||
NumberStateResponse,
|
NumberStateResponse,
|
||||||
SelectStateResponse,
|
SelectStateResponse,
|
||||||
SensorStateResponse,
|
SensorStateResponse,
|
||||||
@ -51,6 +53,8 @@ from aioesphomeapi.model import (
|
|||||||
LegacyCoverState,
|
LegacyCoverState,
|
||||||
LightInfo,
|
LightInfo,
|
||||||
LightState,
|
LightState,
|
||||||
|
LockEntityState,
|
||||||
|
LockInfo,
|
||||||
NumberInfo,
|
NumberInfo,
|
||||||
NumberState,
|
NumberState,
|
||||||
SelectInfo,
|
SelectInfo,
|
||||||
@ -220,6 +224,8 @@ def test_api_version_ord():
|
|||||||
(UserServiceArg, ListEntitiesServicesArgument),
|
(UserServiceArg, ListEntitiesServicesArgument),
|
||||||
(UserService, ListEntitiesServicesResponse),
|
(UserService, ListEntitiesServicesResponse),
|
||||||
(ButtonInfo, ListEntitiesButtonResponse),
|
(ButtonInfo, ListEntitiesButtonResponse),
|
||||||
|
(LockInfo, ListEntitiesLockResponse),
|
||||||
|
(LockEntityState, LockStateResponse),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_basic_pb_conversions(model, pb):
|
def test_basic_pb_conversions(model, pb):
|
||||||
|
Loading…
Reference in New Issue
Block a user