This commit is contained in:
J. Nick Koston
2026-03-03 18:35:00 -10:00
parent 0a816192b2
commit 1e7eba1e90
5 changed files with 54 additions and 52 deletions
+17 -15
View File
@@ -343,19 +343,19 @@ void APIConnection::on_disconnect_response() {
this->flags_.remove = true;
}
uint16_t APIConnection::fill_and_encode_entity_state_(EntityBase *entity, StateResponseProtoMessage &msg,
CalculateSizeFn size_fn, MessageEncodeFn encode_fn,
APIConnection *conn, uint32_t remaining_size) {
uint16_t APIConnection::fill_and_encode_entity_state(EntityBase *entity, StateResponseProtoMessage &msg,
CalculateSizeFn size_fn, MessageEncodeFn encode_fn,
APIConnection *conn, uint32_t remaining_size) {
msg.key = entity->get_object_id_hash();
#ifdef USE_DEVICES
msg.device_id = entity->get_device_id();
#endif
return encode_to_buffer_(size_fn(&msg), encode_fn, &msg, conn, remaining_size);
return encode_to_buffer(size_fn(&msg), encode_fn, &msg, conn, remaining_size);
}
uint16_t APIConnection::fill_and_encode_entity_info_(EntityBase *entity, InfoResponseProtoMessage &msg,
CalculateSizeFn size_fn, MessageEncodeFn encode_fn,
APIConnection *conn, uint32_t remaining_size) {
uint16_t APIConnection::fill_and_encode_entity_info(EntityBase *entity, InfoResponseProtoMessage &msg,
CalculateSizeFn size_fn, MessageEncodeFn encode_fn,
APIConnection *conn, uint32_t remaining_size) {
// Set common fields that are shared by all entity types
msg.key = entity->get_object_id_hash();
@@ -363,7 +363,7 @@ uint16_t APIConnection::fill_and_encode_entity_info_(EntityBase *entity, InfoRes
// For older clients, we must send object_id for backward compatibility
// See: https://github.com/esphome/backlog/issues/76
// TODO: Remove this backward compat code before 2026.7.0 - all clients should support API 1.14 by then
// Buffer must remain in scope until encode_to_buffer_ is called
// Buffer must remain in scope until encode_to_buffer is called
char object_id_buf[OBJECT_ID_MAX_LEN];
if (!conn->client_supports_api_version(1, 14)) {
msg.object_id = entity->get_object_id_to(object_id_buf);
@@ -383,15 +383,17 @@ uint16_t APIConnection::fill_and_encode_entity_info_(EntityBase *entity, InfoRes
#ifdef USE_DEVICES
msg.device_id = entity->get_device_id();
#endif
return encode_to_buffer_(size_fn(&msg), encode_fn, &msg, conn, remaining_size);
return encode_to_buffer(size_fn(&msg), encode_fn, &msg, conn, remaining_size);
}
uint16_t APIConnection::fill_and_encode_entity_info_with_device_class_(
EntityBase *entity, InfoResponseProtoMessage &msg, StringRef &device_class_field, CalculateSizeFn size_fn,
MessageEncodeFn encode_fn, APIConnection *conn, uint32_t remaining_size) {
uint16_t APIConnection::fill_and_encode_entity_info_with_device_class(EntityBase *entity, InfoResponseProtoMessage &msg,
StringRef &device_class_field,
CalculateSizeFn size_fn,
MessageEncodeFn encode_fn, APIConnection *conn,
uint32_t remaining_size) {
char dc_buf[MAX_DEVICE_CLASS_LENGTH];
device_class_field = StringRef(entity->get_device_class_to(dc_buf));
return fill_and_encode_entity_info_(entity, msg, size_fn, encode_fn, conn, remaining_size);
return fill_and_encode_entity_info(entity, msg, size_fn, encode_fn, conn, remaining_size);
}
#ifdef USE_BINARY_SENSOR
@@ -1876,8 +1878,8 @@ bool APIConnection::send_message_(uint32_t payload_size, uint8_t message_type, M
}
// Encodes a message to the buffer and returns the total number of bytes used,
// including header and footer overhead. Returns 0 if the message doesn't fit.
uint16_t APIConnection::encode_to_buffer_(uint32_t calculated_size, MessageEncodeFn encode_fn, const void *msg,
APIConnection *conn, uint32_t remaining_size) {
uint16_t APIConnection::encode_to_buffer(uint32_t calculated_size, MessageEncodeFn encode_fn, const void *msg,
APIConnection *conn, uint32_t remaining_size) {
// Cache frame sizes to avoid repeated virtual calls
const uint8_t header_padding = conn->helper_->frame_header_padding();
const uint8_t footer_size = conn->helper_->frame_footer_size();
+30 -30
View File
@@ -269,9 +269,9 @@ class APIConnection final : public APIServerConnectionBase {
this->log_send_message_(msg.message_name(), msg.dump_to(dump_buf));
#endif
if constexpr (T::ESTIMATED_SIZE == 0) {
return this->send_message_(0, T::MESSAGE_TYPE, &encode_msg_noop_, &msg);
return this->send_message_(0, T::MESSAGE_TYPE, &encode_msg_noop, &msg);
} else {
return this->send_message_(msg.calculate_size(), T::MESSAGE_TYPE, &encode_msg_<T>, &msg);
return this->send_message_(msg.calculate_size(), T::MESSAGE_TYPE, &encode_msg<T>, &msg);
}
}
@@ -339,14 +339,14 @@ class APIConnection final : public APIServerConnectionBase {
}
// Shared no-op encode thunk for empty messages (ESTIMATED_SIZE == 0)
static void encode_msg_noop_(const void *, ProtoWriteBuffer &) {}
static void encode_msg_noop(const void *, ProtoWriteBuffer &) {}
// Non-template buffer management for send_message
bool send_message_(uint32_t payload_size, uint8_t message_type, MessageEncodeFn encode_fn, const void *msg);
// Non-template buffer management for batch encoding
static uint16_t encode_to_buffer_(uint32_t calculated_size, MessageEncodeFn encode_fn, const void *msg,
APIConnection *conn, uint32_t remaining_size);
static uint16_t encode_to_buffer(uint32_t calculated_size, MessageEncodeFn encode_fn, const void *msg,
APIConnection *conn, uint32_t remaining_size);
// Thin template wrapper — computes size, delegates buffer work to non-template helper
template<typename T> static uint16_t encode_message_to_buffer(T &msg, APIConnection *conn, uint32_t remaining_size) {
@@ -358,49 +358,49 @@ class APIConnection final : public APIServerConnectionBase {
}
#endif
if constexpr (T::ESTIMATED_SIZE == 0) {
return encode_to_buffer_(0, &encode_msg_noop_, &msg, conn, remaining_size);
return encode_to_buffer(0, &encode_msg_noop, &msg, conn, remaining_size);
} else {
return encode_to_buffer_(msg.calculate_size(), &encode_msg_<T>, &msg, conn, remaining_size);
return encode_to_buffer(msg.calculate_size(), &encode_msg<T>, &msg, conn, remaining_size);
}
}
// Non-template core — fills state fields and encodes
static uint16_t fill_and_encode_entity_state_(EntityBase *entity, StateResponseProtoMessage &msg,
CalculateSizeFn size_fn, MessageEncodeFn encode_fn, APIConnection *conn,
uint32_t remaining_size);
// Thin template wrapper
template<typename T>
static uint16_t fill_and_encode_entity_state(EntityBase *entity, T &msg, APIConnection *conn,
uint32_t remaining_size) {
return fill_and_encode_entity_state_(entity, msg, &calc_size_<T>, &encode_msg_<T>, conn, remaining_size);
}
// Non-template core — fills info fields, allocates buffers, and encodes
static uint16_t fill_and_encode_entity_info_(EntityBase *entity, InfoResponseProtoMessage &msg,
static uint16_t fill_and_encode_entity_state(EntityBase *entity, StateResponseProtoMessage &msg,
CalculateSizeFn size_fn, MessageEncodeFn encode_fn, APIConnection *conn,
uint32_t remaining_size);
// Thin template wrapper
template<typename T>
static uint16_t fill_and_encode_entity_info(EntityBase *entity, T &msg, APIConnection *conn,
uint32_t remaining_size) {
return fill_and_encode_entity_info_(entity, msg, &calc_size_<T>, &encode_msg_<T>, conn, remaining_size);
static uint16_t fill_and_encode_entity_state(EntityBase *entity, T &msg, APIConnection *conn,
uint32_t remaining_size) {
return fill_and_encode_entity_state(entity, msg, &calc_size<T>, &encode_msg<T>, conn, remaining_size);
}
// Non-template core — fills device_class, then delegates to fill_and_encode_entity_info_
static uint16_t fill_and_encode_entity_info_with_device_class_(EntityBase *entity, InfoResponseProtoMessage &msg,
StringRef &device_class_field, CalculateSizeFn size_fn,
MessageEncodeFn encode_fn, APIConnection *conn,
uint32_t remaining_size);
// Non-template core — fills info fields, allocates buffers, and encodes
static uint16_t fill_and_encode_entity_info(EntityBase *entity, InfoResponseProtoMessage &msg,
CalculateSizeFn size_fn, MessageEncodeFn encode_fn, APIConnection *conn,
uint32_t remaining_size);
// Thin template wrapper
template<typename T>
static uint16_t fill_and_encode_entity_info(EntityBase *entity, T &msg, APIConnection *conn,
uint32_t remaining_size) {
return fill_and_encode_entity_info(entity, msg, &calc_size<T>, &encode_msg<T>, conn, remaining_size);
}
// Non-template core — fills device_class, then delegates to fill_and_encode_entity_info
static uint16_t fill_and_encode_entity_info_with_device_class(EntityBase *entity, InfoResponseProtoMessage &msg,
StringRef &device_class_field, CalculateSizeFn size_fn,
MessageEncodeFn encode_fn, APIConnection *conn,
uint32_t remaining_size);
// Thin template wrapper
template<typename T>
static uint16_t fill_and_encode_entity_info_with_device_class(EntityBase *entity, T &msg,
StringRef &device_class_field, APIConnection *conn,
uint32_t remaining_size) {
return fill_and_encode_entity_info_with_device_class_(entity, msg, device_class_field, &calc_size_<T>,
&encode_msg_<T>, conn, remaining_size);
return fill_and_encode_entity_info_with_device_class(entity, msg, device_class_field, &calc_size<T>, &encode_msg<T>,
conn, remaining_size);
}
#ifdef USE_VOICE_ASSISTANT
+1 -1
View File
@@ -359,7 +359,7 @@ void APIServer::on_update(update::UpdateEntity *obj) {
#endif
#ifdef USE_ZWAVE_PROXY
void APIServer::on_zwave_proxy_request(const esphome::api::ProtoMessage &msg) {
void APIServer::on_zwave_proxy_request(const ZWaveProxyRequest &msg) {
// We could add code to manage a second subscription type, but, since this message type is
// very infrequent and small, we simply send it to all clients
for (auto &c : this->clients_)
+1 -1
View File
@@ -179,7 +179,7 @@ class APIServer : public Component,
void on_update(update::UpdateEntity *obj) override;
#endif
#ifdef USE_ZWAVE_PROXY
void on_zwave_proxy_request(const esphome::api::ProtoMessage &msg);
void on_zwave_proxy_request(const ZWaveProxyRequest &msg);
#endif
#ifdef USE_IR_RF
void send_infrared_rf_receive_event(uint32_t device_id, uint32_t key, const std::vector<int32_t> *timings);
+5 -5
View File
@@ -367,8 +367,8 @@ class ProtoWriteBuffer {
/// Templated so concrete message type is preserved for direct encode/calculate_size calls.
template<typename T> void encode_message(uint32_t field_id, const T &value, bool force = true);
// Non-template core for encode_message — all buffer work happens here
void encode_message_(uint32_t field_id, uint32_t msg_length_bytes, const void *value,
void (*encode_fn)(const void *, ProtoWriteBuffer &), bool force);
void encode_message(uint32_t field_id, uint32_t msg_length_bytes, const void *value,
void (*encode_fn)(const void *, ProtoWriteBuffer &), bool force);
std::vector<uint8_t> *get_buffer() const { return buffer_; }
protected:
@@ -936,14 +936,14 @@ inline void ProtoWriteBuffer::encode_packed_sint32(uint32_t field_id, const std:
// Implementation of encode_message - must be after ProtoMessage is defined
template<typename T> inline void ProtoWriteBuffer::encode_message(uint32_t field_id, const T &value, bool force) {
uint32_t msg_length_bytes = value.calculate_size();
this->encode_message_(
this->encode_message(
field_id, msg_length_bytes, &value,
[](const void *msg, ProtoWriteBuffer &buf) { static_cast<const T *>(msg)->encode(buf); }, force);
}
// Non-template core for encode_message
inline void ProtoWriteBuffer::encode_message_(uint32_t field_id, uint32_t msg_length_bytes, const void *value,
void (*encode_fn)(const void *, ProtoWriteBuffer &), bool force) {
inline void ProtoWriteBuffer::encode_message(uint32_t field_id, uint32_t msg_length_bytes, const void *value,
void (*encode_fn)(const void *, ProtoWriteBuffer &), bool force) {
if (msg_length_bytes == 0 && !force)
return;
this->encode_field_raw(field_id, 2);