[api] Add support for ESPHome action responses

This adds the ability for ESPHome-defined actions (services) to send
responses back to Home Assistant. This is the complement to the existing
feature that allows ESPHome to receive responses from HA actions.

New features:
- ExecuteServiceResponse protobuf message (ID 131) for sending responses
- call_id field in ExecuteServiceRequest for tracking service calls
- api.respond action for sending responses from YAML automations
- Support for JSON response data via data: lambda

Example usage:
```yaml
api:
  actions:
    - action: get_sensor_value
      variables:
        sensor_name: string
      then:
        - api.respond:
            data: |-
              root["value"] = id(my_sensor).state;
              root["unit"] = "°C";
```

Note: This requires corresponding changes in aioesphomeapi and
home-assistant/core to handle the new messages.
This commit is contained in:
Claude
2025-11-20 22:09:19 +00:00
parent 01addeae08
commit c1838fae62
14 changed files with 977 additions and 986 deletions

View File

@@ -63,6 +63,7 @@ HomeAssistantActionResponseTrigger = api_ns.class_(
"HomeAssistantActionResponseTrigger", automation.Trigger
)
APIConnectedCondition = api_ns.class_("APIConnectedCondition", Condition)
APIRespondAction = api_ns.class_("APIRespondAction", automation.Action)
UserServiceTrigger = api_ns.class_("UserServiceTrigger", automation.Trigger)
ListEntitiesServicesArgument = api_ns.class_("ListEntitiesServicesArgument")
@@ -537,6 +538,49 @@ async def homeassistant_tag_scanned_to_code(config, action_id, template_arg, arg
return var
CONF_SUCCESS = "success"
CONF_ERROR_MESSAGE = "error_message"
API_RESPOND_ACTION_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.use_id(APIServer),
cv.Optional(CONF_SUCCESS, default=True): cv.templatable(cv.boolean),
cv.Optional(CONF_ERROR_MESSAGE, default=""): cv.templatable(cv.string),
cv.Optional(CONF_DATA): cv.lambda_,
}
)
@automation.register_action(
"api.respond",
APIRespondAction,
API_RESPOND_ACTION_SCHEMA,
)
async def api_respond_to_code(config, action_id, template_arg, args):
cg.add_define("USE_API_SERVICE_RESPONSES")
serv = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, serv)
templ = await cg.templatable(config[CONF_SUCCESS], args, bool)
cg.add(var.set_success(templ))
templ = await cg.templatable(config[CONF_ERROR_MESSAGE], args, cg.std_string)
cg.add(var.set_error_message(templ))
if CONF_DATA in config:
cg.add_define("USE_API_SERVICE_RESPONSE_JSON")
# Track for AUTO_LOAD to include json component
CORE.data.setdefault(DOMAIN, {})[CONF_CAPTURE_RESPONSE] = True
lambda_ = await cg.process_lambda(
config[CONF_DATA],
args + [(cg.JsonObject, "root")],
return_type=cg.void,
)
cg.add(var.set_data(lambda_))
return var
@automation.register_condition("api.connected", APIConnectedCondition, {})
async def api_connected_to_code(config, condition_id, template_arg, args):
return cg.new_Pvariable(condition_id, template_arg)

View File

@@ -889,6 +889,20 @@ message ExecuteServiceRequest {
fixed32 key = 1;
repeated ExecuteServiceArgument args = 2 [(fixed_vector) = true];
uint32 call_id = 3 [(field_ifdef) = "USE_API_SERVICE_RESPONSES"];
}
// Message sent by ESPHome to Home Assistant with service execution response data
message ExecuteServiceResponse {
option (id) = 131;
option (source) = SOURCE_SERVER;
option (no_delay) = true;
option (ifdef) = "USE_API_SERVICE_RESPONSES";
uint32 call_id = 1; // Matches the call_id from ExecuteServiceRequest
bool success = 2; // Whether the service execution succeeded
string error_message = 3; // Error message if success = false
bytes response_data = 4 [(pointer_to_buffer) = true, (field_ifdef) = "USE_API_SERVICE_RESPONSE_JSON"];
}
// ==================== CAMERA ====================

View File

@@ -1544,6 +1544,12 @@ void APIConnection::on_home_assistant_state_response(const HomeAssistantStateRes
#ifdef USE_API_SERVICES
void APIConnection::execute_service(const ExecuteServiceRequest &msg) {
bool found = false;
#ifdef USE_API_SERVICE_RESPONSES
// Set the call context before executing so responses can be sent
if (msg.call_id != 0) {
this->parent_->set_current_service_call(msg.call_id, this);
}
#endif
for (auto *service : this->parent_->get_user_services()) {
if (service->execute_service(msg)) {
found = true;
@@ -1552,7 +1558,32 @@ void APIConnection::execute_service(const ExecuteServiceRequest &msg) {
if (!found) {
ESP_LOGV(TAG, "Could not find service");
}
#ifdef USE_API_SERVICE_RESPONSES
// Clear call context after execution (if not already cleared by sending a response)
this->parent_->clear_current_service_call();
#endif
}
#ifdef USE_API_SERVICE_RESPONSES
void APIConnection::send_execute_service_response(uint32_t call_id, bool success, const std::string &error_message) {
ExecuteServiceResponse resp;
resp.call_id = call_id;
resp.success = success;
resp.error_message = error_message;
this->send_message(resp, ExecuteServiceResponse::MESSAGE_TYPE);
}
#ifdef USE_API_SERVICE_RESPONSE_JSON
void APIConnection::send_execute_service_response(uint32_t call_id, bool success, const std::string &error_message,
const uint8_t *response_data, size_t response_data_len) {
ExecuteServiceResponse resp;
resp.call_id = call_id;
resp.success = success;
resp.error_message = error_message;
resp.response_data = response_data;
resp.response_data_len = response_data_len;
this->send_message(resp, ExecuteServiceResponse::MESSAGE_TYPE);
}
#endif // USE_API_SERVICE_RESPONSE_JSON
#endif // USE_API_SERVICE_RESPONSES
#endif
#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES

View File

@@ -223,6 +223,13 @@ class APIConnection final : public APIServerConnection {
#endif
#ifdef USE_API_SERVICES
void execute_service(const ExecuteServiceRequest &msg) override;
#ifdef USE_API_SERVICE_RESPONSES
void send_execute_service_response(uint32_t call_id, bool success, const std::string &error_message);
#ifdef USE_API_SERVICE_RESPONSE_JSON
void send_execute_service_response(uint32_t call_id, bool success, const std::string &error_message,
const uint8_t *response_data, size_t response_data_len);
#endif // USE_API_SERVICE_RESPONSE_JSON
#endif // USE_API_SERVICE_RESPONSES
#endif
#ifdef USE_API_NOISE
bool send_noise_encryption_set_key_response(const NoiseEncryptionSetKeyRequest &msg) override;

File diff suppressed because it is too large Load Diff

View File

@@ -290,14 +290,20 @@ class InfoResponseProtoMessage : public ProtoMessage {
public:
~InfoResponseProtoMessage() override = default;
StringRef object_id_ref_{};
void set_object_id(const StringRef &ref) { this->object_id_ref_ = ref; }
void set_object_id(const StringRef &ref) {
this->object_id_ref_ = ref;
}
uint32_t key{0};
StringRef name_ref_{};
void set_name(const StringRef &ref) { this->name_ref_ = ref; }
void set_name(const StringRef &ref) {
this->name_ref_ = ref;
}
bool disabled_by_default{false};
#ifdef USE_ENTITY_ICON
StringRef icon_ref_{};
void set_icon(const StringRef &ref) { this->icon_ref_ = ref; }
void set_icon(const StringRef &ref) {
this->icon_ref_ = ref;
}
#endif
enums::EntityCategory entity_category{};
#ifdef USE_DEVICES
@@ -335,7 +341,7 @@ class HelloRequest final : public ProtoDecodableMessage {
#ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "hello_request"; }
#endif
const uint8_t *client_info{nullptr};
const uint8_t* client_info{nullptr};
uint16_t client_info_len{0};
uint32_t api_version_major{0};
uint32_t api_version_minor{0};
@@ -357,9 +363,13 @@ class HelloResponse final : public ProtoMessage {
uint32_t api_version_major{0};
uint32_t api_version_minor{0};
StringRef server_info_ref_{};
void set_server_info(const StringRef &ref) { this->server_info_ref_ = ref; }
void set_server_info(const StringRef &ref) {
this->server_info_ref_ = ref;
}
StringRef name_ref_{};
void set_name(const StringRef &ref) { this->name_ref_ = ref; }
void set_name(const StringRef &ref) {
this->name_ref_ = ref;
}
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
@@ -376,7 +386,7 @@ class AuthenticationRequest final : public ProtoDecodableMessage {
#ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "authentication_request"; }
#endif
const uint8_t *password{nullptr};
const uint8_t* password{nullptr};
uint16_t password_len{0};
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
@@ -472,7 +482,9 @@ class AreaInfo final : public ProtoMessage {
public:
uint32_t area_id{0};
StringRef name_ref_{};
void set_name(const StringRef &ref) { this->name_ref_ = ref; }
void set_name(const StringRef &ref) {
this->name_ref_ = ref;
}
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
@@ -487,7 +499,9 @@ class DeviceInfo final : public ProtoMessage {
public:
uint32_t device_id{0};
StringRef name_ref_{};
void set_name(const StringRef &ref) { this->name_ref_ = ref; }
void set_name(const StringRef &ref) {
this->name_ref_ = ref;
}
uint32_t area_id{0};
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
@@ -509,25 +523,39 @@ class DeviceInfoResponse final : public ProtoMessage {
bool uses_password{false};
#endif
StringRef name_ref_{};
void set_name(const StringRef &ref) { this->name_ref_ = ref; }
void set_name(const StringRef &ref) {
this->name_ref_ = ref;
}
StringRef mac_address_ref_{};
void set_mac_address(const StringRef &ref) { this->mac_address_ref_ = ref; }
void set_mac_address(const StringRef &ref) {
this->mac_address_ref_ = ref;
}
StringRef esphome_version_ref_{};
void set_esphome_version(const StringRef &ref) { this->esphome_version_ref_ = ref; }
void set_esphome_version(const StringRef &ref) {
this->esphome_version_ref_ = ref;
}
StringRef compilation_time_ref_{};
void set_compilation_time(const StringRef &ref) { this->compilation_time_ref_ = ref; }
void set_compilation_time(const StringRef &ref) {
this->compilation_time_ref_ = ref;
}
StringRef model_ref_{};
void set_model(const StringRef &ref) { this->model_ref_ = ref; }
void set_model(const StringRef &ref) {
this->model_ref_ = ref;
}
#ifdef USE_DEEP_SLEEP
bool has_deep_sleep{false};
#endif
#ifdef ESPHOME_PROJECT_NAME
StringRef project_name_ref_{};
void set_project_name(const StringRef &ref) { this->project_name_ref_ = ref; }
void set_project_name(const StringRef &ref) {
this->project_name_ref_ = ref;
}
#endif
#ifdef ESPHOME_PROJECT_NAME
StringRef project_version_ref_{};
void set_project_version(const StringRef &ref) { this->project_version_ref_ = ref; }
void set_project_version(const StringRef &ref) {
this->project_version_ref_ = ref;
}
#endif
#ifdef USE_WEBSERVER
uint32_t webserver_port{0};
@@ -536,19 +564,27 @@ class DeviceInfoResponse final : public ProtoMessage {
uint32_t bluetooth_proxy_feature_flags{0};
#endif
StringRef manufacturer_ref_{};
void set_manufacturer(const StringRef &ref) { this->manufacturer_ref_ = ref; }
void set_manufacturer(const StringRef &ref) {
this->manufacturer_ref_ = ref;
}
StringRef friendly_name_ref_{};
void set_friendly_name(const StringRef &ref) { this->friendly_name_ref_ = ref; }
void set_friendly_name(const StringRef &ref) {
this->friendly_name_ref_ = ref;
}
#ifdef USE_VOICE_ASSISTANT
uint32_t voice_assistant_feature_flags{0};
#endif
#ifdef USE_AREAS
StringRef suggested_area_ref_{};
void set_suggested_area(const StringRef &ref) { this->suggested_area_ref_ = ref; }
void set_suggested_area(const StringRef &ref) {
this->suggested_area_ref_ = ref;
}
#endif
#ifdef USE_BLUETOOTH_PROXY
StringRef bluetooth_mac_address_ref_{};
void set_bluetooth_mac_address(const StringRef &ref) { this->bluetooth_mac_address_ref_ = ref; }
void set_bluetooth_mac_address(const StringRef &ref) {
this->bluetooth_mac_address_ref_ = ref;
}
#endif
#ifdef USE_API_NOISE
bool api_encryption_supported{false};
@@ -624,7 +660,9 @@ class ListEntitiesBinarySensorResponse final : public InfoResponseProtoMessage {
const char *message_name() const override { return "list_entities_binary_sensor_response"; }
#endif
StringRef device_class_ref_{};
void set_device_class(const StringRef &ref) { this->device_class_ref_ = ref; }
void set_device_class(const StringRef &ref) {
this->device_class_ref_ = ref;
}
bool is_status_binary_sensor{false};
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
@@ -664,7 +702,9 @@ class ListEntitiesCoverResponse final : public InfoResponseProtoMessage {
bool supports_position{false};
bool supports_tilt{false};
StringRef device_class_ref_{};
void set_device_class(const StringRef &ref) { this->device_class_ref_ = ref; }
void set_device_class(const StringRef &ref) {
this->device_class_ref_ = ref;
}
bool supports_stop{false};
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
@@ -725,7 +765,7 @@ class ListEntitiesFanResponse final : public InfoResponseProtoMessage {
bool supports_speed{false};
bool supports_direction{false};
int32_t supported_speed_count{0};
const std::vector<const char *> *supported_preset_modes{};
const std::vector<const char *>* supported_preset_modes{};
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
@@ -746,7 +786,9 @@ class FanStateResponse final : public StateResponseProtoMessage {
enums::FanDirection direction{};
int32_t speed_level{0};
StringRef preset_mode_ref_{};
void set_preset_mode(const StringRef &ref) { this->preset_mode_ref_ = ref; }
void set_preset_mode(const StringRef &ref) {
this->preset_mode_ref_ = ref;
}
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
@@ -790,7 +832,7 @@ class ListEntitiesLightResponse final : public InfoResponseProtoMessage {
#ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "list_entities_light_response"; }
#endif
const light::ColorModeMask *supported_color_modes{};
const light::ColorModeMask* supported_color_modes{};
float min_mireds{0.0f};
float max_mireds{0.0f};
std::vector<std::string> effects{};
@@ -821,7 +863,9 @@ class LightStateResponse final : public StateResponseProtoMessage {
float cold_white{0.0f};
float warm_white{0.0f};
StringRef effect_ref_{};
void set_effect(const StringRef &ref) { this->effect_ref_ = ref; }
void set_effect(const StringRef &ref) {
this->effect_ref_ = ref;
}
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
@@ -882,11 +926,15 @@ class ListEntitiesSensorResponse final : public InfoResponseProtoMessage {
const char *message_name() const override { return "list_entities_sensor_response"; }
#endif
StringRef unit_of_measurement_ref_{};
void set_unit_of_measurement(const StringRef &ref) { this->unit_of_measurement_ref_ = ref; }
void set_unit_of_measurement(const StringRef &ref) {
this->unit_of_measurement_ref_ = ref;
}
int32_t accuracy_decimals{0};
bool force_update{false};
StringRef device_class_ref_{};
void set_device_class(const StringRef &ref) { this->device_class_ref_ = ref; }
void set_device_class(const StringRef &ref) {
this->device_class_ref_ = ref;
}
enums::SensorStateClass state_class{};
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
@@ -924,7 +972,9 @@ class ListEntitiesSwitchResponse final : public InfoResponseProtoMessage {
#endif
bool assumed_state{false};
StringRef device_class_ref_{};
void set_device_class(const StringRef &ref) { this->device_class_ref_ = ref; }
void set_device_class(const StringRef &ref) {
this->device_class_ref_ = ref;
}
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
@@ -975,7 +1025,9 @@ class ListEntitiesTextSensorResponse final : public InfoResponseProtoMessage {
const char *message_name() const override { return "list_entities_text_sensor_response"; }
#endif
StringRef device_class_ref_{};
void set_device_class(const StringRef &ref) { this->device_class_ref_ = ref; }
void set_device_class(const StringRef &ref) {
this->device_class_ref_ = ref;
}
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
@@ -992,7 +1044,9 @@ class TextSensorStateResponse final : public StateResponseProtoMessage {
const char *message_name() const override { return "text_sensor_state_response"; }
#endif
StringRef state_ref_{};
void set_state(const StringRef &ref) { this->state_ref_ = ref; }
void set_state(const StringRef &ref) {
this->state_ref_ = ref;
}
bool missing_state{false};
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
@@ -1027,9 +1081,9 @@ class SubscribeLogsResponse final : public ProtoMessage {
const char *message_name() const override { return "subscribe_logs_response"; }
#endif
enums::LogLevel level{};
const uint8_t *message_ptr_{nullptr};
const uint8_t* message_ptr_{nullptr};
size_t message_len_{0};
void set_message(const uint8_t *data, size_t len) {
void set_message(const uint8_t* data, size_t len) {
this->message_ptr_ = data;
this->message_len_ = len;
}
@@ -1091,7 +1145,9 @@ class SubscribeHomeassistantServicesRequest final : public ProtoMessage {
class HomeassistantServiceMap final : public ProtoMessage {
public:
StringRef key_ref_{};
void set_key(const StringRef &ref) { this->key_ref_ = ref; }
void set_key(const StringRef &ref) {
this->key_ref_ = ref;
}
std::string value{};
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
@@ -1109,7 +1165,9 @@ class HomeassistantActionRequest final : public ProtoMessage {
const char *message_name() const override { return "homeassistant_action_request"; }
#endif
StringRef service_ref_{};
void set_service(const StringRef &ref) { this->service_ref_ = ref; }
void set_service(const StringRef &ref) {
this->service_ref_ = ref;
}
FixedVector<HomeassistantServiceMap> data{};
FixedVector<HomeassistantServiceMap> data_template{};
FixedVector<HomeassistantServiceMap> variables{};
@@ -1144,7 +1202,7 @@ class HomeassistantActionResponse final : public ProtoDecodableMessage {
bool success{false};
std::string error_message{};
#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON
const uint8_t *response_data{nullptr};
const uint8_t* response_data{nullptr};
uint16_t response_data_len{0};
#endif
#ifdef HAS_PROTO_MESSAGE_DUMP
@@ -1178,9 +1236,13 @@ class SubscribeHomeAssistantStateResponse final : public ProtoMessage {
const char *message_name() const override { return "subscribe_home_assistant_state_response"; }
#endif
StringRef entity_id_ref_{};
void set_entity_id(const StringRef &ref) { this->entity_id_ref_ = ref; }
void set_entity_id(const StringRef &ref) {
this->entity_id_ref_ = ref;
}
StringRef attribute_ref_{};
void set_attribute(const StringRef &ref) { this->attribute_ref_ = ref; }
void set_attribute(const StringRef &ref) {
this->attribute_ref_ = ref;
}
bool once{false};
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
@@ -1229,7 +1291,7 @@ class GetTimeResponse final : public ProtoDecodableMessage {
const char *message_name() const override { return "get_time_response"; }
#endif
uint32_t epoch_seconds{0};
const uint8_t *timezone{nullptr};
const uint8_t* timezone{nullptr};
uint16_t timezone_len{0};
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
@@ -1243,7 +1305,9 @@ class GetTimeResponse final : public ProtoDecodableMessage {
class ListEntitiesServicesArgument final : public ProtoMessage {
public:
StringRef name_ref_{};
void set_name(const StringRef &ref) { this->name_ref_ = ref; }
void set_name(const StringRef &ref) {
this->name_ref_ = ref;
}
enums::ServiceArgType type{};
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
@@ -1261,7 +1325,9 @@ class ListEntitiesServicesResponse final : public ProtoMessage {
const char *message_name() const override { return "list_entities_services_response"; }
#endif
StringRef name_ref_{};
void set_name(const StringRef &ref) { this->name_ref_ = ref; }
void set_name(const StringRef &ref) {
this->name_ref_ = ref;
}
uint32_t key{0};
FixedVector<ListEntitiesServicesArgument> args{};
void encode(ProtoWriteBuffer buffer) const override;
@@ -1296,12 +1362,15 @@ class ExecuteServiceArgument final : public ProtoDecodableMessage {
class ExecuteServiceRequest final : public ProtoDecodableMessage {
public:
static constexpr uint8_t MESSAGE_TYPE = 42;
static constexpr uint8_t ESTIMATED_SIZE = 39;
static constexpr uint8_t ESTIMATED_SIZE = 43;
#ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "execute_service_request"; }
#endif
uint32_t key{0};
FixedVector<ExecuteServiceArgument> args{};
#ifdef USE_API_SERVICE_RESPONSES
uint32_t call_id{0};
#endif
void decode(const uint8_t *buffer, size_t length) override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
@@ -1310,6 +1379,34 @@ class ExecuteServiceRequest final : public ProtoDecodableMessage {
protected:
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
#endif
#ifdef USE_API_SERVICE_RESPONSES
class ExecuteServiceResponse final : public ProtoMessage {
public:
static constexpr uint8_t MESSAGE_TYPE = 131;
static constexpr uint8_t ESTIMATED_SIZE = 34;
#ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "execute_service_response"; }
#endif
uint32_t call_id{0};
bool success{false};
StringRef error_message_ref_{};
void set_error_message(const StringRef &ref) {
this->error_message_ref_ = ref;
}
#ifdef USE_API_SERVICE_RESPONSE_JSON
const uint8_t* response_data{nullptr};
uint16_t response_data_len{0};
#endif
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
};
#endif
#ifdef USE_CAMERA
@@ -1335,9 +1432,9 @@ class CameraImageResponse final : public StateResponseProtoMessage {
#ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "camera_image_response"; }
#endif
const uint8_t *data_ptr_{nullptr};
const uint8_t* data_ptr_{nullptr};
size_t data_len_{0};
void set_data(const uint8_t *data, size_t len) {
void set_data(const uint8_t* data, size_t len) {
this->data_ptr_ = data;
this->data_len_ = len;
}
@@ -1377,16 +1474,16 @@ class ListEntitiesClimateResponse final : public InfoResponseProtoMessage {
#endif
bool supports_current_temperature{false};
bool supports_two_point_target_temperature{false};
const climate::ClimateModeMask *supported_modes{};
const climate::ClimateModeMask* supported_modes{};
float visual_min_temperature{0.0f};
float visual_max_temperature{0.0f};
float visual_target_temperature_step{0.0f};
bool supports_action{false};
const climate::ClimateFanModeMask *supported_fan_modes{};
const climate::ClimateSwingModeMask *supported_swing_modes{};
const std::vector<const char *> *supported_custom_fan_modes{};
const climate::ClimatePresetMask *supported_presets{};
const std::vector<const char *> *supported_custom_presets{};
const climate::ClimateFanModeMask* supported_fan_modes{};
const climate::ClimateSwingModeMask* supported_swing_modes{};
const std::vector<const char *>* supported_custom_fan_modes{};
const climate::ClimatePresetMask* supported_presets{};
const std::vector<const char *>* supported_custom_presets{};
float visual_current_temperature_step{0.0f};
bool supports_current_humidity{false};
bool supports_target_humidity{false};
@@ -1417,10 +1514,14 @@ class ClimateStateResponse final : public StateResponseProtoMessage {
enums::ClimateFanMode fan_mode{};
enums::ClimateSwingMode swing_mode{};
StringRef custom_fan_mode_ref_{};
void set_custom_fan_mode(const StringRef &ref) { this->custom_fan_mode_ref_ = ref; }
void set_custom_fan_mode(const StringRef &ref) {
this->custom_fan_mode_ref_ = ref;
}
enums::ClimatePreset preset{};
StringRef custom_preset_ref_{};
void set_custom_preset(const StringRef &ref) { this->custom_preset_ref_ = ref; }
void set_custom_preset(const StringRef &ref) {
this->custom_preset_ref_ = ref;
}
float current_humidity{0.0f};
float target_humidity{0.0f};
void encode(ProtoWriteBuffer buffer) const override;
@@ -1480,10 +1581,14 @@ class ListEntitiesNumberResponse final : public InfoResponseProtoMessage {
float max_value{0.0f};
float step{0.0f};
StringRef unit_of_measurement_ref_{};
void set_unit_of_measurement(const StringRef &ref) { this->unit_of_measurement_ref_ = ref; }
void set_unit_of_measurement(const StringRef &ref) {
this->unit_of_measurement_ref_ = ref;
}
enums::NumberMode mode{};
StringRef device_class_ref_{};
void set_device_class(const StringRef &ref) { this->device_class_ref_ = ref; }
void set_device_class(const StringRef &ref) {
this->device_class_ref_ = ref;
}
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
@@ -1534,7 +1639,7 @@ class ListEntitiesSelectResponse final : public InfoResponseProtoMessage {
#ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "list_entities_select_response"; }
#endif
const FixedVector<const char *> *options{};
const FixedVector<const char *>* options{};
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
@@ -1551,7 +1656,9 @@ class SelectStateResponse final : public StateResponseProtoMessage {
const char *message_name() const override { return "select_state_response"; }
#endif
StringRef state_ref_{};
void set_state(const StringRef &ref) { this->state_ref_ = ref; }
void set_state(const StringRef &ref) {
this->state_ref_ = ref;
}
bool missing_state{false};
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
@@ -1651,7 +1758,9 @@ class ListEntitiesLockResponse final : public InfoResponseProtoMessage {
bool supports_open{false};
bool requires_code{false};
StringRef code_format_ref_{};
void set_code_format(const StringRef &ref) { this->code_format_ref_ = ref; }
void set_code_format(const StringRef &ref) {
this->code_format_ref_ = ref;
}
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
@@ -1705,7 +1814,9 @@ class ListEntitiesButtonResponse final : public InfoResponseProtoMessage {
const char *message_name() const override { return "list_entities_button_response"; }
#endif
StringRef device_class_ref_{};
void set_device_class(const StringRef &ref) { this->device_class_ref_ = ref; }
void set_device_class(const StringRef &ref) {
this->device_class_ref_ = ref;
}
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
@@ -1734,7 +1845,9 @@ class ButtonCommandRequest final : public CommandProtoMessage {
class MediaPlayerSupportedFormat final : public ProtoMessage {
public:
StringRef format_ref_{};
void set_format(const StringRef &ref) { this->format_ref_ = ref; }
void set_format(const StringRef &ref) {
this->format_ref_ = ref;
}
uint32_t sample_rate{0};
uint32_t num_channels{0};
enums::MediaPlayerFormatPurpose purpose{};
@@ -2008,9 +2121,9 @@ class BluetoothGATTReadResponse final : public ProtoMessage {
#endif
uint64_t address{0};
uint32_t handle{0};
const uint8_t *data_ptr_{nullptr};
const uint8_t* data_ptr_{nullptr};
size_t data_len_{0};
void set_data(const uint8_t *data, size_t len) {
void set_data(const uint8_t* data, size_t len) {
this->data_ptr_ = data;
this->data_len_ = len;
}
@@ -2032,7 +2145,7 @@ class BluetoothGATTWriteRequest final : public ProtoDecodableMessage {
uint64_t address{0};
uint32_t handle{0};
bool response{false};
const uint8_t *data{nullptr};
const uint8_t* data{nullptr};
uint16_t data_len{0};
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
@@ -2067,7 +2180,7 @@ class BluetoothGATTWriteDescriptorRequest final : public ProtoDecodableMessage {
#endif
uint64_t address{0};
uint32_t handle{0};
const uint8_t *data{nullptr};
const uint8_t* data{nullptr};
uint16_t data_len{0};
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
@@ -2103,9 +2216,9 @@ class BluetoothGATTNotifyDataResponse final : public ProtoMessage {
#endif
uint64_t address{0};
uint32_t handle{0};
const uint8_t *data_ptr_{nullptr};
const uint8_t* data_ptr_{nullptr};
size_t data_len_{0};
void set_data(const uint8_t *data, size_t len) {
void set_data(const uint8_t* data, size_t len) {
this->data_ptr_ = data;
this->data_len_ = len;
}
@@ -2340,11 +2453,15 @@ class VoiceAssistantRequest final : public ProtoMessage {
#endif
bool start{false};
StringRef conversation_id_ref_{};
void set_conversation_id(const StringRef &ref) { this->conversation_id_ref_ = ref; }
void set_conversation_id(const StringRef &ref) {
this->conversation_id_ref_ = ref;
}
uint32_t flags{0};
VoiceAssistantAudioSettings audio_settings{};
StringRef wake_word_phrase_ref_{};
void set_wake_word_phrase(const StringRef &ref) { this->wake_word_phrase_ref_ = ref; }
void set_wake_word_phrase(const StringRef &ref) {
this->wake_word_phrase_ref_ = ref;
}
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
@@ -2405,9 +2522,9 @@ class VoiceAssistantAudio final : public ProtoDecodableMessage {
const char *message_name() const override { return "voice_assistant_audio"; }
#endif
std::string data{};
const uint8_t *data_ptr_{nullptr};
const uint8_t* data_ptr_{nullptr};
size_t data_len_{0};
void set_data(const uint8_t *data, size_t len) {
void set_data(const uint8_t* data, size_t len) {
this->data_ptr_ = data;
this->data_len_ = len;
}
@@ -2481,9 +2598,13 @@ class VoiceAssistantAnnounceFinished final : public ProtoMessage {
class VoiceAssistantWakeWord final : public ProtoMessage {
public:
StringRef id_ref_{};
void set_id(const StringRef &ref) { this->id_ref_ = ref; }
void set_id(const StringRef &ref) {
this->id_ref_ = ref;
}
StringRef wake_word_ref_{};
void set_wake_word(const StringRef &ref) { this->wake_word_ref_ = ref; }
void set_wake_word(const StringRef &ref) {
this->wake_word_ref_ = ref;
}
std::vector<std::string> trained_languages{};
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
@@ -2533,7 +2654,7 @@ class VoiceAssistantConfigurationResponse final : public ProtoMessage {
const char *message_name() const override { return "voice_assistant_configuration_response"; }
#endif
std::vector<VoiceAssistantWakeWord> available_wake_words{};
const std::vector<std::string> *active_wake_words{};
const std::vector<std::string>* active_wake_words{};
uint32_t max_active_wake_words{0};
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
@@ -2624,7 +2745,9 @@ class ListEntitiesTextResponse final : public InfoResponseProtoMessage {
uint32_t min_length{0};
uint32_t max_length{0};
StringRef pattern_ref_{};
void set_pattern(const StringRef &ref) { this->pattern_ref_ = ref; }
void set_pattern(const StringRef &ref) {
this->pattern_ref_ = ref;
}
enums::TextMode mode{};
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
@@ -2642,7 +2765,9 @@ class TextStateResponse final : public StateResponseProtoMessage {
const char *message_name() const override { return "text_state_response"; }
#endif
StringRef state_ref_{};
void set_state(const StringRef &ref) { this->state_ref_ = ref; }
void set_state(const StringRef &ref) {
this->state_ref_ = ref;
}
bool missing_state{false};
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
@@ -2787,8 +2912,10 @@ class ListEntitiesEventResponse final : public InfoResponseProtoMessage {
const char *message_name() const override { return "list_entities_event_response"; }
#endif
StringRef device_class_ref_{};
void set_device_class(const StringRef &ref) { this->device_class_ref_ = ref; }
const FixedVector<const char *> *event_types{};
void set_device_class(const StringRef &ref) {
this->device_class_ref_ = ref;
}
const FixedVector<const char *>* event_types{};
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
@@ -2805,7 +2932,9 @@ class EventResponse final : public StateResponseProtoMessage {
const char *message_name() const override { return "event_response"; }
#endif
StringRef event_type_ref_{};
void set_event_type(const StringRef &ref) { this->event_type_ref_ = ref; }
void set_event_type(const StringRef &ref) {
this->event_type_ref_ = ref;
}
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
@@ -2824,7 +2953,9 @@ class ListEntitiesValveResponse final : public InfoResponseProtoMessage {
const char *message_name() const override { return "list_entities_valve_response"; }
#endif
StringRef device_class_ref_{};
void set_device_class(const StringRef &ref) { this->device_class_ref_ = ref; }
void set_device_class(const StringRef &ref) {
this->device_class_ref_ = ref;
}
bool assumed_state{false};
bool supports_position{false};
bool supports_stop{false};
@@ -2931,7 +3062,9 @@ class ListEntitiesUpdateResponse final : public InfoResponseProtoMessage {
const char *message_name() const override { return "list_entities_update_response"; }
#endif
StringRef device_class_ref_{};
void set_device_class(const StringRef &ref) { this->device_class_ref_ = ref; }
void set_device_class(const StringRef &ref) {
this->device_class_ref_ = ref;
}
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
@@ -2952,15 +3085,25 @@ class UpdateStateResponse final : public StateResponseProtoMessage {
bool has_progress{false};
float progress{0.0f};
StringRef current_version_ref_{};
void set_current_version(const StringRef &ref) { this->current_version_ref_ = ref; }
void set_current_version(const StringRef &ref) {
this->current_version_ref_ = ref;
}
StringRef latest_version_ref_{};
void set_latest_version(const StringRef &ref) { this->latest_version_ref_ = ref; }
void set_latest_version(const StringRef &ref) {
this->latest_version_ref_ = ref;
}
StringRef title_ref_{};
void set_title(const StringRef &ref) { this->title_ref_ = ref; }
void set_title(const StringRef &ref) {
this->title_ref_ = ref;
}
StringRef release_summary_ref_{};
void set_release_summary(const StringRef &ref) { this->release_summary_ref_ = ref; }
void set_release_summary(const StringRef &ref) {
this->release_summary_ref_ = ref;
}
StringRef release_url_ref_{};
void set_release_url(const StringRef &ref) { this->release_url_ref_ = ref; }
void set_release_url(const StringRef &ref) {
this->release_url_ref_ = ref;
}
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
@@ -2994,7 +3137,7 @@ class ZWaveProxyFrame final : public ProtoDecodableMessage {
#ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "z_wave_proxy_frame"; }
#endif
const uint8_t *data{nullptr};
const uint8_t* data{nullptr};
uint16_t data_len{0};
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
@@ -3013,7 +3156,7 @@ class ZWaveProxyRequest final : public ProtoDecodableMessage {
const char *message_name() const override { return "z_wave_proxy_request"; }
#endif
enums::ZWaveProxyRequestType type{};
const uint8_t *data{nullptr};
const uint8_t* data{nullptr};
uint16_t data_len{0};
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;

View File

@@ -94,7 +94,8 @@ static void dump_field(std::string &out, const char *field_name, const char *val
out.append("\n");
}
template<typename T> static void dump_field(std::string &out, const char *field_name, T value, int indent = 2) {
template<typename T>
static void dump_field(std::string &out, const char *field_name, T value, int indent = 2) {
append_field_prefix(out, field_name, indent);
out.append(proto_enum_to_string<T>(value));
out.append("\n");
@@ -445,8 +446,7 @@ template<> const char *proto_enum_to_string<enums::MediaPlayerFormatPurpose>(enu
}
#endif
#ifdef USE_BLUETOOTH_PROXY
template<>
const char *proto_enum_to_string<enums::BluetoothDeviceRequestType>(enums::BluetoothDeviceRequestType value) {
template<> const char *proto_enum_to_string<enums::BluetoothDeviceRequestType>(enums::BluetoothDeviceRequestType value) {
switch (value) {
case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT:
return "BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT";
@@ -495,8 +495,7 @@ template<> const char *proto_enum_to_string<enums::BluetoothScannerMode>(enums::
}
}
#endif
template<>
const char *proto_enum_to_string<enums::VoiceAssistantSubscribeFlag>(enums::VoiceAssistantSubscribeFlag value) {
template<> const char *proto_enum_to_string<enums::VoiceAssistantSubscribeFlag>(enums::VoiceAssistantSubscribeFlag value) {
switch (value) {
case enums::VOICE_ASSISTANT_SUBSCRIBE_NONE:
return "VOICE_ASSISTANT_SUBSCRIBE_NONE";
@@ -599,8 +598,7 @@ template<> const char *proto_enum_to_string<enums::AlarmControlPanelState>(enums
return "UNKNOWN";
}
}
template<>
const char *proto_enum_to_string<enums::AlarmControlPanelStateCommand>(enums::AlarmControlPanelStateCommand value) {
template<> const char *proto_enum_to_string<enums::AlarmControlPanelStateCommand>(enums::AlarmControlPanelStateCommand value) {
switch (value) {
case enums::ALARM_CONTROL_PANEL_DISARM:
return "ALARM_CONTROL_PANEL_DISARM";
@@ -676,6 +674,7 @@ template<> const char *proto_enum_to_string<enums::ZWaveProxyRequestType>(enums:
}
#endif
void HelloRequest::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "HelloRequest");
out.append(" client_info: ");
@@ -1095,7 +1094,7 @@ void SubscribeLogsResponse::dump_to(std::string &out) const {
void NoiseEncryptionSetKeyRequest::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "NoiseEncryptionSetKeyRequest");
out.append(" key: ");
out.append(format_hex_pretty(reinterpret_cast<const uint8_t *>(this->key.data()), this->key.size()));
out.append(format_hex_pretty(reinterpret_cast<const uint8_t*>(this->key.data()), this->key.size()));
out.append("\n");
}
void NoiseEncryptionSetKeyResponse::dump_to(std::string &out) const { dump_field(out, "success", this->success); }
@@ -1221,6 +1220,22 @@ void ExecuteServiceRequest::dump_to(std::string &out) const {
it.dump_to(out);
out.append("\n");
}
#ifdef USE_API_SERVICE_RESPONSES
dump_field(out, "call_id", this->call_id);
#endif
}
#endif
#ifdef USE_API_SERVICE_RESPONSES
void ExecuteServiceResponse::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "ExecuteServiceResponse");
dump_field(out, "call_id", this->call_id);
dump_field(out, "success", this->success);
dump_field(out, "error_message", this->error_message_ref_);
#ifdef USE_API_SERVICE_RESPONSE_JSON
out.append(" response_data: ");
out.append(format_hex_pretty(this->response_data, this->response_data_len));
out.append("\n");
#endif
}
#endif
#ifdef USE_CAMERA
@@ -1823,10 +1838,10 @@ void VoiceAssistantAudio::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "VoiceAssistantAudio");
out.append(" data: ");
if (this->data_ptr_ != nullptr) {
out.append(format_hex_pretty(this->data_ptr_, this->data_len_));
} else {
out.append(format_hex_pretty(reinterpret_cast<const uint8_t *>(this->data.data()), this->data.size()));
}
out.append(format_hex_pretty(this->data_ptr_, this->data_len_));
} else {
out.append(format_hex_pretty(reinterpret_cast<const uint8_t*>(this->data.data()), this->data.size()));
}
out.append("\n");
dump_field(out, "end", this->end);
}

View File

@@ -654,14 +654,17 @@ void APIServerConnection::on_device_info_request(const DeviceInfoRequest &msg) {
this->on_fatal_error();
}
}
void APIServerConnection::on_list_entities_request(const ListEntitiesRequest &msg) { this->list_entities(msg); }
void APIServerConnection::on_list_entities_request(const ListEntitiesRequest &msg) {
this->list_entities(msg);
}
void APIServerConnection::on_subscribe_states_request(const SubscribeStatesRequest &msg) {
this->subscribe_states(msg);
}
void APIServerConnection::on_subscribe_logs_request(const SubscribeLogsRequest &msg) { this->subscribe_logs(msg); }
void APIServerConnection::on_subscribe_logs_request(const SubscribeLogsRequest &msg) {
this->subscribe_logs(msg);
}
#ifdef USE_API_HOMEASSISTANT_SERVICES
void APIServerConnection::on_subscribe_homeassistant_services_request(
const SubscribeHomeassistantServicesRequest &msg) {
void APIServerConnection::on_subscribe_homeassistant_services_request(const SubscribeHomeassistantServicesRequest &msg) {
this->subscribe_homeassistant_services(msg);
}
#endif
@@ -671,7 +674,9 @@ void APIServerConnection::on_subscribe_home_assistant_states_request(const Subsc
}
#endif
#ifdef USE_API_SERVICES
void APIServerConnection::on_execute_service_request(const ExecuteServiceRequest &msg) { this->execute_service(msg); }
void APIServerConnection::on_execute_service_request(const ExecuteServiceRequest &msg) {
this->execute_service(msg);
}
#endif
#ifdef USE_API_NOISE
void APIServerConnection::on_noise_encryption_set_key_request(const NoiseEncryptionSetKeyRequest &msg) {
@@ -681,19 +686,29 @@ void APIServerConnection::on_noise_encryption_set_key_request(const NoiseEncrypt
}
#endif
#ifdef USE_BUTTON
void APIServerConnection::on_button_command_request(const ButtonCommandRequest &msg) { this->button_command(msg); }
void APIServerConnection::on_button_command_request(const ButtonCommandRequest &msg) {
this->button_command(msg);
}
#endif
#ifdef USE_CAMERA
void APIServerConnection::on_camera_image_request(const CameraImageRequest &msg) { this->camera_image(msg); }
void APIServerConnection::on_camera_image_request(const CameraImageRequest &msg) {
this->camera_image(msg);
}
#endif
#ifdef USE_CLIMATE
void APIServerConnection::on_climate_command_request(const ClimateCommandRequest &msg) { this->climate_command(msg); }
void APIServerConnection::on_climate_command_request(const ClimateCommandRequest &msg) {
this->climate_command(msg);
}
#endif
#ifdef USE_COVER
void APIServerConnection::on_cover_command_request(const CoverCommandRequest &msg) { this->cover_command(msg); }
void APIServerConnection::on_cover_command_request(const CoverCommandRequest &msg) {
this->cover_command(msg);
}
#endif
#ifdef USE_DATETIME_DATE
void APIServerConnection::on_date_command_request(const DateCommandRequest &msg) { this->date_command(msg); }
void APIServerConnection::on_date_command_request(const DateCommandRequest &msg) {
this->date_command(msg);
}
#endif
#ifdef USE_DATETIME_DATETIME
void APIServerConnection::on_date_time_command_request(const DateTimeCommandRequest &msg) {
@@ -701,13 +716,19 @@ void APIServerConnection::on_date_time_command_request(const DateTimeCommandRequ
}
#endif
#ifdef USE_FAN
void APIServerConnection::on_fan_command_request(const FanCommandRequest &msg) { this->fan_command(msg); }
void APIServerConnection::on_fan_command_request(const FanCommandRequest &msg) {
this->fan_command(msg);
}
#endif
#ifdef USE_LIGHT
void APIServerConnection::on_light_command_request(const LightCommandRequest &msg) { this->light_command(msg); }
void APIServerConnection::on_light_command_request(const LightCommandRequest &msg) {
this->light_command(msg);
}
#endif
#ifdef USE_LOCK
void APIServerConnection::on_lock_command_request(const LockCommandRequest &msg) { this->lock_command(msg); }
void APIServerConnection::on_lock_command_request(const LockCommandRequest &msg) {
this->lock_command(msg);
}
#endif
#ifdef USE_MEDIA_PLAYER
void APIServerConnection::on_media_player_command_request(const MediaPlayerCommandRequest &msg) {
@@ -715,32 +736,47 @@ void APIServerConnection::on_media_player_command_request(const MediaPlayerComma
}
#endif
#ifdef USE_NUMBER
void APIServerConnection::on_number_command_request(const NumberCommandRequest &msg) { this->number_command(msg); }
void APIServerConnection::on_number_command_request(const NumberCommandRequest &msg) {
this->number_command(msg);
}
#endif
#ifdef USE_SELECT
void APIServerConnection::on_select_command_request(const SelectCommandRequest &msg) { this->select_command(msg); }
void APIServerConnection::on_select_command_request(const SelectCommandRequest &msg) {
this->select_command(msg);
}
#endif
#ifdef USE_SIREN
void APIServerConnection::on_siren_command_request(const SirenCommandRequest &msg) { this->siren_command(msg); }
void APIServerConnection::on_siren_command_request(const SirenCommandRequest &msg) {
this->siren_command(msg);
}
#endif
#ifdef USE_SWITCH
void APIServerConnection::on_switch_command_request(const SwitchCommandRequest &msg) { this->switch_command(msg); }
void APIServerConnection::on_switch_command_request(const SwitchCommandRequest &msg) {
this->switch_command(msg);
}
#endif
#ifdef USE_TEXT
void APIServerConnection::on_text_command_request(const TextCommandRequest &msg) { this->text_command(msg); }
void APIServerConnection::on_text_command_request(const TextCommandRequest &msg) {
this->text_command(msg);
}
#endif
#ifdef USE_DATETIME_TIME
void APIServerConnection::on_time_command_request(const TimeCommandRequest &msg) { this->time_command(msg); }
void APIServerConnection::on_time_command_request(const TimeCommandRequest &msg) {
this->time_command(msg);
}
#endif
#ifdef USE_UPDATE
void APIServerConnection::on_update_command_request(const UpdateCommandRequest &msg) { this->update_command(msg); }
void APIServerConnection::on_update_command_request(const UpdateCommandRequest &msg) {
this->update_command(msg);
}
#endif
#ifdef USE_VALVE
void APIServerConnection::on_valve_command_request(const ValveCommandRequest &msg) { this->valve_command(msg); }
void APIServerConnection::on_valve_command_request(const ValveCommandRequest &msg) {
this->valve_command(msg);
}
#endif
#ifdef USE_BLUETOOTH_PROXY
void APIServerConnection::on_subscribe_bluetooth_le_advertisements_request(
const SubscribeBluetoothLEAdvertisementsRequest &msg) {
void APIServerConnection::on_subscribe_bluetooth_le_advertisements_request(const SubscribeBluetoothLEAdvertisementsRequest &msg) {
this->subscribe_bluetooth_le_advertisements(msg);
}
#endif
@@ -780,16 +816,14 @@ void APIServerConnection::on_bluetooth_gatt_notify_request(const BluetoothGATTNo
}
#endif
#ifdef USE_BLUETOOTH_PROXY
void APIServerConnection::on_subscribe_bluetooth_connections_free_request(
const SubscribeBluetoothConnectionsFreeRequest &msg) {
void APIServerConnection::on_subscribe_bluetooth_connections_free_request(const SubscribeBluetoothConnectionsFreeRequest &msg) {
if (!this->send_subscribe_bluetooth_connections_free_response(msg)) {
this->on_fatal_error();
}
}
#endif
#ifdef USE_BLUETOOTH_PROXY
void APIServerConnection::on_unsubscribe_bluetooth_le_advertisements_request(
const UnsubscribeBluetoothLEAdvertisementsRequest &msg) {
void APIServerConnection::on_unsubscribe_bluetooth_le_advertisements_request(const UnsubscribeBluetoothLEAdvertisementsRequest &msg) {
this->unsubscribe_bluetooth_le_advertisements(msg);
}
#endif
@@ -821,10 +855,14 @@ void APIServerConnection::on_alarm_control_panel_command_request(const AlarmCont
}
#endif
#ifdef USE_ZWAVE_PROXY
void APIServerConnection::on_z_wave_proxy_frame(const ZWaveProxyFrame &msg) { this->zwave_proxy_frame(msg); }
void APIServerConnection::on_z_wave_proxy_frame(const ZWaveProxyFrame &msg) {
this->zwave_proxy_frame(msg);
}
#endif
#ifdef USE_ZWAVE_PROXY
void APIServerConnection::on_z_wave_proxy_request(const ZWaveProxyRequest &msg) { this->zwave_proxy_request(msg); }
void APIServerConnection::on_z_wave_proxy_request(const ZWaveProxyRequest &msg) {
this->zwave_proxy_request(msg);
}
#endif
void APIServerConnection::read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) {
@@ -835,8 +873,8 @@ void APIServerConnection::read_message(uint32_t msg_size, uint32_t msg_type, uin
case AuthenticationRequest::MESSAGE_TYPE: // No setup required
#endif
case DisconnectRequest::MESSAGE_TYPE: // No setup required
case PingRequest::MESSAGE_TYPE: // No setup required
break; // Skip all checks for these messages
case PingRequest::MESSAGE_TYPE: // No setup required
break; // Skip all checks for these messages
case DeviceInfoRequest::MESSAGE_TYPE: // Connection setup only
if (!this->check_connection_setup_()) {
return; // Connection not setup

View File

@@ -13,7 +13,6 @@ class APIServerConnectionBase : public ProtoService {
#ifdef HAS_PROTO_MESSAGE_DUMP
protected:
void log_send_message_(const char *name, const std::string &dump);
public:
#endif
@@ -40,22 +39,31 @@ class APIServerConnectionBase : public ProtoService {
virtual void on_subscribe_states_request(const SubscribeStatesRequest &value){};
#ifdef USE_COVER
virtual void on_cover_command_request(const CoverCommandRequest &value){};
#endif
#ifdef USE_FAN
virtual void on_fan_command_request(const FanCommandRequest &value){};
#endif
#ifdef USE_LIGHT
virtual void on_light_command_request(const LightCommandRequest &value){};
#endif
#ifdef USE_SWITCH
virtual void on_switch_command_request(const SwitchCommandRequest &value){};
#endif
virtual void on_subscribe_logs_request(const SubscribeLogsRequest &value){};
#ifdef USE_API_NOISE
@@ -83,26 +91,33 @@ class APIServerConnectionBase : public ProtoService {
virtual void on_execute_service_request(const ExecuteServiceRequest &value){};
#endif
#ifdef USE_CAMERA
virtual void on_camera_image_request(const CameraImageRequest &value){};
#endif
#ifdef USE_CLIMATE
virtual void on_climate_command_request(const ClimateCommandRequest &value){};
#endif
#ifdef USE_NUMBER
virtual void on_number_command_request(const NumberCommandRequest &value){};
#endif
#ifdef USE_SELECT
virtual void on_select_command_request(const SelectCommandRequest &value){};
#endif
#ifdef USE_SIREN
virtual void on_siren_command_request(const SirenCommandRequest &value){};
#endif
#ifdef USE_LOCK
virtual void on_lock_command_request(const LockCommandRequest &value){};
#endif
@@ -111,12 +126,12 @@ class APIServerConnectionBase : public ProtoService {
virtual void on_button_command_request(const ButtonCommandRequest &value){};
#endif
#ifdef USE_MEDIA_PLAYER
virtual void on_media_player_command_request(const MediaPlayerCommandRequest &value){};
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual void on_subscribe_bluetooth_le_advertisements_request(
const SubscribeBluetoothLEAdvertisementsRequest &value){};
virtual void on_subscribe_bluetooth_le_advertisements_request(const SubscribeBluetoothLEAdvertisementsRequest &value){};
#endif
#ifdef USE_BLUETOOTH_PROXY
@@ -127,6 +142,7 @@ class APIServerConnectionBase : public ProtoService {
virtual void on_bluetooth_gatt_get_services_request(const BluetoothGATTGetServicesRequest &value){};
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual void on_bluetooth_gatt_read_request(const BluetoothGATTReadRequest &value){};
#endif
@@ -148,11 +164,16 @@ class APIServerConnectionBase : public ProtoService {
virtual void on_subscribe_bluetooth_connections_free_request(const SubscribeBluetoothConnectionsFreeRequest &value){};
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual void on_unsubscribe_bluetooth_le_advertisements_request(
const UnsubscribeBluetoothLEAdvertisementsRequest &value){};
virtual void on_unsubscribe_bluetooth_le_advertisements_request(const UnsubscribeBluetoothLEAdvertisementsRequest &value){};
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual void on_bluetooth_scanner_set_mode_request(const BluetoothScannerSetModeRequest &value){};
#endif
@@ -184,30 +205,39 @@ class APIServerConnectionBase : public ProtoService {
virtual void on_voice_assistant_set_configuration(const VoiceAssistantSetConfiguration &value){};
#endif
#ifdef USE_ALARM_CONTROL_PANEL
virtual void on_alarm_control_panel_command_request(const AlarmControlPanelCommandRequest &value){};
#endif
#ifdef USE_TEXT
virtual void on_text_command_request(const TextCommandRequest &value){};
#endif
#ifdef USE_DATETIME_DATE
virtual void on_date_command_request(const DateCommandRequest &value){};
#endif
#ifdef USE_DATETIME_TIME
virtual void on_time_command_request(const TimeCommandRequest &value){};
#endif
#ifdef USE_VALVE
virtual void on_valve_command_request(const ValveCommandRequest &value){};
#endif
#ifdef USE_DATETIME_DATETIME
virtual void on_date_time_command_request(const DateTimeCommandRequest &value){};
#endif
#ifdef USE_UPDATE
virtual void on_update_command_request(const UpdateCommandRequest &value){};
#endif
@@ -324,8 +354,7 @@ class APIServerConnection : public APIServerConnectionBase {
virtual void bluetooth_gatt_notify(const BluetoothGATTNotifyRequest &msg) = 0;
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual bool send_subscribe_bluetooth_connections_free_response(
const SubscribeBluetoothConnectionsFreeRequest &msg) = 0;
virtual bool send_subscribe_bluetooth_connections_free_response(const SubscribeBluetoothConnectionsFreeRequest &msg) = 0;
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual void unsubscribe_bluetooth_le_advertisements(const UnsubscribeBluetoothLEAdvertisementsRequest &msg) = 0;
@@ -456,8 +485,7 @@ class APIServerConnection : public APIServerConnectionBase {
void on_subscribe_bluetooth_connections_free_request(const SubscribeBluetoothConnectionsFreeRequest &msg) override;
#endif
#ifdef USE_BLUETOOTH_PROXY
void on_unsubscribe_bluetooth_le_advertisements_request(
const UnsubscribeBluetoothLEAdvertisementsRequest &msg) override;
void on_unsubscribe_bluetooth_le_advertisements_request(const UnsubscribeBluetoothLEAdvertisementsRequest &msg) override;
#endif
#ifdef USE_BLUETOOTH_PROXY
void on_bluetooth_scanner_set_mode_request(const BluetoothScannerSetModeRequest &msg) override;

View File

@@ -430,6 +430,30 @@ void APIServer::handle_action_response(uint32_t call_id, bool success, const std
#endif // USE_API_HOMEASSISTANT_ACTION_RESPONSES
#endif // USE_API_HOMEASSISTANT_SERVICES
#ifdef USE_API_SERVICE_RESPONSES
void APIServer::send_service_response(bool success, const std::string &error_message) {
if (this->current_service_connection_ == nullptr || this->current_service_call_id_ == 0) {
ESP_LOGW(TAG, "Cannot send service response: no active service call");
return;
}
this->current_service_connection_->send_execute_service_response(this->current_service_call_id_, success,
error_message);
this->clear_current_service_call();
}
#ifdef USE_API_SERVICE_RESPONSE_JSON
void APIServer::send_service_response(bool success, const std::string &error_message, const uint8_t *response_data,
size_t response_data_len) {
if (this->current_service_connection_ == nullptr || this->current_service_call_id_ == 0) {
ESP_LOGW(TAG, "Cannot send service response: no active service call");
return;
}
this->current_service_connection_->send_execute_service_response(this->current_service_call_id_, success,
error_message, response_data, response_data_len);
this->clear_current_service_call();
}
#endif // USE_API_SERVICE_RESPONSE_JSON
#endif // USE_API_SERVICE_RESPONSES
#ifdef USE_API_HOMEASSISTANT_STATES
void APIServer::subscribe_home_assistant_state(std::string entity_id, optional<std::string> attribute,
std::function<void(std::string)> f) {

View File

@@ -132,6 +132,25 @@ class APIServer : public Component, public Controller {
// Only compile push_back method when custom_services: true (external components)
void register_user_service(UserServiceDescriptor *descriptor) { this->user_services_.push_back(descriptor); }
#endif
#ifdef USE_API_SERVICE_RESPONSES
// Service response handling - set context before triggering service, clear after
void set_current_service_call(uint32_t call_id, APIConnection *conn) {
this->current_service_call_id_ = call_id;
this->current_service_connection_ = conn;
}
void clear_current_service_call() {
this->current_service_call_id_ = 0;
this->current_service_connection_ = nullptr;
}
uint32_t get_current_service_call_id() const { return this->current_service_call_id_; }
bool has_current_service_call() const { return this->current_service_call_id_ != 0; }
// Send response for current service call
void send_service_response(bool success, const std::string &error_message);
#ifdef USE_API_SERVICE_RESPONSE_JSON
void send_service_response(bool success, const std::string &error_message, const uint8_t *response_data,
size_t response_data_len);
#endif // USE_API_SERVICE_RESPONSE_JSON
#endif // USE_API_SERVICE_RESPONSES
#endif
#ifdef USE_HOMEASSISTANT_TIME
void request_time();
@@ -208,6 +227,11 @@ class APIServer : public Component, public Controller {
#endif
#ifdef USE_API_SERVICES
std::vector<UserServiceDescriptor *> user_services_;
#ifdef USE_API_SERVICE_RESPONSES
// Current service call context for sending responses
uint32_t current_service_call_id_{0};
APIConnection *current_service_connection_{nullptr};
#endif // USE_API_SERVICE_RESPONSES
#endif
#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES
struct PendingActionResponse {

View File

@@ -6,6 +6,10 @@
#include "esphome/core/component.h"
#include "esphome/core/automation.h"
#include "api_pb2.h"
#include "api_server.h"
#ifdef USE_API_SERVICE_RESPONSE_JSON
#include "esphome/components/json/json_util.h"
#endif
#ifdef USE_API_SERVICES
namespace esphome::api {
@@ -121,5 +125,59 @@ template<typename... Ts> class UserServiceTrigger : public UserServiceBase<Ts...
void execute(Ts... x) override { this->trigger(x...); } // NOLINT
};
#ifdef USE_API_SERVICE_RESPONSES
template<typename... Ts> class APIRespondAction : public Action<Ts...> {
public:
explicit APIRespondAction(APIServer *parent) : parent_(parent) {}
template<typename V> void set_success(V success) { this->success_ = success; }
template<typename V> void set_error_message(V error) { this->error_message_ = error; }
#ifdef USE_API_SERVICE_RESPONSE_JSON
void set_data(std::function<void(Ts..., JsonObject)> func) {
this->json_builder_ = std::move(func);
this->has_data_ = true;
}
#endif
void play(Ts... x) override {
if (!this->parent_->has_current_service_call()) {
ESP_LOGW("api", "api.respond called outside of service execution context");
return;
}
bool success = this->success_.value(x...);
std::string error_message = this->error_message_.value(x...);
#ifdef USE_API_SERVICE_RESPONSE_JSON
if (this->has_data_) {
// Build JSON response
std::string json_str;
{
JsonDocument doc;
JsonObject root = doc.to<JsonObject>();
this->json_builder_(x..., root);
json::serialize_json(root, json_str);
}
this->parent_->send_service_response(success, error_message, reinterpret_cast<const uint8_t *>(json_str.data()),
json_str.size());
} else
#endif
{
this->parent_->send_service_response(success, error_message);
}
}
protected:
APIServer *parent_;
TemplatableValue<bool, Ts...> success_{true};
TemplatableValue<std::string, Ts...> error_message_{""};
#ifdef USE_API_SERVICE_RESPONSE_JSON
std::function<void(Ts..., JsonObject)> json_builder_;
bool has_data_{false};
#endif
};
#endif // USE_API_SERVICE_RESPONSES
} // namespace esphome::api
#endif // USE_API_SERVICES

View File

@@ -126,6 +126,8 @@
#define USE_API_PLAINTEXT
#define USE_API_SERVICES
#define USE_API_CUSTOM_SERVICES
#define USE_API_SERVICE_RESPONSES
#define USE_API_SERVICE_RESPONSE_JSON
#define API_MAX_SEND_QUEUE 8
#define USE_MD5
#define USE_SHA256

View File

@@ -177,6 +177,47 @@ api:
else:
- logger.log: "Skipped loops"
- logger.log: "After combined test"
# Test api.respond action - simple success response
- action: test_respond_simple
then:
- api.respond:
success: true
# Test api.respond action - with error message
- action: test_respond_error
variables:
error_msg: string
then:
- api.respond:
success: false
error_message: !lambda 'return error_msg;'
# Test api.respond action - with JSON data
- action: test_respond_with_data
variables:
sensor_name: string
value: float
then:
- api.respond:
data: |-
root["sensor"] = sensor_name;
root["value"] = value;
root["unit"] = "°C";
# Test api.respond action - conditional response
- action: test_respond_conditional
variables:
do_succeed: bool
then:
- if:
condition:
lambda: 'return do_succeed;'
then:
- api.respond:
success: true
data: |-
root["status"] = "ok";
else:
- api.respond:
success: false
error_message: "Operation failed"
event:
- platform: template