mirror of
https://github.com/esphome/esphome.git
synced 2025-10-27 13:13:50 +00:00
🏗 Merge C++ into python codebase (#504)
## Description: Move esphome-core codebase into esphome (and a bunch of other refactors). See https://github.com/esphome/feature-requests/issues/97 Yes this is a shit ton of work and no there's no way to automate it :( But it will be worth it 👍 Progress: - Core support (file copy etc): 80% - Base Abstractions (light, switch): ~50% - Integrations: ~10% - Working? Yes, (but only with ported components). Other refactors: - Moves all codegen related stuff into a single class: `esphome.codegen` (imported as `cg`) - Rework coroutine syntax - Move from `component/platform.py` to `domain/component.py` structure as with HA - Move all defaults out of C++ and into config validation. - Remove `make_...` helpers from Application class. Reason: Merge conflicts with every single new integration. - Pointer Variables are stored globally instead of locally in setup(). Reason: stack size limit. Future work: - Rework const.py - Move all `CONF_...` into a conf class (usage `conf.UPDATE_INTERVAL` vs `CONF_UPDATE_INTERVAL`). Reason: Less convoluted import block - Enable loading from `custom_components` folder. **Related issue (if applicable):** https://github.com/esphome/feature-requests/issues/97 **Pull request in [esphome-docs](https://github.com/esphome/esphome-docs) with documentation (if applicable):** esphome/esphome-docs#<esphome-docs PR number goes here> ## Checklist: - [ ] The code change is tested and works locally. - [ ] Tests have been added to verify that the new code works (under `tests/` folder). If user exposed functionality or configuration variables are added/changed: - [ ] Documentation added/updated in [esphomedocs](https://github.com/OttoWinter/esphomedocs).
This commit is contained in:
127
esphome/components/api/__init__.py
Normal file
127
esphome/components/api/__init__.py
Normal file
@@ -0,0 +1,127 @@
|
||||
|
||||
from esphome import automation
|
||||
from esphome.automation import ACTION_REGISTRY, CONDITION_REGISTRY, Condition
|
||||
import esphome.config_validation as cv
|
||||
import esphome.codegen as cg
|
||||
from esphome.const import CONF_DATA, CONF_DATA_TEMPLATE, CONF_ID, CONF_PASSWORD, CONF_PORT, \
|
||||
CONF_REBOOT_TIMEOUT, CONF_SERVICE, CONF_VARIABLES, CONF_SERVICES, CONF_TRIGGER_ID
|
||||
from esphome.core import CORE, coroutine_with_priority
|
||||
|
||||
api_ns = cg.esphome_ns.namespace('api')
|
||||
APIServer = api_ns.class_('APIServer', cg.Component, cg.Controller)
|
||||
HomeAssistantServiceCallAction = api_ns.class_('HomeAssistantServiceCallAction', cg.Action)
|
||||
KeyValuePair = api_ns.class_('KeyValuePair')
|
||||
TemplatableKeyValuePair = api_ns.class_('TemplatableKeyValuePair')
|
||||
APIConnectedCondition = api_ns.class_('APIConnectedCondition', Condition)
|
||||
|
||||
UserService = api_ns.class_('UserService', cg.Trigger)
|
||||
ServiceTypeArgument = api_ns.class_('ServiceTypeArgument')
|
||||
ServiceArgType = api_ns.enum('ServiceArgType')
|
||||
SERVICE_ARG_TYPES = {
|
||||
'bool': ServiceArgType.SERVICE_ARG_TYPE_BOOL,
|
||||
'int': ServiceArgType.SERVICE_ARG_TYPE_INT,
|
||||
'float': ServiceArgType.SERVICE_ARG_TYPE_FLOAT,
|
||||
'string': ServiceArgType.SERVICE_ARG_TYPE_STRING,
|
||||
}
|
||||
SERVICE_ARG_NATIVE_TYPES = {
|
||||
'bool': bool,
|
||||
'int': cg.int32,
|
||||
'float': float,
|
||||
'string': cg.std_string,
|
||||
}
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.Schema({
|
||||
cv.GenerateID(): cv.declare_variable_id(APIServer),
|
||||
cv.Optional(CONF_PORT, default=6053): cv.port,
|
||||
cv.Optional(CONF_PASSWORD, default=''): cv.string_strict,
|
||||
cv.Optional(CONF_REBOOT_TIMEOUT, default='5min'): cv.positive_time_period_milliseconds,
|
||||
cv.Optional(CONF_SERVICES): automation.validate_automation({
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(UserService),
|
||||
cv.Required(CONF_SERVICE): cv.valid_name,
|
||||
cv.Optional(CONF_VARIABLES, default={}): cv.Schema({
|
||||
cv.validate_id_name: cv.one_of(*SERVICE_ARG_TYPES, lower=True),
|
||||
}),
|
||||
}),
|
||||
}).extend(cv.COMPONENT_SCHEMA)
|
||||
|
||||
|
||||
@coroutine_with_priority(40.0)
|
||||
def to_code(config):
|
||||
rhs = APIServer.new()
|
||||
api = cg.Pvariable(config[CONF_ID], rhs)
|
||||
yield cg.register_component(api, config)
|
||||
|
||||
cg.add(api.set_port(config[CONF_PORT]))
|
||||
cg.add(api.set_password(config[CONF_PASSWORD]))
|
||||
cg.add(api.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT]))
|
||||
|
||||
for conf in config.get(CONF_SERVICES, []):
|
||||
template_args = []
|
||||
func_args = []
|
||||
service_type_args = []
|
||||
for name, var_ in conf[CONF_VARIABLES].items():
|
||||
native = SERVICE_ARG_NATIVE_TYPES[var_]
|
||||
template_args.append(native)
|
||||
func_args.append((native, name))
|
||||
service_type_args.append(ServiceTypeArgument(name, SERVICE_ARG_TYPES[var_]))
|
||||
func = api.make_user_service_trigger.template(*template_args)
|
||||
rhs = func(conf[CONF_SERVICE], service_type_args)
|
||||
type_ = UserService.template(*template_args)
|
||||
trigger = cg.Pvariable(conf[CONF_TRIGGER_ID], rhs, type=type_)
|
||||
yield automation.build_automation(trigger, func_args, conf)
|
||||
|
||||
cg.add_define('USE_API')
|
||||
if CORE.is_esp32:
|
||||
cg.add_library('AsyncTCP', '1.0.3')
|
||||
elif CORE.is_esp8266:
|
||||
cg.add_library('ESPAsyncTCP', '1.2.0')
|
||||
|
||||
|
||||
CONF_HOMEASSISTANT_SERVICE = 'homeassistant.service'
|
||||
HOMEASSISTANT_SERVICE_ACTION_SCHEMA = cv.Schema({
|
||||
cv.GenerateID(): cv.use_variable_id(APIServer),
|
||||
cv.Required(CONF_SERVICE): cv.string,
|
||||
cv.Optional(CONF_DATA): cv.Schema({
|
||||
cv.string: cv.string,
|
||||
}),
|
||||
cv.Optional(CONF_DATA_TEMPLATE): cv.Schema({
|
||||
cv.string: cv.string,
|
||||
}),
|
||||
cv.Optional(CONF_VARIABLES): cv.Schema({
|
||||
cv.string: cv.lambda_,
|
||||
}),
|
||||
})
|
||||
|
||||
|
||||
@ACTION_REGISTRY.register(CONF_HOMEASSISTANT_SERVICE, HOMEASSISTANT_SERVICE_ACTION_SCHEMA)
|
||||
def homeassistant_service_to_code(config, action_id, template_arg, args):
|
||||
var = yield cg.get_variable(config[CONF_ID])
|
||||
type = HomeAssistantServiceCallAction.template(template_arg)
|
||||
rhs = type.new(var)
|
||||
act = cg.Pvariable(action_id, rhs, type=type)
|
||||
cg.add(act.set_service(config[CONF_SERVICE]))
|
||||
if CONF_DATA in config:
|
||||
datas = [KeyValuePair(k, v) for k, v in config[CONF_DATA].items()]
|
||||
cg.add(act.set_data(datas))
|
||||
if CONF_DATA_TEMPLATE in config:
|
||||
datas = [KeyValuePair(k, v) for k, v in config[CONF_DATA_TEMPLATE].items()]
|
||||
cg.add(act.set_data_template(datas))
|
||||
if CONF_VARIABLES in config:
|
||||
datas = []
|
||||
for key, value in config[CONF_VARIABLES].items():
|
||||
value_ = yield cg.process_lambda(value, [])
|
||||
datas.append(TemplatableKeyValuePair(key, value_))
|
||||
cg.add(act.set_variables(datas))
|
||||
yield act
|
||||
|
||||
|
||||
CONF_API_CONNECTED = 'api.connected'
|
||||
API_CONNECTED_CONDITION_SCHEMA = cv.Schema({})
|
||||
|
||||
|
||||
@CONDITION_REGISTRY.register(CONF_API_CONNECTED, API_CONNECTED_CONDITION_SCHEMA)
|
||||
def api_connected_to_code(config, condition_id, template_arg, args):
|
||||
rhs = APIConnectedCondition.new(template_arg)
|
||||
type = APIConnectedCondition.template(template_arg)
|
||||
yield cg.Pvariable(condition_id, rhs, type=type)
|
||||
506
esphome/components/api/api.proto
Normal file
506
esphome/components/api/api.proto
Normal file
@@ -0,0 +1,506 @@
|
||||
syntax = "proto3";
|
||||
|
||||
|
||||
// ==================== BASE PACKETS ====================
|
||||
|
||||
// The Home Assistant protocol is structured as a simple
|
||||
// TCP socket with short binary messages encoded in the protocol buffers format
|
||||
// First, a message in this protocol has a specific format:
|
||||
// * VarInt denoting the size of the message object. (type is not part of this)
|
||||
// * VarInt denoting the type of message.
|
||||
// * The message object encoded as a ProtoBuf message
|
||||
|
||||
// The connection is established in 4 steps:
|
||||
// * First, the client connects to the server and sends a "Hello Request" identifying itself
|
||||
// * The server responds with a "Hello Response" and selects the protocol version
|
||||
// * After receiving this message, the client attempts to authenticate itself using
|
||||
// the password and a "Connect Request"
|
||||
// * The server responds with a "Connect Response" and notifies of invalid password.
|
||||
// If anything in this initial process fails, the connection must immediately closed
|
||||
// by both sides and _no_ disconnection message is to be sent.
|
||||
|
||||
// Message sent at the beginning of each connection
|
||||
// Can only be sent by the client and only at the beginning of the connection
|
||||
// ID: 1
|
||||
message HelloRequest {
|
||||
// Description of client (like User Agent)
|
||||
// For example "Home Assistant"
|
||||
// Not strictly necessary to send but nice for debugging
|
||||
// purposes.
|
||||
string client_info = 1;
|
||||
}
|
||||
|
||||
// Confirmation of successful connection request.
|
||||
// Can only be sent by the server and only at the beginning of the connection
|
||||
// ID: 2
|
||||
message HelloResponse {
|
||||
// The version of the API to use. The _client_ (for example Home Assistant) needs to check
|
||||
// for compatibility and if necessary adopt to an older API.
|
||||
// Major is for breaking changes in the base protocol - a mismatch will lead to immediate disconnect_client_
|
||||
// Minor is for breaking changes in individual messages - a mismatch will lead to a warning message
|
||||
uint32 api_version_major = 1;
|
||||
uint32 api_version_minor = 2;
|
||||
|
||||
// A string identifying the server (ESP); like client info this may be empty
|
||||
// and only exists for debugging/logging purposes.
|
||||
// For example "ESPHome v1.10.0 on ESP8266"
|
||||
string server_info = 3;
|
||||
}
|
||||
|
||||
// Message sent at the beginning of each connection to authenticate the client
|
||||
// Can only be sent by the client and only at the beginning of the connection
|
||||
// ID: 3
|
||||
message ConnectRequest {
|
||||
// The password to log in with
|
||||
string password = 1;
|
||||
}
|
||||
|
||||
// Confirmation of successful connection. After this the connection is available for all traffic.
|
||||
// Can only be sent by the server and only at the beginning of the connection
|
||||
// ID: 4
|
||||
message ConnectResponse {
|
||||
bool invalid_password = 1;
|
||||
}
|
||||
|
||||
// Request to close the connection.
|
||||
// Can be sent by both the client and server
|
||||
// ID: 5
|
||||
message DisconnectRequest {
|
||||
// Do not close the connection before the acknowledgement arrives
|
||||
}
|
||||
|
||||
// ID: 6
|
||||
message DisconnectResponse {
|
||||
// Empty - Both parties are required to close the connection after this
|
||||
// message has been received.
|
||||
}
|
||||
|
||||
// ID: 7
|
||||
message PingRequest {
|
||||
// Empty
|
||||
}
|
||||
|
||||
// ID: 8
|
||||
message PingResponse {
|
||||
// Empty
|
||||
}
|
||||
|
||||
// ID: 9
|
||||
message DeviceInfoRequest {
|
||||
// Empty
|
||||
}
|
||||
|
||||
// ID: 10
|
||||
message DeviceInfoResponse {
|
||||
bool uses_password = 1;
|
||||
|
||||
// The name of the node, given by "App.set_name()"
|
||||
string name = 2;
|
||||
|
||||
// The mac address of the device. For example "AC:BC:32:89:0E:A9"
|
||||
string mac_address = 3;
|
||||
|
||||
// A string describing the ESPHome version. For example "1.10.0"
|
||||
string esphome_core_version = 4;
|
||||
|
||||
// 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.
|
||||
// If the user isn't using ESPHome, this will also not be set.
|
||||
string compilation_time = 5;
|
||||
|
||||
// The model of the board. For example NodeMCU
|
||||
string model = 6;
|
||||
|
||||
bool has_deep_sleep = 7;
|
||||
}
|
||||
|
||||
// ID: 11
|
||||
message ListEntitiesRequest {
|
||||
// Empty
|
||||
}
|
||||
// ID: 19
|
||||
message ListEntitiesDoneResponse {
|
||||
// Empty
|
||||
}
|
||||
// ID: 20
|
||||
message SubscribeStatesRequest {
|
||||
// Empty
|
||||
}
|
||||
|
||||
// ==================== BINARY SENSOR ====================
|
||||
// ID: 12
|
||||
message ListEntitiesBinarySensorResponse {
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
string name = 3;
|
||||
string unique_id = 4;
|
||||
|
||||
string device_class = 5;
|
||||
bool is_status_binary_sensor = 6;
|
||||
}
|
||||
// ID: 21
|
||||
message BinarySensorStateResponse {
|
||||
fixed32 key = 1;
|
||||
bool state = 2;
|
||||
}
|
||||
|
||||
// ==================== COVER ====================
|
||||
// ID: 13
|
||||
message ListEntitiesCoverResponse {
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
string name = 3;
|
||||
string unique_id = 4;
|
||||
|
||||
bool assumed_state = 5;
|
||||
bool supports_position = 6;
|
||||
bool supports_tilt = 7;
|
||||
string device_class = 8;
|
||||
}
|
||||
// ID: 22
|
||||
message CoverStateResponse {
|
||||
fixed32 key = 1;
|
||||
|
||||
// legacy: state has been removed in 1.13
|
||||
// clients/servers must still send/accept it until the next protocol change
|
||||
enum LegacyCoverState {
|
||||
OPEN = 0;
|
||||
CLOSED = 1;
|
||||
}
|
||||
LegacyCoverState legacy_state = 2;
|
||||
|
||||
float position = 3;
|
||||
float tilt = 4;
|
||||
enum CoverOperation {
|
||||
IDLE = 0;
|
||||
IS_OPENING = 1;
|
||||
IS_CLOSING = 2;
|
||||
}
|
||||
CoverOperation current_operation = 5;
|
||||
}
|
||||
// ID: 30
|
||||
message CoverCommandRequest {
|
||||
fixed32 key = 1;
|
||||
|
||||
// legacy: command has been removed in 1.13
|
||||
// clients/servers must still send/accept it until the next protocol change
|
||||
enum LegacyCoverCommand {
|
||||
OPEN = 0;
|
||||
CLOSE = 1;
|
||||
STOP = 2;
|
||||
}
|
||||
bool has_legacy_command = 2;
|
||||
LegacyCoverCommand legacy_command = 3;
|
||||
|
||||
bool has_position = 4;
|
||||
float position = 5;
|
||||
bool has_tilt = 6;
|
||||
float tilt = 7;
|
||||
bool stop = 8;
|
||||
}
|
||||
|
||||
// ==================== FAN ====================
|
||||
// ID: 14
|
||||
message ListEntitiesFanResponse {
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
string name = 3;
|
||||
string unique_id = 4;
|
||||
|
||||
bool supports_oscillation = 5;
|
||||
bool supports_speed = 6;
|
||||
}
|
||||
enum FanSpeed {
|
||||
LOW = 0;
|
||||
MEDIUM = 1;
|
||||
HIGH = 2;
|
||||
}
|
||||
// ID: 23
|
||||
message FanStateResponse {
|
||||
fixed32 key = 1;
|
||||
bool state = 2;
|
||||
bool oscillating = 3;
|
||||
FanSpeed speed = 4;
|
||||
}
|
||||
// ID: 31
|
||||
message FanCommandRequest {
|
||||
fixed32 key = 1;
|
||||
bool has_state = 2;
|
||||
bool state = 3;
|
||||
bool has_speed = 4;
|
||||
FanSpeed speed = 5;
|
||||
bool has_oscillating = 6;
|
||||
bool oscillating = 7;
|
||||
}
|
||||
|
||||
// ==================== LIGHT ====================
|
||||
// ID: 15
|
||||
message ListEntitiesLightResponse {
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
string name = 3;
|
||||
string unique_id = 4;
|
||||
|
||||
bool supports_brightness = 5;
|
||||
bool supports_rgb = 6;
|
||||
bool supports_white_value = 7;
|
||||
bool supports_color_temperature = 8;
|
||||
float min_mireds = 9;
|
||||
float max_mireds = 10;
|
||||
repeated string effects = 11;
|
||||
}
|
||||
// ID: 24
|
||||
message LightStateResponse {
|
||||
fixed32 key = 1;
|
||||
bool state = 2;
|
||||
float brightness = 3;
|
||||
float red = 4;
|
||||
float green = 5;
|
||||
float blue = 6;
|
||||
float white = 7;
|
||||
float color_temperature = 8;
|
||||
string effect = 9;
|
||||
}
|
||||
// ID: 32
|
||||
message LightCommandRequest {
|
||||
fixed32 key = 1;
|
||||
bool has_state = 2;
|
||||
bool state = 3;
|
||||
bool has_brightness = 4;
|
||||
float brightness = 5;
|
||||
bool has_rgb = 6;
|
||||
float red = 7;
|
||||
float green = 8;
|
||||
float blue = 9;
|
||||
bool has_white = 10;
|
||||
float white = 11;
|
||||
bool has_color_temperature = 12;
|
||||
float color_temperature = 13;
|
||||
bool has_transition_length = 14;
|
||||
uint32 transition_length = 15;
|
||||
bool has_flash_length = 16;
|
||||
uint32 flash_length = 17;
|
||||
bool has_effect = 18;
|
||||
string effect = 19;
|
||||
}
|
||||
|
||||
// ==================== SENSOR ====================
|
||||
// ID: 16
|
||||
message ListEntitiesSensorResponse {
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
string name = 3;
|
||||
string unique_id = 4;
|
||||
|
||||
string icon = 5;
|
||||
string unit_of_measurement = 6;
|
||||
int32 accuracy_decimals = 7;
|
||||
}
|
||||
// ID: 25
|
||||
message SensorStateResponse {
|
||||
fixed32 key = 1;
|
||||
float state = 2;
|
||||
}
|
||||
|
||||
// ==================== SWITCH ====================
|
||||
// ID: 17
|
||||
message ListEntitiesSwitchResponse {
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
string name = 3;
|
||||
string unique_id = 4;
|
||||
|
||||
string icon = 5;
|
||||
bool assumed_state = 6;
|
||||
}
|
||||
// ID: 26
|
||||
message SwitchStateResponse {
|
||||
fixed32 key = 1;
|
||||
bool state = 2;
|
||||
}
|
||||
// ID: 33
|
||||
message SwitchCommandRequest {
|
||||
fixed32 key = 1;
|
||||
bool state = 2;
|
||||
}
|
||||
|
||||
// ==================== TEXT SENSOR ====================
|
||||
// ID: 18
|
||||
message ListEntitiesTextSensorResponse {
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
string name = 3;
|
||||
string unique_id = 4;
|
||||
|
||||
string icon = 5;
|
||||
}
|
||||
// ID: 27
|
||||
message TextSensorStateResponse {
|
||||
fixed32 key = 1;
|
||||
string state = 2;
|
||||
}
|
||||
|
||||
// ==================== SUBSCRIBE LOGS ====================
|
||||
enum LogLevel {
|
||||
NONE = 0;
|
||||
ERROR = 1;
|
||||
WARN = 2;
|
||||
INFO = 3;
|
||||
DEBUG = 4;
|
||||
VERBOSE = 5;
|
||||
VERY_VERBOSE = 6;
|
||||
}
|
||||
// ID: 28
|
||||
message SubscribeLogsRequest {
|
||||
LogLevel level = 1;
|
||||
bool dump_config = 2;
|
||||
}
|
||||
// ID: 29
|
||||
message SubscribeLogsResponse {
|
||||
LogLevel level = 1;
|
||||
string tag = 2;
|
||||
string message = 3;
|
||||
bool send_failed = 4;
|
||||
}
|
||||
|
||||
// ==================== HOMEASSISTANT.SERVICE ====================
|
||||
// ID: 34
|
||||
message SubscribeServiceCallsRequest {
|
||||
|
||||
}
|
||||
|
||||
// ID: 35
|
||||
message ServiceCallResponse {
|
||||
string service = 1;
|
||||
map<string, string> data = 2;
|
||||
map<string, string> data_template = 3;
|
||||
map<string, string> variables = 4;
|
||||
}
|
||||
|
||||
// ==================== IMPORT HOME ASSISTANT STATES ====================
|
||||
// 1. Client sends SubscribeHomeAssistantStatesRequest
|
||||
// 2. Server responds with zero or more SubscribeHomeAssistantStateResponse (async)
|
||||
// 3. Client sends HomeAssistantStateResponse for state changes.
|
||||
// ID: 38
|
||||
message SubscribeHomeAssistantStatesRequest {
|
||||
|
||||
}
|
||||
|
||||
// ID: 39
|
||||
message SubscribeHomeAssistantStateResponse {
|
||||
string entity_id = 1;
|
||||
}
|
||||
|
||||
// ID: 40
|
||||
message HomeAssistantStateResponse {
|
||||
string entity_id = 1;
|
||||
string state = 2;
|
||||
}
|
||||
|
||||
// ==================== IMPORT TIME ====================
|
||||
// ID: 36
|
||||
message GetTimeRequest {
|
||||
|
||||
}
|
||||
|
||||
// ID: 37
|
||||
message GetTimeResponse {
|
||||
fixed32 epoch_seconds = 1;
|
||||
}
|
||||
|
||||
// ==================== USER-DEFINES SERVICES ====================
|
||||
message ListEntitiesServicesArgument {
|
||||
string name = 1;
|
||||
enum Type {
|
||||
BOOL = 0;
|
||||
INT = 1;
|
||||
FLOAT = 2;
|
||||
STRING = 3;
|
||||
}
|
||||
Type type = 2;
|
||||
}
|
||||
// ID: 41
|
||||
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;
|
||||
}
|
||||
// ID: 42
|
||||
message ExecuteServiceRequest {
|
||||
fixed32 key = 1;
|
||||
repeated ExecuteServiceArgument args = 2;
|
||||
}
|
||||
|
||||
// ==================== CAMERA ====================
|
||||
// ID: 43
|
||||
message ListEntitiesCameraResponse {
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
string name = 3;
|
||||
string unique_id = 4;
|
||||
}
|
||||
|
||||
// ID: 44
|
||||
message CameraImageResponse {
|
||||
fixed32 key = 1;
|
||||
bytes data = 2;
|
||||
bool done = 3;
|
||||
}
|
||||
// ID: 45
|
||||
message CameraImageRequest {
|
||||
bool single = 1;
|
||||
bool stream = 2;
|
||||
}
|
||||
|
||||
// ==================== CLIMATE ====================
|
||||
enum ClimateMode {
|
||||
OFF = 0;
|
||||
AUTO = 1;
|
||||
COOL = 2;
|
||||
HEAT = 3;
|
||||
}
|
||||
// ID: 46
|
||||
message ListEntitiesClimateResponse {
|
||||
string object_id = 1;
|
||||
fixed32 key = 2;
|
||||
string name = 3;
|
||||
string unique_id = 4;
|
||||
|
||||
bool supports_current_temperature = 5;
|
||||
bool supports_two_point_target_temperature = 6;
|
||||
repeated ClimateMode supported_modes = 7;
|
||||
float visual_min_temperature = 8;
|
||||
float visual_max_temperature = 9;
|
||||
float visual_temperature_step = 10;
|
||||
bool supports_away = 11;
|
||||
}
|
||||
// ID: 47
|
||||
message ClimateStateResponse {
|
||||
fixed32 key = 1;
|
||||
ClimateMode mode = 2;
|
||||
float current_temperature = 3;
|
||||
float target_temperature = 4;
|
||||
float target_temperature_low = 5;
|
||||
float target_temperature_high = 6;
|
||||
bool away = 7;
|
||||
}
|
||||
// ID: 48
|
||||
message ClimateCommandRequest {
|
||||
fixed32 key = 1;
|
||||
bool has_mode = 2;
|
||||
ClimateMode mode = 3;
|
||||
bool has_target_temperature = 4;
|
||||
float target_temperature = 5;
|
||||
bool has_target_temperature_low = 6;
|
||||
float target_temperature_low = 7;
|
||||
bool has_target_temperature_high = 8;
|
||||
float target_temperature_high = 9;
|
||||
bool has_away = 10;
|
||||
bool away = 11;
|
||||
}
|
||||
87
esphome/components/api/api_message.cpp
Normal file
87
esphome/components/api/api_message.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
#include "api_message.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
static const char *TAG = "api.message";
|
||||
|
||||
bool APIMessage::decode_varint(uint32_t field_id, uint32_t value) { return false; }
|
||||
bool APIMessage::decode_length_delimited(uint32_t field_id, const uint8_t *value, size_t len) { return false; }
|
||||
bool APIMessage::decode_32bit(uint32_t field_id, uint32_t value) { return false; }
|
||||
void APIMessage::encode(APIBuffer &buffer) {}
|
||||
void APIMessage::decode(const uint8_t *buffer, size_t length) {
|
||||
uint32_t i = 0;
|
||||
bool error = false;
|
||||
while (i < length) {
|
||||
uint32_t consumed;
|
||||
auto res = proto_decode_varuint32(&buffer[i], length - i, &consumed);
|
||||
if (!res.has_value()) {
|
||||
ESP_LOGV(TAG, "Invalid field start at %u", i);
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t field_type = (*res) & 0b111;
|
||||
uint32_t field_id = (*res) >> 3;
|
||||
i += consumed;
|
||||
|
||||
switch (field_type) {
|
||||
case 0: { // VarInt
|
||||
res = proto_decode_varuint32(&buffer[i], length - i, &consumed);
|
||||
if (!res.has_value()) {
|
||||
ESP_LOGV(TAG, "Invalid VarInt at %u", i);
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
if (!this->decode_varint(field_id, *res)) {
|
||||
ESP_LOGV(TAG, "Cannot decode VarInt field %u with value %u!", field_id, *res);
|
||||
}
|
||||
i += consumed;
|
||||
break;
|
||||
}
|
||||
case 2: { // Length-delimited
|
||||
res = proto_decode_varuint32(&buffer[i], length - i, &consumed);
|
||||
if (!res.has_value()) {
|
||||
ESP_LOGV(TAG, "Invalid Length Delimited at %u", i);
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
i += consumed;
|
||||
if (*res > length - i) {
|
||||
ESP_LOGV(TAG, "Out-of-bounds Length Delimited at %u", i);
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
if (!this->decode_length_delimited(field_id, &buffer[i], *res)) {
|
||||
ESP_LOGV(TAG, "Cannot decode Length Delimited field %u!", field_id);
|
||||
}
|
||||
i += *res;
|
||||
break;
|
||||
}
|
||||
case 5: { // 32-bit
|
||||
if (length - i < 4) {
|
||||
ESP_LOGV(TAG, "Out-of-bounds Fixed32-bit at %u", i);
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
uint32_t val = (uint32_t(buffer[i]) << 0) | (uint32_t(buffer[i + 1]) << 8) | (uint32_t(buffer[i + 2]) << 16) |
|
||||
(uint32_t(buffer[i + 3]) << 24);
|
||||
if (!this->decode_32bit(field_id, val)) {
|
||||
ESP_LOGV(TAG, "Cannot decode 32-bit field %u with value %u!", field_id, val);
|
||||
}
|
||||
i += 4;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ESP_LOGV(TAG, "Invalid field type at %u", i);
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
if (error) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
79
esphome/components/api/api_message.h
Normal file
79
esphome/components/api/api_message.h
Normal file
@@ -0,0 +1,79 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
enum class APIMessageType {
|
||||
HELLO_REQUEST = 1,
|
||||
HELLO_RESPONSE = 2,
|
||||
CONNECT_REQUEST = 3,
|
||||
CONNECT_RESPONSE = 4,
|
||||
DISCONNECT_REQUEST = 5,
|
||||
DISCONNECT_RESPONSE = 6,
|
||||
PING_REQUEST = 7,
|
||||
PING_RESPONSE = 8,
|
||||
DEVICE_INFO_REQUEST = 9,
|
||||
DEVICE_INFO_RESPONSE = 10,
|
||||
|
||||
LIST_ENTITIES_REQUEST = 11,
|
||||
LIST_ENTITIES_BINARY_SENSOR_RESPONSE = 12,
|
||||
LIST_ENTITIES_COVER_RESPONSE = 13,
|
||||
LIST_ENTITIES_FAN_RESPONSE = 14,
|
||||
LIST_ENTITIES_LIGHT_RESPONSE = 15,
|
||||
LIST_ENTITIES_SENSOR_RESPONSE = 16,
|
||||
LIST_ENTITIES_SWITCH_RESPONSE = 17,
|
||||
LIST_ENTITIES_TEXT_SENSOR_RESPONSE = 18,
|
||||
LIST_ENTITIES_SERVICE_RESPONSE = 41,
|
||||
LIST_ENTITIES_CAMERA_RESPONSE = 43,
|
||||
LIST_ENTITIES_CLIMATE_RESPONSE = 46,
|
||||
LIST_ENTITIES_DONE_RESPONSE = 19,
|
||||
|
||||
SUBSCRIBE_STATES_REQUEST = 20,
|
||||
BINARY_SENSOR_STATE_RESPONSE = 21,
|
||||
COVER_STATE_RESPONSE = 22,
|
||||
FAN_STATE_RESPONSE = 23,
|
||||
LIGHT_STATE_RESPONSE = 24,
|
||||
SENSOR_STATE_RESPONSE = 25,
|
||||
SWITCH_STATE_RESPONSE = 26,
|
||||
TEXT_SENSOR_STATE_RESPONSE = 27,
|
||||
CAMERA_IMAGE_RESPONSE = 44,
|
||||
CLIMATE_STATE_RESPONSE = 47,
|
||||
|
||||
SUBSCRIBE_LOGS_REQUEST = 28,
|
||||
SUBSCRIBE_LOGS_RESPONSE = 29,
|
||||
|
||||
COVER_COMMAND_REQUEST = 30,
|
||||
FAN_COMMAND_REQUEST = 31,
|
||||
LIGHT_COMMAND_REQUEST = 32,
|
||||
SWITCH_COMMAND_REQUEST = 33,
|
||||
CAMERA_IMAGE_REQUEST = 45,
|
||||
CLIMATE_COMMAND_REQUEST = 48,
|
||||
|
||||
SUBSCRIBE_SERVICE_CALLS_REQUEST = 34,
|
||||
SERVICE_CALL_RESPONSE = 35,
|
||||
GET_TIME_REQUEST = 36,
|
||||
GET_TIME_RESPONSE = 37,
|
||||
|
||||
SUBSCRIBE_HOME_ASSISTANT_STATES_REQUEST = 38,
|
||||
SUBSCRIBE_HOME_ASSISTANT_STATE_RESPONSE = 39,
|
||||
HOME_ASSISTANT_STATE_RESPONSE = 40,
|
||||
|
||||
EXECUTE_SERVICE_REQUEST = 42,
|
||||
};
|
||||
|
||||
class APIMessage {
|
||||
public:
|
||||
void decode(const uint8_t *buffer, size_t length);
|
||||
virtual bool decode_varint(uint32_t field_id, uint32_t value);
|
||||
virtual bool decode_length_delimited(uint32_t field_id, const uint8_t *value, size_t len);
|
||||
virtual bool decode_32bit(uint32_t field_id, uint32_t value);
|
||||
virtual APIMessageType message_type() const = 0;
|
||||
|
||||
virtual void encode(APIBuffer &buffer);
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
1202
esphome/components/api/api_server.cpp
Normal file
1202
esphome/components/api/api_server.cpp
Normal file
File diff suppressed because it is too large
Load Diff
245
esphome/components/api/api_server.h
Normal file
245
esphome/components/api/api_server.h
Normal file
@@ -0,0 +1,245 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/controller.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "util.h"
|
||||
#include "api_message.h"
|
||||
#include "basic_messages.h"
|
||||
#include "list_entities.h"
|
||||
#include "subscribe_state.h"
|
||||
#include "subscribe_logs.h"
|
||||
#include "command_messages.h"
|
||||
#include "service_call_message.h"
|
||||
#include "user_services.h"
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include <AsyncTCP.h>
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP8266
|
||||
#include <ESPAsyncTCP.h>
|
||||
#endif
|
||||
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
class APIServer;
|
||||
|
||||
class APIConnection {
|
||||
public:
|
||||
APIConnection(AsyncClient *client, APIServer *parent);
|
||||
~APIConnection();
|
||||
|
||||
void disconnect_client();
|
||||
APIBuffer get_buffer();
|
||||
bool send_buffer(APIMessageType type);
|
||||
bool send_message(APIMessage &msg);
|
||||
bool send_empty_message(APIMessageType type);
|
||||
void loop();
|
||||
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
bool send_binary_sensor_state(binary_sensor::BinarySensor *binary_sensor, bool state);
|
||||
#endif
|
||||
#ifdef USE_COVER
|
||||
bool send_cover_state(cover::Cover *cover);
|
||||
#endif
|
||||
#ifdef USE_FAN
|
||||
bool send_fan_state(fan::FanState *fan);
|
||||
#endif
|
||||
#ifdef USE_LIGHT
|
||||
bool send_light_state(light::LightState *light);
|
||||
#endif
|
||||
#ifdef USE_SENSOR
|
||||
bool send_sensor_state(sensor::Sensor *sensor, float state);
|
||||
#endif
|
||||
#ifdef USE_SWITCH
|
||||
bool send_switch_state(switch_::Switch *a_switch, bool state);
|
||||
#endif
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
bool send_text_sensor_state(text_sensor::TextSensor *text_sensor, std::string state);
|
||||
#endif
|
||||
#ifdef USE_ESP32_CAMERA
|
||||
void send_camera_state(std::shared_ptr<esp32_camera::CameraImage> image);
|
||||
#endif
|
||||
#ifdef USE_CLIMATE
|
||||
bool send_climate_state(climate::Climate *climate);
|
||||
#endif
|
||||
bool send_log_message(int level, const char *tag, const char *line);
|
||||
bool send_disconnect_request();
|
||||
bool send_ping_request();
|
||||
void send_service_call(ServiceCallResponse &call);
|
||||
#ifdef USE_HOMEASSISTANT_TIME
|
||||
void send_time_request();
|
||||
#endif
|
||||
|
||||
protected:
|
||||
friend APIServer;
|
||||
|
||||
void on_error_(int8_t error);
|
||||
void on_disconnect_();
|
||||
void on_timeout_(uint32_t time);
|
||||
void on_data_(uint8_t *buf, size_t len);
|
||||
void fatal_error_();
|
||||
bool valid_rx_message_type_(uint32_t msg_type);
|
||||
void read_message_(uint32_t size, uint32_t type, uint8_t *msg);
|
||||
void parse_recv_buffer_();
|
||||
|
||||
// request types
|
||||
void on_hello_request_(const HelloRequest &req);
|
||||
void on_connect_request_(const ConnectRequest &req);
|
||||
void on_disconnect_request_(const DisconnectRequest &req);
|
||||
void on_disconnect_response_(const DisconnectResponse &req);
|
||||
void on_ping_request_(const PingRequest &req);
|
||||
void on_ping_response_(const PingResponse &req);
|
||||
void on_device_info_request_(const DeviceInfoRequest &req);
|
||||
void on_list_entities_request_(const ListEntitiesRequest &req);
|
||||
void on_subscribe_states_request_(const SubscribeStatesRequest &req);
|
||||
void on_subscribe_logs_request_(const SubscribeLogsRequest &req);
|
||||
#ifdef USE_COVER
|
||||
void on_cover_command_request_(const CoverCommandRequest &req);
|
||||
#endif
|
||||
#ifdef USE_FAN
|
||||
void on_fan_command_request_(const FanCommandRequest &req);
|
||||
#endif
|
||||
#ifdef USE_LIGHT
|
||||
void on_light_command_request_(const LightCommandRequest &req);
|
||||
#endif
|
||||
#ifdef USE_SWITCH
|
||||
void on_switch_command_request_(const SwitchCommandRequest &req);
|
||||
#endif
|
||||
#ifdef USE_CLIMATE
|
||||
void on_climate_command_request_(const ClimateCommandRequest &req);
|
||||
#endif
|
||||
void on_subscribe_service_calls_request_(const SubscribeServiceCallsRequest &req);
|
||||
void on_subscribe_home_assistant_states_request_(const SubscribeHomeAssistantStatesRequest &req);
|
||||
void on_home_assistant_state_response_(const HomeAssistantStateResponse &req);
|
||||
void on_execute_service_(const ExecuteServiceRequest &req);
|
||||
#ifdef USE_ESP32_CAMERA
|
||||
void on_camera_image_request_(const CameraImageRequest &req);
|
||||
#endif
|
||||
|
||||
enum class ConnectionState {
|
||||
WAITING_FOR_HELLO,
|
||||
WAITING_FOR_CONNECT,
|
||||
CONNECTED,
|
||||
} connection_state_{ConnectionState::WAITING_FOR_HELLO};
|
||||
|
||||
bool remove_{false};
|
||||
|
||||
std::vector<uint8_t> send_buffer_;
|
||||
std::vector<uint8_t> recv_buffer_;
|
||||
|
||||
std::string client_info_;
|
||||
#ifdef USE_ESP32_CAMERA
|
||||
esp32_camera::CameraImageReader image_reader_;
|
||||
#endif
|
||||
|
||||
bool state_subscription_{false};
|
||||
int log_subscription_{ESPHOME_LOG_LEVEL_NONE};
|
||||
uint32_t last_traffic_;
|
||||
bool sent_ping_{false};
|
||||
bool service_call_subscription_{false};
|
||||
AsyncClient *client_;
|
||||
APIServer *parent_;
|
||||
InitialStateIterator initial_state_iterator_;
|
||||
ListEntitiesIterator list_entities_iterator_;
|
||||
};
|
||||
|
||||
template<typename... Ts> class HomeAssistantServiceCallAction;
|
||||
|
||||
class APIServer : public Component, public Controller {
|
||||
public:
|
||||
APIServer();
|
||||
void setup() override;
|
||||
uint16_t get_port() const;
|
||||
float get_setup_priority() const override;
|
||||
void loop() override;
|
||||
void dump_config() override;
|
||||
void on_shutdown() override;
|
||||
bool check_password(const std::string &password) const;
|
||||
bool uses_password() const;
|
||||
void set_port(uint16_t port);
|
||||
void set_password(const std::string &password);
|
||||
void set_reboot_timeout(uint32_t reboot_timeout);
|
||||
void handle_disconnect(APIConnection *conn);
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
void on_binary_sensor_update(binary_sensor::BinarySensor *obj, bool state) override;
|
||||
#endif
|
||||
#ifdef USE_COVER
|
||||
void on_cover_update(cover::Cover *obj) override;
|
||||
#endif
|
||||
#ifdef USE_FAN
|
||||
void on_fan_update(fan::FanState *obj) override;
|
||||
#endif
|
||||
#ifdef USE_LIGHT
|
||||
void on_light_update(light::LightState *obj) override;
|
||||
#endif
|
||||
#ifdef USE_SENSOR
|
||||
void on_sensor_update(sensor::Sensor *obj, float state) override;
|
||||
#endif
|
||||
#ifdef USE_SWITCH
|
||||
void on_switch_update(switch_::Switch *obj, bool state) override;
|
||||
#endif
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
void on_text_sensor_update(text_sensor::TextSensor *obj, std::string state) override;
|
||||
#endif
|
||||
#ifdef USE_CLIMATE
|
||||
void on_climate_update(climate::Climate *obj) override;
|
||||
#endif
|
||||
void send_service_call(ServiceCallResponse &call);
|
||||
void register_user_service(UserServiceDescriptor *descriptor) { this->user_services_.push_back(descriptor); }
|
||||
#ifdef USE_HOMEASSISTANT_TIME
|
||||
void request_time();
|
||||
#endif
|
||||
|
||||
bool is_connected() const;
|
||||
|
||||
struct HomeAssistantStateSubscription {
|
||||
std::string entity_id;
|
||||
std::function<void(std::string)> callback;
|
||||
};
|
||||
|
||||
void subscribe_home_assistant_state(std::string entity_id, std::function<void(std::string)> f);
|
||||
const std::vector<HomeAssistantStateSubscription> &get_state_subs() const;
|
||||
const std::vector<UserServiceDescriptor *> &get_user_services() const { return this->user_services_; }
|
||||
|
||||
protected:
|
||||
AsyncServer server_{0};
|
||||
uint16_t port_{6053};
|
||||
uint32_t reboot_timeout_{300000};
|
||||
uint32_t last_connected_{0};
|
||||
std::vector<APIConnection *> clients_;
|
||||
std::string password_;
|
||||
std::vector<HomeAssistantStateSubscription> state_subs_;
|
||||
std::vector<UserServiceDescriptor *> user_services_;
|
||||
};
|
||||
|
||||
extern APIServer *global_api_server;
|
||||
|
||||
template<typename... Ts> class HomeAssistantServiceCallAction : public Action<Ts...> {
|
||||
public:
|
||||
explicit HomeAssistantServiceCallAction(APIServer *parent) : parent_(parent) {}
|
||||
void set_service(const std::string &service) { this->resp_.set_service(service); }
|
||||
void set_data(const std::vector<KeyValuePair> &data) { this->resp_.set_data(data); }
|
||||
void set_data_template(const std::vector<KeyValuePair> &data_template) {
|
||||
this->resp_.set_data_template(data_template);
|
||||
}
|
||||
void set_variables(const std::vector<TemplatableKeyValuePair> &variables) { this->resp_.set_variables(variables); }
|
||||
void play(Ts... x) override {
|
||||
this->parent_->send_service_call(this->resp_);
|
||||
this->play_next(x...);
|
||||
}
|
||||
|
||||
protected:
|
||||
APIServer *parent_;
|
||||
ServiceCallResponse resp_;
|
||||
};
|
||||
|
||||
template<typename... Ts> class APIConnectedCondition : public Condition<Ts...> {
|
||||
public:
|
||||
bool check(Ts... x) override { return global_api_server->is_connected(); }
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
57
esphome/components/api/basic_messages.cpp
Normal file
57
esphome/components/api/basic_messages.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
#include "basic_messages.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
// Hello
|
||||
bool HelloRequest::decode_length_delimited(uint32_t field_id, const uint8_t *value, size_t len) {
|
||||
switch (field_id) {
|
||||
case 1: // string client_info = 1;
|
||||
this->client_info_ = as_string(value, len);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
const std::string &HelloRequest::get_client_info() const { return this->client_info_; }
|
||||
void HelloRequest::set_client_info(const std::string &client_info) { this->client_info_ = client_info; }
|
||||
APIMessageType HelloRequest::message_type() const { return APIMessageType::HELLO_REQUEST; }
|
||||
|
||||
// Connect
|
||||
bool ConnectRequest::decode_length_delimited(uint32_t field_id, const uint8_t *value, size_t len) {
|
||||
switch (field_id) {
|
||||
case 1: // string password = 1;
|
||||
this->password_ = as_string(value, len);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
const std::string &ConnectRequest::get_password() const { return this->password_; }
|
||||
void ConnectRequest::set_password(const std::string &password) { this->password_ = password; }
|
||||
APIMessageType ConnectRequest::message_type() const { return APIMessageType::CONNECT_REQUEST; }
|
||||
|
||||
APIMessageType DeviceInfoRequest::message_type() const { return APIMessageType::DEVICE_INFO_REQUEST; }
|
||||
APIMessageType DisconnectRequest::message_type() const { return APIMessageType::DISCONNECT_REQUEST; }
|
||||
bool DisconnectRequest::decode_length_delimited(uint32_t field_id, const uint8_t *value, size_t len) {
|
||||
switch (field_id) {
|
||||
case 1: // string reason = 1;
|
||||
this->reason_ = as_string(value, len);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
const std::string &DisconnectRequest::get_reason() const { return this->reason_; }
|
||||
void DisconnectRequest::set_reason(const std::string &reason) { this->reason_ = reason; }
|
||||
void DisconnectRequest::encode(APIBuffer &buffer) {
|
||||
// string reason = 1;
|
||||
buffer.encode_string(1, this->reason_);
|
||||
}
|
||||
APIMessageType DisconnectResponse::message_type() const { return APIMessageType::DISCONNECT_RESPONSE; }
|
||||
APIMessageType PingRequest::message_type() const { return APIMessageType::PING_REQUEST; }
|
||||
APIMessageType PingResponse::message_type() const { return APIMessageType::PING_RESPONSE; }
|
||||
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
63
esphome/components/api/basic_messages.h
Normal file
63
esphome/components/api/basic_messages.h
Normal file
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#include "api_message.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
class HelloRequest : public APIMessage {
|
||||
public:
|
||||
bool decode_length_delimited(uint32_t field_id, const uint8_t *value, size_t len) override;
|
||||
const std::string &get_client_info() const;
|
||||
void set_client_info(const std::string &client_info);
|
||||
APIMessageType message_type() const override;
|
||||
|
||||
protected:
|
||||
std::string client_info_;
|
||||
};
|
||||
|
||||
class ConnectRequest : public APIMessage {
|
||||
public:
|
||||
bool decode_length_delimited(uint32_t field_id, const uint8_t *value, size_t len) override;
|
||||
const std::string &get_password() const;
|
||||
void set_password(const std::string &password);
|
||||
APIMessageType message_type() const override;
|
||||
|
||||
protected:
|
||||
std::string password_;
|
||||
};
|
||||
|
||||
class DeviceInfoRequest : public APIMessage {
|
||||
public:
|
||||
APIMessageType message_type() const override;
|
||||
};
|
||||
|
||||
class DisconnectRequest : public APIMessage {
|
||||
public:
|
||||
bool decode_length_delimited(uint32_t field_id, const uint8_t *value, size_t len) override;
|
||||
void encode(APIBuffer &buffer) override;
|
||||
APIMessageType message_type() const override;
|
||||
const std::string &get_reason() const;
|
||||
void set_reason(const std::string &reason);
|
||||
|
||||
protected:
|
||||
std::string reason_;
|
||||
};
|
||||
|
||||
class DisconnectResponse : public APIMessage {
|
||||
public:
|
||||
APIMessageType message_type() const override;
|
||||
};
|
||||
|
||||
class PingRequest : public APIMessage {
|
||||
public:
|
||||
APIMessageType message_type() const override;
|
||||
};
|
||||
|
||||
class PingResponse : public APIMessage {
|
||||
public:
|
||||
APIMessageType message_type() const override;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
417
esphome/components/api/command_messages.cpp
Normal file
417
esphome/components/api/command_messages.cpp
Normal file
@@ -0,0 +1,417 @@
|
||||
#include "command_messages.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
#ifdef USE_COVER
|
||||
bool CoverCommandRequest::decode_varint(uint32_t field_id, uint32_t value) {
|
||||
switch (field_id) {
|
||||
case 2:
|
||||
// bool has_legacy_command = 2;
|
||||
this->has_legacy_command_ = value;
|
||||
return true;
|
||||
case 3:
|
||||
// enum LegacyCoverCommand {
|
||||
// OPEN = 0;
|
||||
// CLOSE = 1;
|
||||
// STOP = 2;
|
||||
// }
|
||||
// LegacyCoverCommand legacy_command_ = 3;
|
||||
this->legacy_command_ = static_cast<LegacyCoverCommand>(value);
|
||||
return true;
|
||||
case 4:
|
||||
// bool has_position = 4;
|
||||
this->has_position_ = value;
|
||||
return true;
|
||||
case 6:
|
||||
// bool has_tilt = 6;
|
||||
this->has_tilt_ = value;
|
||||
return true;
|
||||
case 8:
|
||||
// bool stop = 8;
|
||||
this->stop_ = value;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool CoverCommandRequest::decode_32bit(uint32_t field_id, uint32_t value) {
|
||||
switch (field_id) {
|
||||
case 1:
|
||||
// fixed32 key = 1;
|
||||
this->key_ = value;
|
||||
return true;
|
||||
case 5:
|
||||
// float position = 5;
|
||||
this->position_ = as_float(value);
|
||||
return true;
|
||||
case 7:
|
||||
// float tilt = 7;
|
||||
this->tilt_ = as_float(value);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
APIMessageType CoverCommandRequest::message_type() const { return APIMessageType ::COVER_COMMAND_REQUEST; }
|
||||
uint32_t CoverCommandRequest::get_key() const { return this->key_; }
|
||||
optional<LegacyCoverCommand> CoverCommandRequest::get_legacy_command() const {
|
||||
if (!this->has_legacy_command_)
|
||||
return {};
|
||||
return this->legacy_command_;
|
||||
}
|
||||
optional<float> CoverCommandRequest::get_position() const {
|
||||
if (!this->has_position_)
|
||||
return {};
|
||||
return this->position_;
|
||||
}
|
||||
optional<float> CoverCommandRequest::get_tilt() const {
|
||||
if (!this->has_tilt_)
|
||||
return {};
|
||||
return this->tilt_;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_FAN
|
||||
bool FanCommandRequest::decode_varint(uint32_t field_id, uint32_t value) {
|
||||
switch (field_id) {
|
||||
case 2:
|
||||
// bool has_state = 2;
|
||||
this->has_state_ = value;
|
||||
return true;
|
||||
case 3:
|
||||
// bool state = 3;
|
||||
this->state_ = value;
|
||||
return true;
|
||||
case 4:
|
||||
// bool has_speed = 4;
|
||||
this->has_speed_ = value;
|
||||
return true;
|
||||
case 5:
|
||||
// FanSpeed speed = 5;
|
||||
this->speed_ = static_cast<fan::FanSpeed>(value);
|
||||
return true;
|
||||
case 6:
|
||||
// bool has_oscillating = 6;
|
||||
this->has_oscillating_ = value;
|
||||
return true;
|
||||
case 7:
|
||||
// bool oscillating = 7;
|
||||
this->oscillating_ = value;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool FanCommandRequest::decode_32bit(uint32_t field_id, uint32_t value) {
|
||||
switch (field_id) {
|
||||
case 1:
|
||||
// fixed32 key = 1;
|
||||
this->key_ = value;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
APIMessageType FanCommandRequest::message_type() const { return APIMessageType::FAN_COMMAND_REQUEST; }
|
||||
uint32_t FanCommandRequest::get_key() const { return this->key_; }
|
||||
optional<bool> FanCommandRequest::get_state() const {
|
||||
if (!this->has_state_)
|
||||
return {};
|
||||
return this->state_;
|
||||
}
|
||||
optional<fan::FanSpeed> FanCommandRequest::get_speed() const {
|
||||
if (!this->has_speed_)
|
||||
return {};
|
||||
return this->speed_;
|
||||
}
|
||||
optional<bool> FanCommandRequest::get_oscillating() const {
|
||||
if (!this->has_oscillating_)
|
||||
return {};
|
||||
return this->oscillating_;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_LIGHT
|
||||
bool LightCommandRequest::decode_varint(uint32_t field_id, uint32_t value) {
|
||||
switch (field_id) {
|
||||
case 2:
|
||||
// bool has_state = 2;
|
||||
this->has_state_ = value;
|
||||
return true;
|
||||
case 3:
|
||||
// bool state = 3;
|
||||
this->state_ = value;
|
||||
return true;
|
||||
case 4:
|
||||
// bool has_brightness = 4;
|
||||
this->has_brightness_ = value;
|
||||
return true;
|
||||
case 6:
|
||||
// bool has_rgb = 6;
|
||||
this->has_rgb_ = value;
|
||||
return true;
|
||||
case 10:
|
||||
// bool has_white = 10;
|
||||
this->has_white_ = value;
|
||||
return true;
|
||||
case 12:
|
||||
// bool has_color_temperature = 12;
|
||||
this->has_color_temperature_ = value;
|
||||
return true;
|
||||
case 14:
|
||||
// bool has_transition_length = 14;
|
||||
this->has_transition_length_ = value;
|
||||
return true;
|
||||
case 15:
|
||||
// uint32 transition_length = 15;
|
||||
this->transition_length_ = value;
|
||||
return true;
|
||||
case 16:
|
||||
// bool has_flash_length = 16;
|
||||
this->has_flash_length_ = value;
|
||||
return true;
|
||||
case 17:
|
||||
// uint32 flash_length = 17;
|
||||
this->flash_length_ = value;
|
||||
return true;
|
||||
case 18:
|
||||
// bool has_effect = 18;
|
||||
this->has_effect_ = value;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool LightCommandRequest::decode_length_delimited(uint32_t field_id, const uint8_t *value, size_t len) {
|
||||
switch (field_id) {
|
||||
case 19:
|
||||
// string effect = 19;
|
||||
this->effect_ = as_string(value, len);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool LightCommandRequest::decode_32bit(uint32_t field_id, uint32_t value) {
|
||||
switch (field_id) {
|
||||
case 1:
|
||||
// fixed32 key = 1;
|
||||
this->key_ = value;
|
||||
return true;
|
||||
case 5:
|
||||
// float brightness = 5;
|
||||
this->brightness_ = as_float(value);
|
||||
return true;
|
||||
case 7:
|
||||
// float red = 7;
|
||||
this->red_ = as_float(value);
|
||||
return true;
|
||||
case 8:
|
||||
// float green = 8;
|
||||
this->green_ = as_float(value);
|
||||
return true;
|
||||
case 9:
|
||||
// float blue = 9;
|
||||
this->blue_ = as_float(value);
|
||||
return true;
|
||||
case 11:
|
||||
// float white = 11;
|
||||
this->white_ = as_float(value);
|
||||
return true;
|
||||
case 13:
|
||||
// float color_temperature = 13;
|
||||
this->color_temperature_ = as_float(value);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
APIMessageType LightCommandRequest::message_type() const { return APIMessageType::LIGHT_COMMAND_REQUEST; }
|
||||
uint32_t LightCommandRequest::get_key() const { return this->key_; }
|
||||
optional<bool> LightCommandRequest::get_state() const {
|
||||
if (!this->has_state_)
|
||||
return {};
|
||||
return this->state_;
|
||||
}
|
||||
optional<float> LightCommandRequest::get_brightness() const {
|
||||
if (!this->has_brightness_)
|
||||
return {};
|
||||
return this->brightness_;
|
||||
}
|
||||
optional<float> LightCommandRequest::get_red() const {
|
||||
if (!this->has_rgb_)
|
||||
return {};
|
||||
return this->red_;
|
||||
}
|
||||
optional<float> LightCommandRequest::get_green() const {
|
||||
if (!this->has_rgb_)
|
||||
return {};
|
||||
return this->green_;
|
||||
}
|
||||
optional<float> LightCommandRequest::get_blue() const {
|
||||
if (!this->has_rgb_)
|
||||
return {};
|
||||
return this->blue_;
|
||||
}
|
||||
optional<float> LightCommandRequest::get_white() const {
|
||||
if (!this->has_white_)
|
||||
return {};
|
||||
return this->white_;
|
||||
}
|
||||
optional<float> LightCommandRequest::get_color_temperature() const {
|
||||
if (!this->has_color_temperature_)
|
||||
return {};
|
||||
return this->color_temperature_;
|
||||
}
|
||||
optional<uint32_t> LightCommandRequest::get_transition_length() const {
|
||||
if (!this->has_transition_length_)
|
||||
return {};
|
||||
return this->transition_length_;
|
||||
}
|
||||
optional<uint32_t> LightCommandRequest::get_flash_length() const {
|
||||
if (!this->has_flash_length_)
|
||||
return {};
|
||||
return this->flash_length_;
|
||||
}
|
||||
optional<std::string> LightCommandRequest::get_effect() const {
|
||||
if (!this->has_effect_)
|
||||
return {};
|
||||
return this->effect_;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_SWITCH
|
||||
bool SwitchCommandRequest::decode_varint(uint32_t field_id, uint32_t value) {
|
||||
switch (field_id) {
|
||||
case 2:
|
||||
// bool state = 2;
|
||||
this->state_ = value;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool SwitchCommandRequest::decode_32bit(uint32_t field_id, uint32_t value) {
|
||||
switch (field_id) {
|
||||
case 1:
|
||||
// fixed32 key = 1;
|
||||
this->key_ = value;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
APIMessageType SwitchCommandRequest::message_type() const { return APIMessageType::SWITCH_COMMAND_REQUEST; }
|
||||
uint32_t SwitchCommandRequest::get_key() const { return this->key_; }
|
||||
bool SwitchCommandRequest::get_state() const { return this->state_; }
|
||||
#endif
|
||||
|
||||
#ifdef USE_ESP32_CAMERA
|
||||
bool CameraImageRequest::get_single() const { return this->single_; }
|
||||
bool CameraImageRequest::get_stream() const { return this->stream_; }
|
||||
bool CameraImageRequest::decode_varint(uint32_t field_id, uint32_t value) {
|
||||
switch (field_id) {
|
||||
case 1:
|
||||
// bool single = 1;
|
||||
this->single_ = value;
|
||||
return true;
|
||||
case 2:
|
||||
// bool stream = 2;
|
||||
this->stream_ = value;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
APIMessageType CameraImageRequest::message_type() const { return APIMessageType::CAMERA_IMAGE_REQUEST; }
|
||||
#endif
|
||||
|
||||
#ifdef USE_CLIMATE
|
||||
bool ClimateCommandRequest::decode_varint(uint32_t field_id, uint32_t value) {
|
||||
switch (field_id) {
|
||||
case 2:
|
||||
// bool has_mode = 2;
|
||||
this->has_mode_ = value;
|
||||
return true;
|
||||
case 3:
|
||||
// ClimateMode mode = 3;
|
||||
this->mode_ = static_cast<climate::ClimateMode>(value);
|
||||
return true;
|
||||
case 4:
|
||||
// bool has_target_temperature = 4;
|
||||
this->has_target_temperature_ = value;
|
||||
return true;
|
||||
case 6:
|
||||
// bool has_target_temperature_low = 6;
|
||||
this->has_target_temperature_low_ = value;
|
||||
return true;
|
||||
case 8:
|
||||
// bool has_target_temperature_high = 8;
|
||||
this->has_target_temperature_high_ = value;
|
||||
return true;
|
||||
case 10:
|
||||
// bool has_away = 10;
|
||||
this->has_away_ = value;
|
||||
return true;
|
||||
case 11:
|
||||
// bool away = 11;
|
||||
this->away_ = value;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool ClimateCommandRequest::decode_32bit(uint32_t field_id, uint32_t value) {
|
||||
switch (field_id) {
|
||||
case 1:
|
||||
// fixed32 key = 1;
|
||||
this->key_ = value;
|
||||
return true;
|
||||
case 5:
|
||||
// float target_temperature = 5;
|
||||
this->target_temperature_ = as_float(value);
|
||||
return true;
|
||||
case 7:
|
||||
// float target_temperature_low = 7;
|
||||
this->target_temperature_low_ = as_float(value);
|
||||
return true;
|
||||
case 9:
|
||||
// float target_temperature_high = 9;
|
||||
this->target_temperature_high_ = as_float(value);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
APIMessageType ClimateCommandRequest::message_type() const { return APIMessageType::CLIMATE_COMMAND_REQUEST; }
|
||||
uint32_t ClimateCommandRequest::get_key() const { return this->key_; }
|
||||
optional<climate::ClimateMode> ClimateCommandRequest::get_mode() const {
|
||||
if (!this->has_mode_)
|
||||
return {};
|
||||
return this->mode_;
|
||||
}
|
||||
optional<float> ClimateCommandRequest::get_target_temperature() const {
|
||||
if (!this->has_target_temperature_)
|
||||
return {};
|
||||
return this->target_temperature_;
|
||||
}
|
||||
optional<float> ClimateCommandRequest::get_target_temperature_low() const {
|
||||
if (!this->has_target_temperature_low_)
|
||||
return {};
|
||||
return this->target_temperature_low_;
|
||||
}
|
||||
optional<float> ClimateCommandRequest::get_target_temperature_high() const {
|
||||
if (!this->has_target_temperature_high_)
|
||||
return {};
|
||||
return this->target_temperature_high_;
|
||||
}
|
||||
optional<bool> ClimateCommandRequest::get_away() const {
|
||||
if (!this->has_away_)
|
||||
return {};
|
||||
return this->away_;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
162
esphome/components/api/command_messages.h
Normal file
162
esphome/components/api/command_messages.h
Normal file
@@ -0,0 +1,162 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "api_message.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
#ifdef USE_COVER
|
||||
enum LegacyCoverCommand {
|
||||
LEGACY_COVER_COMMAND_OPEN = 0,
|
||||
LEGACY_COVER_COMMAND_CLOSE = 1,
|
||||
LEGACY_COVER_COMMAND_STOP = 2,
|
||||
};
|
||||
|
||||
class CoverCommandRequest : public APIMessage {
|
||||
public:
|
||||
bool decode_varint(uint32_t field_id, uint32_t value) override;
|
||||
bool decode_32bit(uint32_t field_id, uint32_t value) override;
|
||||
APIMessageType message_type() const override;
|
||||
uint32_t get_key() const;
|
||||
optional<LegacyCoverCommand> get_legacy_command() const;
|
||||
optional<float> get_position() const;
|
||||
optional<float> get_tilt() const;
|
||||
bool get_stop() const { return this->stop_; }
|
||||
|
||||
protected:
|
||||
uint32_t key_{0};
|
||||
bool has_legacy_command_{false};
|
||||
LegacyCoverCommand legacy_command_{LEGACY_COVER_COMMAND_OPEN};
|
||||
bool has_position_{false};
|
||||
float position_{0.0f};
|
||||
bool has_tilt_{false};
|
||||
float tilt_{0.0f};
|
||||
bool stop_{false};
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef USE_FAN
|
||||
class FanCommandRequest : public APIMessage {
|
||||
public:
|
||||
bool decode_varint(uint32_t field_id, uint32_t value) override;
|
||||
bool decode_32bit(uint32_t field_id, uint32_t value) override;
|
||||
APIMessageType message_type() const override;
|
||||
uint32_t get_key() const;
|
||||
optional<bool> get_state() const;
|
||||
optional<fan::FanSpeed> get_speed() const;
|
||||
optional<bool> get_oscillating() const;
|
||||
|
||||
protected:
|
||||
uint32_t key_{0};
|
||||
bool has_state_{false};
|
||||
bool state_{false};
|
||||
bool has_speed_{false};
|
||||
fan::FanSpeed speed_{fan::FAN_SPEED_LOW};
|
||||
bool has_oscillating_{false};
|
||||
bool oscillating_{false};
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef USE_LIGHT
|
||||
class LightCommandRequest : public APIMessage {
|
||||
public:
|
||||
bool decode_varint(uint32_t field_id, uint32_t value) override;
|
||||
bool decode_length_delimited(uint32_t field_id, const uint8_t *value, size_t len) override;
|
||||
bool decode_32bit(uint32_t field_id, uint32_t value) override;
|
||||
APIMessageType message_type() const override;
|
||||
uint32_t get_key() const;
|
||||
optional<bool> get_state() const;
|
||||
optional<float> get_brightness() const;
|
||||
optional<float> get_red() const;
|
||||
optional<float> get_green() const;
|
||||
optional<float> get_blue() const;
|
||||
optional<float> get_white() const;
|
||||
optional<float> get_color_temperature() const;
|
||||
optional<uint32_t> get_transition_length() const;
|
||||
optional<uint32_t> get_flash_length() const;
|
||||
optional<std::string> get_effect() const;
|
||||
|
||||
protected:
|
||||
uint32_t key_{0};
|
||||
bool has_state_{false};
|
||||
bool state_{false};
|
||||
bool has_brightness_{false};
|
||||
float brightness_{0.0f};
|
||||
bool has_rgb_{false};
|
||||
float red_{0.0f};
|
||||
float green_{0.0f};
|
||||
float blue_{0.0f};
|
||||
bool has_white_{false};
|
||||
float white_{0.0f};
|
||||
bool has_color_temperature_{false};
|
||||
float color_temperature_{0.0f};
|
||||
bool has_transition_length_{false};
|
||||
uint32_t transition_length_{0};
|
||||
bool has_flash_length_{false};
|
||||
uint32_t flash_length_{0};
|
||||
bool has_effect_{false};
|
||||
std::string effect_{};
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef USE_SWITCH
|
||||
class SwitchCommandRequest : public APIMessage {
|
||||
public:
|
||||
bool decode_varint(uint32_t field_id, uint32_t value) override;
|
||||
bool decode_32bit(uint32_t field_id, uint32_t value) override;
|
||||
APIMessageType message_type() const override;
|
||||
uint32_t get_key() const;
|
||||
bool get_state() const;
|
||||
|
||||
protected:
|
||||
uint32_t key_{0};
|
||||
bool state_{false};
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef USE_ESP32_CAMERA
|
||||
class CameraImageRequest : public APIMessage {
|
||||
public:
|
||||
bool decode_varint(uint32_t field_id, uint32_t value) override;
|
||||
bool get_single() const;
|
||||
bool get_stream() const;
|
||||
APIMessageType message_type() const override;
|
||||
|
||||
protected:
|
||||
bool single_{false};
|
||||
bool stream_{false};
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef USE_CLIMATE
|
||||
class ClimateCommandRequest : public APIMessage {
|
||||
public:
|
||||
bool decode_varint(uint32_t field_id, uint32_t value) override;
|
||||
bool decode_32bit(uint32_t field_id, uint32_t value) override;
|
||||
APIMessageType message_type() const override;
|
||||
uint32_t get_key() const;
|
||||
optional<climate::ClimateMode> get_mode() const;
|
||||
optional<float> get_target_temperature() const;
|
||||
optional<float> get_target_temperature_low() const;
|
||||
optional<float> get_target_temperature_high() const;
|
||||
optional<bool> get_away() const;
|
||||
|
||||
protected:
|
||||
uint32_t key_{0};
|
||||
bool has_mode_{false};
|
||||
climate::ClimateMode mode_{climate::CLIMATE_MODE_OFF};
|
||||
bool has_target_temperature_{false};
|
||||
float target_temperature_{0.0f};
|
||||
bool has_target_temperature_low_{false};
|
||||
float target_temperature_low_{0.0f};
|
||||
bool has_target_temperature_high_{false};
|
||||
float target_temperature_high_{0.0f};
|
||||
bool has_away_{false};
|
||||
bool away_{false};
|
||||
};
|
||||
#endif
|
||||
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
190
esphome/components/api/list_entities.cpp
Normal file
190
esphome/components/api/list_entities.cpp
Normal file
@@ -0,0 +1,190 @@
|
||||
#include "list_entities.h"
|
||||
#include "esphome/core/util.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/application.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
std::string get_default_unique_id(const std::string &component_type, Nameable *nameable) {
|
||||
return App.get_name() + component_type + nameable->get_object_id();
|
||||
}
|
||||
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
bool ListEntitiesIterator::on_binary_sensor(binary_sensor::BinarySensor *binary_sensor) {
|
||||
auto buffer = this->client_->get_buffer();
|
||||
buffer.encode_nameable(binary_sensor);
|
||||
// string unique_id = 4;
|
||||
buffer.encode_string(4, get_default_unique_id("binary_sensor", binary_sensor));
|
||||
// string device_class = 5;
|
||||
buffer.encode_string(5, binary_sensor->get_device_class());
|
||||
// bool is_status_binary_sensor = 6;
|
||||
buffer.encode_bool(6, binary_sensor->is_status_binary_sensor());
|
||||
return this->client_->send_buffer(APIMessageType::LIST_ENTITIES_BINARY_SENSOR_RESPONSE);
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_COVER
|
||||
bool ListEntitiesIterator::on_cover(cover::Cover *cover) {
|
||||
auto buffer = this->client_->get_buffer();
|
||||
buffer.encode_nameable(cover);
|
||||
// string unique_id = 4;
|
||||
buffer.encode_string(4, get_default_unique_id("cover", cover));
|
||||
auto traits = cover->get_traits();
|
||||
|
||||
// bool assumed_state = 5;
|
||||
buffer.encode_bool(5, traits.get_is_assumed_state());
|
||||
// bool supports_position = 6;
|
||||
buffer.encode_bool(6, traits.get_supports_position());
|
||||
// bool supports_tilt = 7;
|
||||
buffer.encode_bool(7, traits.get_supports_tilt());
|
||||
// string device_class = 8;
|
||||
buffer.encode_string(8, cover->get_device_class());
|
||||
return this->client_->send_buffer(APIMessageType::LIST_ENTITIES_COVER_RESPONSE);
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_FAN
|
||||
bool ListEntitiesIterator::on_fan(fan::FanState *fan) {
|
||||
auto buffer = this->client_->get_buffer();
|
||||
buffer.encode_nameable(fan);
|
||||
// string unique_id = 4;
|
||||
buffer.encode_string(4, get_default_unique_id("fan", fan));
|
||||
// bool supports_oscillation = 5;
|
||||
buffer.encode_bool(5, fan->get_traits().supports_oscillation());
|
||||
// bool supports_speed = 6;
|
||||
buffer.encode_bool(6, fan->get_traits().supports_speed());
|
||||
return this->client_->send_buffer(APIMessageType::LIST_ENTITIES_FAN_RESPONSE);
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_LIGHT
|
||||
bool ListEntitiesIterator::on_light(light::LightState *light) {
|
||||
auto buffer = this->client_->get_buffer();
|
||||
buffer.encode_nameable(light);
|
||||
// string unique_id = 4;
|
||||
buffer.encode_string(4, get_default_unique_id("light", light));
|
||||
// bool supports_brightness = 5;
|
||||
auto traits = light->get_traits();
|
||||
buffer.encode_bool(5, traits.get_supports_brightness());
|
||||
// bool supports_rgb = 6;
|
||||
buffer.encode_bool(6, traits.get_supports_rgb());
|
||||
// bool supports_white_value = 7;
|
||||
buffer.encode_bool(7, traits.get_supports_rgb_white_value());
|
||||
// bool supports_color_temperature = 8;
|
||||
buffer.encode_bool(8, traits.get_supports_color_temperature());
|
||||
if (traits.get_supports_color_temperature()) {
|
||||
// float min_mireds = 9;
|
||||
buffer.encode_float(9, traits.get_min_mireds());
|
||||
// float max_mireds = 10;
|
||||
buffer.encode_float(10, traits.get_max_mireds());
|
||||
}
|
||||
// repeated string effects = 11;
|
||||
if (light->supports_effects()) {
|
||||
buffer.encode_string(11, "None");
|
||||
for (auto *effect : light->get_effects()) {
|
||||
buffer.encode_string(11, effect->get_name());
|
||||
}
|
||||
}
|
||||
return this->client_->send_buffer(APIMessageType::LIST_ENTITIES_LIGHT_RESPONSE);
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_SENSOR
|
||||
bool ListEntitiesIterator::on_sensor(sensor::Sensor *sensor) {
|
||||
auto buffer = this->client_->get_buffer();
|
||||
buffer.encode_nameable(sensor);
|
||||
// string unique_id = 4;
|
||||
std::string unique_id = sensor->unique_id();
|
||||
if (unique_id.empty())
|
||||
unique_id = get_default_unique_id("sensor", sensor);
|
||||
buffer.encode_string(4, unique_id);
|
||||
// string icon = 5;
|
||||
buffer.encode_string(5, sensor->get_icon());
|
||||
// string unit_of_measurement = 6;
|
||||
buffer.encode_string(6, sensor->get_unit_of_measurement());
|
||||
// int32 accuracy_decimals = 7;
|
||||
buffer.encode_int32(7, sensor->get_accuracy_decimals());
|
||||
return this->client_->send_buffer(APIMessageType::LIST_ENTITIES_SENSOR_RESPONSE);
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_SWITCH
|
||||
bool ListEntitiesIterator::on_switch(switch_::Switch *a_switch) {
|
||||
auto buffer = this->client_->get_buffer();
|
||||
buffer.encode_nameable(a_switch);
|
||||
// string unique_id = 4;
|
||||
buffer.encode_string(4, get_default_unique_id("switch", a_switch));
|
||||
// string icon = 5;
|
||||
buffer.encode_string(5, a_switch->get_icon());
|
||||
// bool assumed_state = 6;
|
||||
buffer.encode_bool(6, a_switch->assumed_state());
|
||||
return this->client_->send_buffer(APIMessageType::LIST_ENTITIES_SWITCH_RESPONSE);
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
bool ListEntitiesIterator::on_text_sensor(text_sensor::TextSensor *text_sensor) {
|
||||
auto buffer = this->client_->get_buffer();
|
||||
buffer.encode_nameable(text_sensor);
|
||||
// string unique_id = 4;
|
||||
std::string unique_id = text_sensor->unique_id();
|
||||
if (unique_id.empty())
|
||||
unique_id = get_default_unique_id("text_sensor", text_sensor);
|
||||
buffer.encode_string(4, unique_id);
|
||||
// string icon = 5;
|
||||
buffer.encode_string(5, text_sensor->get_icon());
|
||||
return this->client_->send_buffer(APIMessageType::LIST_ENTITIES_TEXT_SENSOR_RESPONSE);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool ListEntitiesIterator::on_end() {
|
||||
return this->client_->send_empty_message(APIMessageType::LIST_ENTITIES_DONE_RESPONSE);
|
||||
}
|
||||
ListEntitiesIterator::ListEntitiesIterator(APIServer *server, APIConnection *client)
|
||||
: ComponentIterator(server), client_(client) {}
|
||||
bool ListEntitiesIterator::on_service(UserServiceDescriptor *service) {
|
||||
auto buffer = this->client_->get_buffer();
|
||||
service->encode_list_service_response(buffer);
|
||||
return this->client_->send_buffer(APIMessageType::LIST_ENTITIES_SERVICE_RESPONSE);
|
||||
}
|
||||
|
||||
#ifdef USE_ESP32_CAMERA
|
||||
bool ListEntitiesIterator::on_camera(esp32_camera::ESP32Camera *camera) {
|
||||
auto buffer = this->client_->get_buffer();
|
||||
buffer.encode_nameable(camera);
|
||||
// string unique_id = 4;
|
||||
buffer.encode_string(4, get_default_unique_id("camera", camera));
|
||||
return this->client_->send_buffer(APIMessageType::LIST_ENTITIES_CAMERA_RESPONSE);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_CLIMATE
|
||||
bool ListEntitiesIterator::on_climate(climate::Climate *climate) {
|
||||
auto buffer = this->client_->get_buffer();
|
||||
buffer.encode_nameable(climate);
|
||||
// string unique_id = 4;
|
||||
buffer.encode_string(4, get_default_unique_id("climate", climate));
|
||||
|
||||
auto traits = climate->get_traits();
|
||||
// bool supports_current_temperature = 5;
|
||||
buffer.encode_bool(5, traits.get_supports_current_temperature());
|
||||
// bool supports_two_point_target_temperature = 6;
|
||||
buffer.encode_bool(6, traits.get_supports_two_point_target_temperature());
|
||||
// repeated ClimateMode supported_modes = 7;
|
||||
for (auto mode : {climate::CLIMATE_MODE_AUTO, climate::CLIMATE_MODE_OFF, climate::CLIMATE_MODE_COOL,
|
||||
climate::CLIMATE_MODE_HEAT}) {
|
||||
if (traits.supports_mode(mode))
|
||||
buffer.encode_uint32(7, mode, true);
|
||||
}
|
||||
|
||||
// float visual_min_temperature = 8;
|
||||
buffer.encode_float(8, traits.get_visual_min_temperature());
|
||||
// float visual_max_temperature = 9;
|
||||
buffer.encode_float(9, traits.get_visual_max_temperature());
|
||||
// float visual_temperature_step = 10;
|
||||
buffer.encode_float(10, traits.get_visual_temperature_step());
|
||||
// bool supports_away = 11;
|
||||
buffer.encode_bool(11, traits.get_supports_away());
|
||||
return this->client_->send_buffer(APIMessageType::LIST_ENTITIES_CLIMATE_RESPONSE);
|
||||
}
|
||||
#endif
|
||||
|
||||
APIMessageType ListEntitiesRequest::message_type() const { return APIMessageType::LIST_ENTITIES_REQUEST; }
|
||||
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
57
esphome/components/api/list_entities.h
Normal file
57
esphome/components/api/list_entities.h
Normal file
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "api_message.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
class ListEntitiesRequest : public APIMessage {
|
||||
public:
|
||||
APIMessageType message_type() const override;
|
||||
};
|
||||
|
||||
class APIConnection;
|
||||
|
||||
class ListEntitiesIterator : public ComponentIterator {
|
||||
public:
|
||||
ListEntitiesIterator(APIServer *server, APIConnection *client);
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
bool on_binary_sensor(binary_sensor::BinarySensor *binary_sensor) override;
|
||||
#endif
|
||||
#ifdef USE_COVER
|
||||
bool on_cover(cover::Cover *cover) override;
|
||||
#endif
|
||||
#ifdef USE_FAN
|
||||
bool on_fan(fan::FanState *fan) override;
|
||||
#endif
|
||||
#ifdef USE_LIGHT
|
||||
bool on_light(light::LightState *light) override;
|
||||
#endif
|
||||
#ifdef USE_SENSOR
|
||||
bool on_sensor(sensor::Sensor *sensor) override;
|
||||
#endif
|
||||
#ifdef USE_SWITCH
|
||||
bool on_switch(switch_::Switch *a_switch) override;
|
||||
#endif
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
bool on_text_sensor(text_sensor::TextSensor *text_sensor) override;
|
||||
#endif
|
||||
bool on_service(UserServiceDescriptor *service) override;
|
||||
#ifdef USE_ESP32_CAMERA
|
||||
bool on_camera(esp32_camera::ESP32Camera *camera) override;
|
||||
#endif
|
||||
#ifdef USE_CLIMATE
|
||||
bool on_climate(climate::Climate *climate) override;
|
||||
#endif
|
||||
bool on_end() override;
|
||||
|
||||
protected:
|
||||
APIConnection *client_;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
|
||||
#include "api_server.h"
|
||||
49
esphome/components/api/service_call_message.cpp
Normal file
49
esphome/components/api/service_call_message.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
#include "service_call_message.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
APIMessageType SubscribeServiceCallsRequest::message_type() const {
|
||||
return APIMessageType::SUBSCRIBE_SERVICE_CALLS_REQUEST;
|
||||
}
|
||||
|
||||
APIMessageType ServiceCallResponse::message_type() const { return APIMessageType::SERVICE_CALL_RESPONSE; }
|
||||
void ServiceCallResponse::encode(APIBuffer &buffer) {
|
||||
// string service = 1;
|
||||
buffer.encode_string(1, this->service_);
|
||||
// map<string, string> data = 2;
|
||||
for (auto &it : this->data_) {
|
||||
auto nested = buffer.begin_nested(2);
|
||||
buffer.encode_string(1, it.key);
|
||||
buffer.encode_string(2, it.value);
|
||||
buffer.end_nested(nested);
|
||||
}
|
||||
// map<string, string> data_template = 3;
|
||||
for (auto &it : this->data_template_) {
|
||||
auto nested = buffer.begin_nested(3);
|
||||
buffer.encode_string(1, it.key);
|
||||
buffer.encode_string(2, it.value);
|
||||
buffer.end_nested(nested);
|
||||
}
|
||||
// map<string, string> variables = 4;
|
||||
for (auto &it : this->variables_) {
|
||||
auto nested = buffer.begin_nested(4);
|
||||
buffer.encode_string(1, it.key);
|
||||
buffer.encode_string(2, it.value());
|
||||
buffer.end_nested(nested);
|
||||
}
|
||||
}
|
||||
void ServiceCallResponse::set_service(const std::string &service) { this->service_ = service; }
|
||||
void ServiceCallResponse::set_data(const std::vector<KeyValuePair> &data) { this->data_ = data; }
|
||||
void ServiceCallResponse::set_data_template(const std::vector<KeyValuePair> &data_template) {
|
||||
this->data_template_ = data_template;
|
||||
}
|
||||
void ServiceCallResponse::set_variables(const std::vector<TemplatableKeyValuePair> &variables) {
|
||||
this->variables_ = variables;
|
||||
}
|
||||
|
||||
KeyValuePair::KeyValuePair(const std::string &key, const std::string &value) : key(key), value(value) {}
|
||||
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
53
esphome/components/api/service_call_message.h
Normal file
53
esphome/components/api/service_call_message.h
Normal file
@@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "api_message.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
class SubscribeServiceCallsRequest : public APIMessage {
|
||||
public:
|
||||
APIMessageType message_type() const override;
|
||||
};
|
||||
|
||||
class KeyValuePair {
|
||||
public:
|
||||
KeyValuePair(const std::string &key, const std::string &value);
|
||||
|
||||
std::string key;
|
||||
std::string value;
|
||||
};
|
||||
|
||||
class TemplatableKeyValuePair {
|
||||
public:
|
||||
template<typename T> TemplatableKeyValuePair(std::string key, T func);
|
||||
|
||||
std::string key;
|
||||
std::function<std::string()> value;
|
||||
};
|
||||
template<typename T> TemplatableKeyValuePair::TemplatableKeyValuePair(std::string key, T func) : key(key) {
|
||||
this->value = [func]() -> std::string { return to_string(func()); };
|
||||
}
|
||||
|
||||
class ServiceCallResponse : public APIMessage {
|
||||
public:
|
||||
APIMessageType message_type() const override;
|
||||
|
||||
void encode(APIBuffer &buffer) override;
|
||||
|
||||
void set_service(const std::string &service);
|
||||
void set_data(const std::vector<KeyValuePair> &data);
|
||||
void set_data_template(const std::vector<KeyValuePair> &data_template);
|
||||
void set_variables(const std::vector<TemplatableKeyValuePair> &variables);
|
||||
|
||||
protected:
|
||||
std::string service_;
|
||||
std::vector<KeyValuePair> data_;
|
||||
std::vector<KeyValuePair> data_template_;
|
||||
std::vector<TemplatableKeyValuePair> variables_;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
26
esphome/components/api/subscribe_logs.cpp
Normal file
26
esphome/components/api/subscribe_logs.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#include "subscribe_logs.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
APIMessageType SubscribeLogsRequest::message_type() const { return APIMessageType::SUBSCRIBE_LOGS_REQUEST; }
|
||||
bool SubscribeLogsRequest::decode_varint(uint32_t field_id, uint32_t value) {
|
||||
switch (field_id) {
|
||||
case 1: // LogLevel level = 1;
|
||||
this->level_ = value;
|
||||
return true;
|
||||
case 2: // bool dump_config = 2;
|
||||
this->dump_config_ = value;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
uint32_t SubscribeLogsRequest::get_level() const { return this->level_; }
|
||||
void SubscribeLogsRequest::set_level(uint32_t level) { this->level_ = level; }
|
||||
bool SubscribeLogsRequest::get_dump_config() const { return this->dump_config_; }
|
||||
void SubscribeLogsRequest::set_dump_config(bool dump_config) { this->dump_config_ = dump_config; }
|
||||
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
24
esphome/components/api/subscribe_logs.h
Normal file
24
esphome/components/api/subscribe_logs.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "api_message.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
class SubscribeLogsRequest : public APIMessage {
|
||||
public:
|
||||
bool decode_varint(uint32_t field_id, uint32_t value) override;
|
||||
APIMessageType message_type() const override;
|
||||
uint32_t get_level() const;
|
||||
void set_level(uint32_t level);
|
||||
bool get_dump_config() const;
|
||||
void set_dump_config(bool dump_config);
|
||||
|
||||
protected:
|
||||
uint32_t level_{6};
|
||||
bool dump_config_{false};
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
77
esphome/components/api/subscribe_state.cpp
Normal file
77
esphome/components/api/subscribe_state.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
#include "subscribe_state.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
bool InitialStateIterator::on_binary_sensor(binary_sensor::BinarySensor *binary_sensor) {
|
||||
if (!binary_sensor->has_state())
|
||||
return true;
|
||||
|
||||
return this->client_->send_binary_sensor_state(binary_sensor, binary_sensor->state);
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_COVER
|
||||
bool InitialStateIterator::on_cover(cover::Cover *cover) { return this->client_->send_cover_state(cover); }
|
||||
#endif
|
||||
#ifdef USE_FAN
|
||||
bool InitialStateIterator::on_fan(fan::FanState *fan) { return this->client_->send_fan_state(fan); }
|
||||
#endif
|
||||
#ifdef USE_LIGHT
|
||||
bool InitialStateIterator::on_light(light::LightState *light) { return this->client_->send_light_state(light); }
|
||||
#endif
|
||||
#ifdef USE_SENSOR
|
||||
bool InitialStateIterator::on_sensor(sensor::Sensor *sensor) {
|
||||
if (!sensor->has_state())
|
||||
return true;
|
||||
|
||||
return this->client_->send_sensor_state(sensor, sensor->state);
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_SWITCH
|
||||
bool InitialStateIterator::on_switch(switch_::Switch *a_switch) {
|
||||
return this->client_->send_switch_state(a_switch, a_switch->state);
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
bool InitialStateIterator::on_text_sensor(text_sensor::TextSensor *text_sensor) {
|
||||
if (!text_sensor->has_state())
|
||||
return true;
|
||||
|
||||
return this->client_->send_text_sensor_state(text_sensor, text_sensor->state);
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_CLIMATE
|
||||
bool InitialStateIterator::on_climate(climate::Climate *climate) { return this->client_->send_climate_state(climate); }
|
||||
#endif
|
||||
InitialStateIterator::InitialStateIterator(APIServer *server, APIConnection *client)
|
||||
: ComponentIterator(server), client_(client) {}
|
||||
|
||||
APIMessageType SubscribeStatesRequest::message_type() const { return APIMessageType::SUBSCRIBE_STATES_REQUEST; }
|
||||
|
||||
bool HomeAssistantStateResponse::decode_length_delimited(uint32_t field_id, const uint8_t *value, size_t len) {
|
||||
switch (field_id) {
|
||||
case 1:
|
||||
// string entity_id = 1;
|
||||
this->entity_id_ = as_string(value, len);
|
||||
return true;
|
||||
case 2:
|
||||
// string state = 2;
|
||||
this->state_ = as_string(value, len);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
APIMessageType HomeAssistantStateResponse::message_type() const {
|
||||
return APIMessageType::HOME_ASSISTANT_STATE_RESPONSE;
|
||||
}
|
||||
const std::string &HomeAssistantStateResponse::get_entity_id() const { return this->entity_id_; }
|
||||
const std::string &HomeAssistantStateResponse::get_state() const { return this->state_; }
|
||||
APIMessageType SubscribeHomeAssistantStatesRequest::message_type() const {
|
||||
return APIMessageType::SUBSCRIBE_HOME_ASSISTANT_STATES_REQUEST;
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
70
esphome/components/api/subscribe_state.h
Normal file
70
esphome/components/api/subscribe_state.h
Normal file
@@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/controller.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "util.h"
|
||||
#include "api_message.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
class SubscribeStatesRequest : public APIMessage {
|
||||
public:
|
||||
APIMessageType message_type() const override;
|
||||
};
|
||||
|
||||
class APIConnection;
|
||||
|
||||
class InitialStateIterator : public ComponentIterator {
|
||||
public:
|
||||
InitialStateIterator(APIServer *server, APIConnection *client);
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
bool on_binary_sensor(binary_sensor::BinarySensor *binary_sensor) override;
|
||||
#endif
|
||||
#ifdef USE_COVER
|
||||
bool on_cover(cover::Cover *cover) override;
|
||||
#endif
|
||||
#ifdef USE_FAN
|
||||
bool on_fan(fan::FanState *fan) override;
|
||||
#endif
|
||||
#ifdef USE_LIGHT
|
||||
bool on_light(light::LightState *light) override;
|
||||
#endif
|
||||
#ifdef USE_SENSOR
|
||||
bool on_sensor(sensor::Sensor *sensor) override;
|
||||
#endif
|
||||
#ifdef USE_SWITCH
|
||||
bool on_switch(switch_::Switch *a_switch) override;
|
||||
#endif
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
bool on_text_sensor(text_sensor::TextSensor *text_sensor) override;
|
||||
#endif
|
||||
#ifdef USE_CLIMATE
|
||||
bool on_climate(climate::Climate *climate) override;
|
||||
#endif
|
||||
protected:
|
||||
APIConnection *client_;
|
||||
};
|
||||
|
||||
class SubscribeHomeAssistantStatesRequest : public APIMessage {
|
||||
public:
|
||||
APIMessageType message_type() const override;
|
||||
};
|
||||
|
||||
class HomeAssistantStateResponse : public APIMessage {
|
||||
public:
|
||||
bool decode_length_delimited(uint32_t field_id, const uint8_t *value, size_t len) override;
|
||||
APIMessageType message_type() const override;
|
||||
const std::string &get_entity_id() const;
|
||||
const std::string &get_state() const;
|
||||
|
||||
protected:
|
||||
std::string entity_id_;
|
||||
std::string state_;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
|
||||
#include "api_server.h"
|
||||
74
esphome/components/api/user_services.cpp
Normal file
74
esphome/components/api/user_services.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
#include "user_services.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
template<> bool ExecuteServiceArgument::get_value<bool>() { return this->value_bool_; }
|
||||
template<> int ExecuteServiceArgument::get_value<int>() { return this->value_int_; }
|
||||
template<> float ExecuteServiceArgument::get_value<float>() { return this->value_float_; }
|
||||
template<> std::string ExecuteServiceArgument::get_value<std::string>() { return this->value_string_; }
|
||||
|
||||
APIMessageType ExecuteServiceArgument::message_type() const { return APIMessageType::EXECUTE_SERVICE_REQUEST; }
|
||||
bool ExecuteServiceArgument::decode_varint(uint32_t field_id, uint32_t value) {
|
||||
switch (field_id) {
|
||||
case 1: // bool bool_ = 1;
|
||||
this->value_bool_ = value;
|
||||
return true;
|
||||
case 2: // int32 int_ = 2;
|
||||
this->value_int_ = value;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool ExecuteServiceArgument::decode_32bit(uint32_t field_id, uint32_t value) {
|
||||
switch (field_id) {
|
||||
case 3: // float float_ = 3;
|
||||
this->value_float_ = as_float(value);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool ExecuteServiceArgument::decode_length_delimited(uint32_t field_id, const uint8_t *value, size_t len) {
|
||||
switch (field_id) {
|
||||
case 4: // string string_ = 4;
|
||||
this->value_string_ = as_string(value, len);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ExecuteServiceRequest::decode_32bit(uint32_t field_id, uint32_t value) {
|
||||
switch (field_id) {
|
||||
case 1: // fixed32 key = 1;
|
||||
this->key_ = value;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool ExecuteServiceRequest::decode_length_delimited(uint32_t field_id, const uint8_t *value, size_t len) {
|
||||
switch (field_id) {
|
||||
case 2: { // repeated ExecuteServiceArgument args = 2;
|
||||
ExecuteServiceArgument arg;
|
||||
arg.decode(value, len);
|
||||
this->args_.push_back(arg);
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
APIMessageType ExecuteServiceRequest::message_type() const { return APIMessageType::EXECUTE_SERVICE_REQUEST; }
|
||||
const std::vector<ExecuteServiceArgument> &ExecuteServiceRequest::get_args() const { return this->args_; }
|
||||
uint32_t ExecuteServiceRequest::get_key() const { return this->key_; }
|
||||
|
||||
ServiceTypeArgument::ServiceTypeArgument(const std::string &name, ServiceArgType type) : name_(name), type_(type) {}
|
||||
const std::string &ServiceTypeArgument::get_name() const { return this->name_; }
|
||||
ServiceArgType ServiceTypeArgument::get_type() const { return this->type_; }
|
||||
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
125
esphome/components/api/user_services.h
Normal file
125
esphome/components/api/user_services.h
Normal file
@@ -0,0 +1,125 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "api_message.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
enum ServiceArgType {
|
||||
SERVICE_ARG_TYPE_BOOL = 0,
|
||||
SERVICE_ARG_TYPE_INT = 1,
|
||||
SERVICE_ARG_TYPE_FLOAT = 2,
|
||||
SERVICE_ARG_TYPE_STRING = 3,
|
||||
};
|
||||
|
||||
class ServiceTypeArgument {
|
||||
public:
|
||||
ServiceTypeArgument(const std::string &name, ServiceArgType type);
|
||||
const std::string &get_name() const;
|
||||
ServiceArgType get_type() const;
|
||||
|
||||
protected:
|
||||
std::string name_;
|
||||
ServiceArgType type_;
|
||||
};
|
||||
|
||||
class ExecuteServiceArgument : public APIMessage {
|
||||
public:
|
||||
APIMessageType message_type() const override;
|
||||
template<typename T> T get_value();
|
||||
|
||||
bool decode_varint(uint32_t field_id, uint32_t value) override;
|
||||
bool decode_length_delimited(uint32_t field_id, const uint8_t *value, size_t len) override;
|
||||
bool decode_32bit(uint32_t field_id, uint32_t value) override;
|
||||
|
||||
protected:
|
||||
bool value_bool_{false};
|
||||
int value_int_{0};
|
||||
float value_float_{0.0f};
|
||||
std::string value_string_{};
|
||||
};
|
||||
|
||||
class ExecuteServiceRequest : public APIMessage {
|
||||
public:
|
||||
bool decode_length_delimited(uint32_t field_id, const uint8_t *value, size_t len) override;
|
||||
bool decode_32bit(uint32_t field_id, uint32_t value) override;
|
||||
APIMessageType message_type() const override;
|
||||
|
||||
uint32_t get_key() const;
|
||||
const std::vector<ExecuteServiceArgument> &get_args() const;
|
||||
|
||||
protected:
|
||||
uint32_t key_;
|
||||
std::vector<ExecuteServiceArgument> args_;
|
||||
};
|
||||
|
||||
class UserServiceDescriptor {
|
||||
public:
|
||||
virtual void encode_list_service_response(APIBuffer &buffer) = 0;
|
||||
|
||||
virtual bool execute_service(const ExecuteServiceRequest &req) = 0;
|
||||
};
|
||||
|
||||
template<typename... Ts> class UserService : public UserServiceDescriptor, public Trigger<Ts...> {
|
||||
public:
|
||||
UserService(const std::string &name, const std::array<ServiceTypeArgument, sizeof...(Ts)> &args);
|
||||
|
||||
void encode_list_service_response(APIBuffer &buffer) override;
|
||||
|
||||
bool execute_service(const ExecuteServiceRequest &req) override;
|
||||
|
||||
protected:
|
||||
template<int... S> void execute_(std::vector<ExecuteServiceArgument> args, seq<S...>);
|
||||
|
||||
std::string name_;
|
||||
uint32_t key_{0};
|
||||
std::array<ServiceTypeArgument, sizeof...(Ts)> args_;
|
||||
};
|
||||
|
||||
template<typename... Ts>
|
||||
template<int... S>
|
||||
void UserService<Ts...>::execute_(std::vector<ExecuteServiceArgument> args, seq<S...>) {
|
||||
this->trigger((args[S].get_value<Ts>())...);
|
||||
}
|
||||
template<typename... Ts> void UserService<Ts...>::encode_list_service_response(APIBuffer &buffer) {
|
||||
// string name = 1;
|
||||
buffer.encode_string(1, this->name_);
|
||||
// fixed32 key = 2;
|
||||
buffer.encode_fixed32(2, this->key_);
|
||||
|
||||
// repeated ListServicesArgument args = 3;
|
||||
for (auto &arg : this->args_) {
|
||||
auto nested = buffer.begin_nested(3);
|
||||
// string name = 1;
|
||||
buffer.encode_string(1, arg.get_name());
|
||||
// Type type = 2;
|
||||
buffer.encode_int32(2, arg.get_type());
|
||||
buffer.end_nested(nested);
|
||||
}
|
||||
}
|
||||
template<typename... Ts> bool UserService<Ts...>::execute_service(const ExecuteServiceRequest &req) {
|
||||
if (req.get_key() != this->key_)
|
||||
return false;
|
||||
|
||||
if (req.get_args().size() != this->args_.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this->execute_(req.get_args(), typename gens<sizeof...(Ts)>::type());
|
||||
return true;
|
||||
}
|
||||
template<typename... Ts>
|
||||
UserService<Ts...>::UserService(const std::string &name, const std::array<ServiceTypeArgument, sizeof...(Ts)> &args)
|
||||
: name_(name), args_(args) {
|
||||
this->key_ = fnv1_hash(this->name_);
|
||||
}
|
||||
|
||||
template<> bool ExecuteServiceArgument::get_value<bool>();
|
||||
template<> int ExecuteServiceArgument::get_value<int>();
|
||||
template<> float ExecuteServiceArgument::get_value<float>();
|
||||
template<> std::string ExecuteServiceArgument::get_value<std::string>();
|
||||
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
353
esphome/components/api/util.cpp
Normal file
353
esphome/components/api/util.cpp
Normal file
@@ -0,0 +1,353 @@
|
||||
#include "util.h"
|
||||
#include "api_server.h"
|
||||
#include "user_services.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/application.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
APIBuffer::APIBuffer(std::vector<uint8_t> *buffer) : buffer_(buffer) {}
|
||||
size_t APIBuffer::get_length() const { return this->buffer_->size(); }
|
||||
void APIBuffer::write(uint8_t value) { this->buffer_->push_back(value); }
|
||||
void APIBuffer::encode_uint32(uint32_t field, uint32_t value, bool force) {
|
||||
if (value == 0 && !force)
|
||||
return;
|
||||
|
||||
this->encode_field_raw(field, 0);
|
||||
this->encode_varint_raw(value);
|
||||
}
|
||||
void APIBuffer::encode_int32(uint32_t field, int32_t value, bool force) {
|
||||
this->encode_uint32(field, static_cast<uint32_t>(value), force);
|
||||
}
|
||||
void APIBuffer::encode_bool(uint32_t field, bool value, bool force) {
|
||||
if (!value && !force)
|
||||
return;
|
||||
|
||||
this->encode_field_raw(field, 0);
|
||||
this->write(0x01);
|
||||
}
|
||||
void APIBuffer::encode_string(uint32_t field, const std::string &value) {
|
||||
this->encode_string(field, value.data(), value.size());
|
||||
}
|
||||
void APIBuffer::encode_bytes(uint32_t field, const uint8_t *data, size_t len) {
|
||||
this->encode_string(field, reinterpret_cast<const char *>(data), len);
|
||||
}
|
||||
void APIBuffer::encode_string(uint32_t field, const char *string, size_t len) {
|
||||
if (len == 0)
|
||||
return;
|
||||
|
||||
this->encode_field_raw(field, 2);
|
||||
this->encode_varint_raw(len);
|
||||
const uint8_t *data = reinterpret_cast<const uint8_t *>(string);
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
this->write(data[i]);
|
||||
}
|
||||
}
|
||||
void APIBuffer::encode_fixed32(uint32_t field, uint32_t value, bool force) {
|
||||
if (value == 0 && !force)
|
||||
return;
|
||||
|
||||
this->encode_field_raw(field, 5);
|
||||
this->write((value >> 0) & 0xFF);
|
||||
this->write((value >> 8) & 0xFF);
|
||||
this->write((value >> 16) & 0xFF);
|
||||
this->write((value >> 24) & 0xFF);
|
||||
}
|
||||
void APIBuffer::encode_float(uint32_t field, float value, bool force) {
|
||||
if (value == 0.0f && !force)
|
||||
return;
|
||||
|
||||
union {
|
||||
float value_f;
|
||||
uint32_t value_raw;
|
||||
} val;
|
||||
val.value_f = value;
|
||||
this->encode_fixed32(field, val.value_raw);
|
||||
}
|
||||
void APIBuffer::encode_field_raw(uint32_t field, uint32_t type) {
|
||||
uint32_t val = (field << 3) | (type & 0b111);
|
||||
this->encode_varint_raw(val);
|
||||
}
|
||||
void APIBuffer::encode_varint_raw(uint32_t value) {
|
||||
if (value <= 0x7F) {
|
||||
this->write(value);
|
||||
return;
|
||||
}
|
||||
|
||||
while (value) {
|
||||
uint8_t temp = value & 0x7F;
|
||||
value >>= 7;
|
||||
if (value) {
|
||||
this->write(temp | 0x80);
|
||||
} else {
|
||||
this->write(temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
void APIBuffer::encode_sint32(uint32_t field, int32_t value, bool force) {
|
||||
if (value < 0)
|
||||
this->encode_uint32(field, ~(uint32_t(value) << 1), force);
|
||||
else
|
||||
this->encode_uint32(field, uint32_t(value) << 1, force);
|
||||
}
|
||||
void APIBuffer::encode_nameable(Nameable *nameable) {
|
||||
// string object_id = 1;
|
||||
this->encode_string(1, nameable->get_object_id());
|
||||
// fixed32 key = 2;
|
||||
this->encode_fixed32(2, nameable->get_object_id_hash());
|
||||
// string name = 3;
|
||||
this->encode_string(3, nameable->get_name());
|
||||
}
|
||||
size_t APIBuffer::begin_nested(uint32_t field) {
|
||||
this->encode_field_raw(field, 2);
|
||||
return this->buffer_->size();
|
||||
}
|
||||
void APIBuffer::end_nested(size_t begin_index) {
|
||||
const uint32_t nested_length = this->buffer_->size() - begin_index;
|
||||
// add varint
|
||||
std::vector<uint8_t> var;
|
||||
uint32_t val = nested_length;
|
||||
if (val <= 0x7F) {
|
||||
var.push_back(val);
|
||||
} else {
|
||||
while (val) {
|
||||
uint8_t temp = val & 0x7F;
|
||||
val >>= 7;
|
||||
if (val) {
|
||||
var.push_back(temp | 0x80);
|
||||
} else {
|
||||
var.push_back(temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
this->buffer_->insert(this->buffer_->begin() + begin_index, var.begin(), var.end());
|
||||
}
|
||||
|
||||
optional<uint32_t> proto_decode_varuint32(const uint8_t *buf, size_t len, uint32_t *consumed) {
|
||||
if (len == 0)
|
||||
return {};
|
||||
|
||||
uint32_t result = 0;
|
||||
uint8_t bitpos = 0;
|
||||
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
uint8_t val = buf[i];
|
||||
result |= uint32_t(val & 0x7F) << bitpos;
|
||||
bitpos += 7;
|
||||
if ((val & 0x80) == 0) {
|
||||
if (consumed != nullptr) {
|
||||
*consumed = i + 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string as_string(const uint8_t *value, size_t len) {
|
||||
return std::string(reinterpret_cast<const char *>(value), len);
|
||||
}
|
||||
|
||||
int32_t as_sint32(uint32_t val) {
|
||||
if (val & 1)
|
||||
return uint32_t(~(val >> 1));
|
||||
else
|
||||
return uint32_t(val >> 1);
|
||||
}
|
||||
|
||||
float as_float(uint32_t val) {
|
||||
static_assert(sizeof(uint32_t) == sizeof(float), "float must be 32bit long");
|
||||
union {
|
||||
uint32_t raw;
|
||||
float value;
|
||||
} x;
|
||||
x.raw = val;
|
||||
return x.value;
|
||||
}
|
||||
|
||||
ComponentIterator::ComponentIterator(APIServer *server) : server_(server) {}
|
||||
void ComponentIterator::begin() {
|
||||
this->state_ = IteratorState::BEGIN;
|
||||
this->at_ = 0;
|
||||
}
|
||||
void ComponentIterator::advance() {
|
||||
bool advance_platform = false;
|
||||
bool success = true;
|
||||
switch (this->state_) {
|
||||
case IteratorState::NONE:
|
||||
// not started
|
||||
return;
|
||||
case IteratorState::BEGIN:
|
||||
if (this->on_begin()) {
|
||||
advance_platform = true;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
case IteratorState::BINARY_SENSOR:
|
||||
if (this->at_ >= App.get_binary_sensors().size()) {
|
||||
advance_platform = true;
|
||||
} else {
|
||||
auto *binary_sensor = App.get_binary_sensors()[this->at_];
|
||||
if (binary_sensor->is_internal()) {
|
||||
success = true;
|
||||
break;
|
||||
} else {
|
||||
success = this->on_binary_sensor(binary_sensor);
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_COVER
|
||||
case IteratorState::COVER:
|
||||
if (this->at_ >= App.get_covers().size()) {
|
||||
advance_platform = true;
|
||||
} else {
|
||||
auto *cover = App.get_covers()[this->at_];
|
||||
if (cover->is_internal()) {
|
||||
success = true;
|
||||
break;
|
||||
} else {
|
||||
success = this->on_cover(cover);
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_FAN
|
||||
case IteratorState::FAN:
|
||||
if (this->at_ >= App.get_fans().size()) {
|
||||
advance_platform = true;
|
||||
} else {
|
||||
auto *fan = App.get_fans()[this->at_];
|
||||
if (fan->is_internal()) {
|
||||
success = true;
|
||||
break;
|
||||
} else {
|
||||
success = this->on_fan(fan);
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_LIGHT
|
||||
case IteratorState::LIGHT:
|
||||
if (this->at_ >= App.get_lights().size()) {
|
||||
advance_platform = true;
|
||||
} else {
|
||||
auto *light = App.get_lights()[this->at_];
|
||||
if (light->is_internal()) {
|
||||
success = true;
|
||||
break;
|
||||
} else {
|
||||
success = this->on_light(light);
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_SENSOR
|
||||
case IteratorState::SENSOR:
|
||||
if (this->at_ >= App.get_sensors().size()) {
|
||||
advance_platform = true;
|
||||
} else {
|
||||
auto *sensor = App.get_sensors()[this->at_];
|
||||
if (sensor->is_internal()) {
|
||||
success = true;
|
||||
break;
|
||||
} else {
|
||||
success = this->on_sensor(sensor);
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_SWITCH
|
||||
case IteratorState::SWITCH:
|
||||
if (this->at_ >= App.get_switches().size()) {
|
||||
advance_platform = true;
|
||||
} else {
|
||||
auto *a_switch = App.get_switches()[this->at_];
|
||||
if (a_switch->is_internal()) {
|
||||
success = true;
|
||||
break;
|
||||
} else {
|
||||
success = this->on_switch(a_switch);
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
case IteratorState::TEXT_SENSOR:
|
||||
if (this->at_ >= App.get_text_sensors().size()) {
|
||||
advance_platform = true;
|
||||
} else {
|
||||
auto *text_sensor = App.get_text_sensors()[this->at_];
|
||||
if (text_sensor->is_internal()) {
|
||||
success = true;
|
||||
break;
|
||||
} else {
|
||||
success = this->on_text_sensor(text_sensor);
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case IteratorState ::SERVICE:
|
||||
if (this->at_ >= this->server_->get_user_services().size()) {
|
||||
advance_platform = true;
|
||||
} else {
|
||||
auto *service = this->server_->get_user_services()[this->at_];
|
||||
success = this->on_service(service);
|
||||
}
|
||||
break;
|
||||
#ifdef USE_ESP32_CAMERA
|
||||
case IteratorState::CAMERA:
|
||||
if (esp32_camera::global_esp32_camera == nullptr) {
|
||||
advance_platform = true;
|
||||
} else {
|
||||
if (esp32_camera::global_esp32_camera->is_internal()) {
|
||||
advance_platform = success = true;
|
||||
break;
|
||||
} else {
|
||||
advance_platform = success = this->on_camera(esp32_camera::global_esp32_camera);
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_CLIMATE
|
||||
case IteratorState::CLIMATE:
|
||||
if (this->at_ >= App.get_climates().size()) {
|
||||
advance_platform = true;
|
||||
} else {
|
||||
auto *climate = App.get_climates()[this->at_];
|
||||
if (climate->is_internal()) {
|
||||
success = true;
|
||||
break;
|
||||
} else {
|
||||
success = this->on_climate(climate);
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case IteratorState::MAX:
|
||||
if (this->on_end()) {
|
||||
this->state_ = IteratorState::NONE;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (advance_platform) {
|
||||
this->state_ = static_cast<IteratorState>(static_cast<uint32_t>(this->state_) + 1);
|
||||
this->at_ = 0;
|
||||
} else if (success) {
|
||||
this->at_++;
|
||||
}
|
||||
}
|
||||
bool ComponentIterator::on_end() { return true; }
|
||||
bool ComponentIterator::on_begin() { return true; }
|
||||
bool ComponentIterator::on_service(UserServiceDescriptor *service) { return true; }
|
||||
#ifdef USE_ESP32_CAMERA
|
||||
bool ComponentIterator::on_camera(esp32_camera::ESP32Camera *camera) { return true; }
|
||||
#endif
|
||||
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
127
esphome/components/api/util.h
Normal file
127
esphome/components/api/util.h
Normal file
@@ -0,0 +1,127 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/controller.h"
|
||||
#ifdef USE_ESP32_CAMERA
|
||||
#include "esphome/components/esp32_camera/esp32_camera.h"
|
||||
#endif
|
||||
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
class APIBuffer {
|
||||
public:
|
||||
APIBuffer(std::vector<uint8_t> *buffer);
|
||||
|
||||
size_t get_length() const;
|
||||
void write(uint8_t value);
|
||||
|
||||
void encode_int32(uint32_t field, int32_t value, bool force = false);
|
||||
void encode_uint32(uint32_t field, uint32_t value, bool force = false);
|
||||
void encode_sint32(uint32_t field, int32_t value, bool force = false);
|
||||
void encode_bool(uint32_t field, bool value, bool force = false);
|
||||
void encode_string(uint32_t field, const std::string &value);
|
||||
void encode_string(uint32_t field, const char *string, size_t len);
|
||||
void encode_bytes(uint32_t field, const uint8_t *data, size_t len);
|
||||
void encode_fixed32(uint32_t field, uint32_t value, bool force = false);
|
||||
void encode_float(uint32_t field, float value, bool force = false);
|
||||
void encode_nameable(Nameable *nameable);
|
||||
|
||||
size_t begin_nested(uint32_t field);
|
||||
void end_nested(size_t begin_index);
|
||||
|
||||
void encode_field_raw(uint32_t field, uint32_t type);
|
||||
void encode_varint_raw(uint32_t value);
|
||||
|
||||
protected:
|
||||
std::vector<uint8_t> *buffer_;
|
||||
};
|
||||
|
||||
optional<uint32_t> proto_decode_varuint32(const uint8_t *buf, size_t len, uint32_t *consumed = nullptr);
|
||||
|
||||
std::string as_string(const uint8_t *value, size_t len);
|
||||
int32_t as_sint32(uint32_t val);
|
||||
float as_float(uint32_t val);
|
||||
|
||||
class APIServer;
|
||||
class UserServiceDescriptor;
|
||||
|
||||
class ComponentIterator {
|
||||
public:
|
||||
ComponentIterator(APIServer *server);
|
||||
|
||||
void begin();
|
||||
void advance();
|
||||
virtual bool on_begin();
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
virtual bool on_binary_sensor(binary_sensor::BinarySensor *binary_sensor) = 0;
|
||||
#endif
|
||||
#ifdef USE_COVER
|
||||
virtual bool on_cover(cover::Cover *cover) = 0;
|
||||
#endif
|
||||
#ifdef USE_FAN
|
||||
virtual bool on_fan(fan::FanState *fan) = 0;
|
||||
#endif
|
||||
#ifdef USE_LIGHT
|
||||
virtual bool on_light(light::LightState *light) = 0;
|
||||
#endif
|
||||
#ifdef USE_SENSOR
|
||||
virtual bool on_sensor(sensor::Sensor *sensor) = 0;
|
||||
#endif
|
||||
#ifdef USE_SWITCH
|
||||
virtual bool on_switch(switch_::Switch *a_switch) = 0;
|
||||
#endif
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
virtual bool on_text_sensor(text_sensor::TextSensor *text_sensor) = 0;
|
||||
#endif
|
||||
virtual bool on_service(UserServiceDescriptor *service);
|
||||
#ifdef USE_ESP32_CAMERA
|
||||
virtual bool on_camera(esp32_camera::ESP32Camera *camera);
|
||||
#endif
|
||||
#ifdef USE_CLIMATE
|
||||
virtual bool on_climate(climate::Climate *climate) = 0;
|
||||
#endif
|
||||
virtual bool on_end();
|
||||
|
||||
protected:
|
||||
enum class IteratorState {
|
||||
NONE = 0,
|
||||
BEGIN,
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
BINARY_SENSOR,
|
||||
#endif
|
||||
#ifdef USE_COVER
|
||||
COVER,
|
||||
#endif
|
||||
#ifdef USE_FAN
|
||||
FAN,
|
||||
#endif
|
||||
#ifdef USE_LIGHT
|
||||
LIGHT,
|
||||
#endif
|
||||
#ifdef USE_SENSOR
|
||||
SENSOR,
|
||||
#endif
|
||||
#ifdef USE_SWITCH
|
||||
SWITCH,
|
||||
#endif
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
TEXT_SENSOR,
|
||||
#endif
|
||||
SERVICE,
|
||||
#ifdef USE_ESP32_CAMERA
|
||||
CAMERA,
|
||||
#endif
|
||||
#ifdef USE_CLIMATE
|
||||
CLIMATE,
|
||||
#endif
|
||||
MAX,
|
||||
} state_{IteratorState::NONE};
|
||||
size_t at_{0};
|
||||
|
||||
APIServer *server_;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
Reference in New Issue
Block a user