Add native API
This commit is contained in:
parent
0faf2244e6
commit
2907240972
|
@ -92,7 +92,7 @@ message DeviceInfoResponse {
|
||||||
|
|
||||||
// A string describing the date of compilation, this is generated by the compiler
|
// A string describing the date of compilation, this is generated by the compiler
|
||||||
// and therefore may not be in the same format all the time.
|
// and therefore may not be in the same format all the time.
|
||||||
// If the user isn't using esphomeyaml, this will also not be set.
|
// If the user isn't using ESPHome, this will also not be set.
|
||||||
string compilation_time = 5;
|
string compilation_time = 5;
|
||||||
|
|
||||||
// The model of the board. For example NodeMCU
|
// The model of the board. For example NodeMCU
|
||||||
|
@ -290,6 +290,7 @@ message SubscribeLogsResponse {
|
||||||
LogLevel level = 1;
|
LogLevel level = 1;
|
||||||
string tag = 2;
|
string tag = 2;
|
||||||
string message = 3;
|
string message = 3;
|
||||||
|
bool send_failed = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message SubscribeServiceCallsRequest {
|
message SubscribeServiceCallsRequest {
|
||||||
|
@ -327,3 +328,32 @@ message GetTimeResponse {
|
||||||
fixed32 epoch_seconds = 1;
|
fixed32 epoch_seconds = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
message ListEntitiesServicesArgument {
|
||||||
|
string name = 1;
|
||||||
|
enum Type {
|
||||||
|
BOOL = 0;
|
||||||
|
INT = 1;
|
||||||
|
FLOAT = 2;
|
||||||
|
STRING = 3;
|
||||||
|
}
|
||||||
|
Type type = 2;
|
||||||
|
}
|
||||||
|
message ListEntitiesServicesResponse {
|
||||||
|
string name = 1;
|
||||||
|
fixed32 key = 2;
|
||||||
|
repeated ListEntitiesServicesArgument args = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ExecuteServiceArgument {
|
||||||
|
bool bool_ = 1;
|
||||||
|
int32 int_ = 2;
|
||||||
|
float float_ = 3;
|
||||||
|
string string_ = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ExecuteServiceRequest {
|
||||||
|
fixed32 key = 1;
|
||||||
|
repeated ExecuteServiceArgument args = 2;
|
||||||
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -57,6 +57,8 @@ MESSAGE_TYPE_TO_PROTO = {
|
||||||
38: pb.SubscribeHomeAssistantStatesRequest,
|
38: pb.SubscribeHomeAssistantStatesRequest,
|
||||||
39: pb.SubscribeHomeAssistantStateResponse,
|
39: pb.SubscribeHomeAssistantStateResponse,
|
||||||
40: pb.HomeAssistantStateResponse,
|
40: pb.HomeAssistantStateResponse,
|
||||||
|
41: pb.ListEntitiesServicesResponse,
|
||||||
|
42: pb.ExecuteServiceRequest,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -267,16 +269,49 @@ class ServiceCall:
|
||||||
variables = attr.ib(type=Dict[str, str], converter=dict)
|
variables = attr.ib(type=Dict[str, str], converter=dict)
|
||||||
|
|
||||||
|
|
||||||
|
USER_SERVICE_ARG_BOOL = 0
|
||||||
|
USER_SERVICE_ARG_INT = 1
|
||||||
|
USER_SERVICE_ARG_FLOAT = 2
|
||||||
|
USER_SERVICE_ARG_STRING = 3
|
||||||
|
USER_SERVICE_ARG_TYPES = [
|
||||||
|
USER_SERVICE_ARG_BOOL, USER_SERVICE_ARG_INT, USER_SERVICE_ARG_FLOAT, USER_SERVICE_ARG_STRING
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _attr_obj_from_dict(cls, **kwargs):
|
||||||
|
return cls(**{key: kwargs[key] for key in attr.fields_dict(cls)})
|
||||||
|
|
||||||
|
|
||||||
@attr.s
|
@attr.s
|
||||||
class State:
|
class UserServiceArg:
|
||||||
running = attr.ib(type=bool)
|
name = attr.ib(type=str)
|
||||||
stopped = attr.ib(type=bool)
|
type_ = attr.ib(type=int, converter=int,
|
||||||
socket = attr.ib(type=Optional[socket.socket])
|
validator=attr.validators.in_(USER_SERVICE_ARG_TYPES))
|
||||||
socket_reader = attr.ib(type=Optional[asyncio.StreamReader])
|
|
||||||
socket_writer = attr.ib(type=Optional[asyncio.StreamWriter])
|
|
||||||
socket_open = attr.ib(type=bool)
|
@attr.s
|
||||||
connected = attr.ib(type=bool)
|
class UserService:
|
||||||
authenticated = attr.ib(type=bool)
|
name = attr.ib(type=str)
|
||||||
|
key = attr.ib(type=int)
|
||||||
|
args = attr.ib(type=List[UserServiceArg], converter=list)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_dict(dict_):
|
||||||
|
args = []
|
||||||
|
for arg in dict_.get('args', []):
|
||||||
|
args.append(_attr_obj_from_dict(UserServiceArg, **arg))
|
||||||
|
return UserService(
|
||||||
|
name=dict_.get('name', ''),
|
||||||
|
key=dict_.get('key', 0),
|
||||||
|
args=args
|
||||||
|
)
|
||||||
|
|
||||||
|
def to_dict(self):
|
||||||
|
return {
|
||||||
|
'name': self.name,
|
||||||
|
'key': self.key,
|
||||||
|
'args': [attr.asdict(arg) for arg in self.args],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@attr.s
|
@attr.s
|
||||||
|
@ -669,7 +704,7 @@ class APIClient:
|
||||||
has_deep_sleep=resp.has_deep_sleep,
|
has_deep_sleep=resp.has_deep_sleep,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def list_entities(self) -> List[Any]:
|
async def list_entities_services(self) -> Tuple[List[Any], List[UserService]]:
|
||||||
self._check_authenticated()
|
self._check_authenticated()
|
||||||
response_types = {
|
response_types = {
|
||||||
pb.ListEntitiesBinarySensorResponse: BinarySensorInfo,
|
pb.ListEntitiesBinarySensorResponse: BinarySensorInfo,
|
||||||
|
@ -679,6 +714,7 @@ class APIClient:
|
||||||
pb.ListEntitiesSensorResponse: SensorInfo,
|
pb.ListEntitiesSensorResponse: SensorInfo,
|
||||||
pb.ListEntitiesSwitchResponse: SwitchInfo,
|
pb.ListEntitiesSwitchResponse: SwitchInfo,
|
||||||
pb.ListEntitiesTextSensorResponse: TextSensorInfo,
|
pb.ListEntitiesTextSensorResponse: TextSensorInfo,
|
||||||
|
pb.ListEntitiesServicesResponse: None,
|
||||||
}
|
}
|
||||||
|
|
||||||
def do_append(msg):
|
def do_append(msg):
|
||||||
|
@ -690,7 +726,21 @@ class APIClient:
|
||||||
resp = await self._connection.send_message_await_response_complex(
|
resp = await self._connection.send_message_await_response_complex(
|
||||||
pb.ListEntitiesRequest(), do_append, do_stop, timeout=5)
|
pb.ListEntitiesRequest(), do_append, do_stop, timeout=5)
|
||||||
entities = []
|
entities = []
|
||||||
|
services = []
|
||||||
for msg in resp:
|
for msg in resp:
|
||||||
|
if isinstance(msg, pb.ListEntitiesServicesResponse):
|
||||||
|
args = []
|
||||||
|
for arg in msg.args:
|
||||||
|
args.append(UserServiceArg(
|
||||||
|
name=arg.name,
|
||||||
|
type_=arg.type,
|
||||||
|
))
|
||||||
|
services.append(UserService(
|
||||||
|
name=msg.name,
|
||||||
|
key=msg.key,
|
||||||
|
args=args,
|
||||||
|
))
|
||||||
|
continue
|
||||||
cls = None
|
cls = None
|
||||||
for resp_type, cls in response_types.items():
|
for resp_type, cls in response_types.items():
|
||||||
if isinstance(msg, resp_type):
|
if isinstance(msg, resp_type):
|
||||||
|
@ -699,7 +749,7 @@ class APIClient:
|
||||||
for key, _ in attr.fields_dict(cls).items():
|
for key, _ in attr.fields_dict(cls).items():
|
||||||
kwargs[key] = getattr(msg, key)
|
kwargs[key] = getattr(msg, key)
|
||||||
entities.append(cls(**kwargs))
|
entities.append(cls(**kwargs))
|
||||||
return entities
|
return entities, services
|
||||||
|
|
||||||
async def subscribe_states(self, on_state: Callable[[Any], None]) -> None:
|
async def subscribe_states(self, on_state: Callable[[Any], None]) -> None:
|
||||||
self._check_authenticated()
|
self._check_authenticated()
|
||||||
|
@ -862,3 +912,23 @@ class APIClient:
|
||||||
req.key = key
|
req.key = key
|
||||||
req.state = state
|
req.state = state
|
||||||
await self._connection.send_message(req)
|
await self._connection.send_message(req)
|
||||||
|
|
||||||
|
async def execute_service(self, service: UserService, data: dict):
|
||||||
|
self._check_authenticated()
|
||||||
|
|
||||||
|
req = pb.ExecuteServiceRequest()
|
||||||
|
req.key = service.key
|
||||||
|
args = []
|
||||||
|
for arg_desc in service.args:
|
||||||
|
arg = pb.ExecuteServiceArgument()
|
||||||
|
val = data[arg_desc.name]
|
||||||
|
attr_ = {
|
||||||
|
USER_SERVICE_ARG_BOOL: 'bool_',
|
||||||
|
USER_SERVICE_ARG_INT: 'int_',
|
||||||
|
USER_SERVICE_ARG_FLOAT: 'float_',
|
||||||
|
USER_SERVICE_ARG_STRING: 'string_',
|
||||||
|
}[arg_desc.type_]
|
||||||
|
setattr(arg, attr_, val)
|
||||||
|
args.append(arg)
|
||||||
|
req.args.extend(args)
|
||||||
|
await self._connection.send_message(req)
|
||||||
|
|
Loading…
Reference in New Issue