mirror of
https://github.com/esphome/esphome.git
synced 2026-09-13 16:18:41 +00:00
[api] Add max_data_length and force to DeviceInfoResponse/HelloResponse proto fields
Add max_data_length + force proto options to string fields in HelloResponse, AreaInfo, DeviceInfo, and DeviceInfoResponse where we have strong compile-time or codegen guarantees on max length. This enables encode_short_string_force() (direct byte writes, no varint branching) for fields with single-byte tags, and fixed-formula size calculations for all annotated fields. Add static_asserts to cross-validate C++ constexpr constants (MAC_ADDRESS_PRETTY_BUFFER_SIZE, BUILD_TIME_STR_SIZE, ESPHOME_VERSION, ESPHOME_MANUFACTURER) against the proto max_data_length annotations.
This commit is contained in:
@@ -129,11 +129,12 @@ message HelloResponse {
|
||||
|
||||
// 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;
|
||||
// Currently set to ESPHOME_VERSION string literal.
|
||||
string server_info = 3 [(max_data_length) = 32, (force) = true];
|
||||
|
||||
// The name of the server (App.get_name())
|
||||
string name = 4;
|
||||
// max_data_length matches config_validation.NAME_MAX_LENGTH
|
||||
string name = 4 [(max_data_length) = 120, (force) = true];
|
||||
}
|
||||
|
||||
// DEPRECATED in ESPHome 2026.1.0 - Password authentication is no longer supported.
|
||||
@@ -196,12 +197,14 @@ message DeviceInfoRequest {
|
||||
|
||||
message AreaInfo {
|
||||
uint32 area_id = 1;
|
||||
string name = 2;
|
||||
// max_data_length matches core/config.FRIENDLY_NAME_MAX_LEN via AREA_SCHEMA
|
||||
string name = 2 [(max_data_length) = 120, (force) = true];
|
||||
}
|
||||
|
||||
message DeviceInfo {
|
||||
uint32 device_id = 1;
|
||||
string name = 2;
|
||||
// max_data_length matches core/config.FRIENDLY_NAME_MAX_LEN via DEVICE_SCHEMA
|
||||
string name = 2 [(max_data_length) = 120, (force) = true];
|
||||
uint32 area_id = 3;
|
||||
}
|
||||
|
||||
@@ -216,6 +219,12 @@ message SerialProxyInfo {
|
||||
SerialProxyPortType port_type = 2; // Port type (RS232, RS485)
|
||||
}
|
||||
|
||||
// DeviceInfoResponse max_data_length values:
|
||||
// name/friendly_name = 120 (config_validation.NAME_MAX_LENGTH / core/config.FRIENDLY_NAME_MAX_LEN)
|
||||
// mac_address/bluetooth_mac_address = 17 (MAC_ADDRESS_PRETTY_BUFFER_SIZE - 1, constexpr)
|
||||
// esphome_version = 32 (ESPHOME_VERSION string literal)
|
||||
// compilation_time = 25 (Application::BUILD_TIME_STR_SIZE - 1, constexpr)
|
||||
// manufacturer = 20 (longest hardcoded literal: "Nordic Semiconductor")
|
||||
message DeviceInfoResponse {
|
||||
option (id) = 10;
|
||||
option (source) = SOURCE_SERVER;
|
||||
@@ -225,18 +234,18 @@ message DeviceInfoResponse {
|
||||
bool uses_password = 1 [deprecated = true];
|
||||
|
||||
// The name of the node, given by "App.set_name()"
|
||||
string name = 2;
|
||||
string name = 2 [(max_data_length) = 120, (force) = true];
|
||||
|
||||
// The mac address of the device. For example "AC:BC:32:89:0E:A9"
|
||||
string mac_address = 3;
|
||||
string mac_address = 3 [(max_data_length) = 17, (force) = true];
|
||||
|
||||
// A string describing the ESPHome version. For example "1.10.0"
|
||||
string esphome_version = 4;
|
||||
string esphome_version = 4 [(max_data_length) = 32, (force) = true];
|
||||
|
||||
// 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;
|
||||
string compilation_time = 5 [(max_data_length) = 25, (force) = true];
|
||||
|
||||
// The model of the board. For example NodeMCU
|
||||
string model = 6;
|
||||
@@ -253,9 +262,9 @@ message DeviceInfoResponse {
|
||||
uint32 legacy_bluetooth_proxy_version = 11 [deprecated=true, (field_ifdef) = "USE_BLUETOOTH_PROXY"];
|
||||
uint32 bluetooth_proxy_feature_flags = 15 [(field_ifdef) = "USE_BLUETOOTH_PROXY"];
|
||||
|
||||
string manufacturer = 12;
|
||||
string manufacturer = 12 [(max_data_length) = 20, (force) = true];
|
||||
|
||||
string friendly_name = 13;
|
||||
string friendly_name = 13 [(max_data_length) = 120, (force) = true];
|
||||
|
||||
// Deprecated in API version 1.10
|
||||
uint32 legacy_voice_assistant_version = 14 [deprecated=true, (field_ifdef) = "USE_VOICE_ASSISTANT"];
|
||||
@@ -264,7 +273,7 @@ message DeviceInfoResponse {
|
||||
string suggested_area = 16 [(field_ifdef) = "USE_AREAS"];
|
||||
|
||||
// The Bluetooth mac address of the device. For example "AC:BC:32:89:0E:AA"
|
||||
string bluetooth_mac_address = 18 [(field_ifdef) = "USE_BLUETOOTH_PROXY"];
|
||||
string bluetooth_mac_address = 18 [(max_data_length) = 17, (force) = true, (field_ifdef) = "USE_BLUETOOTH_PROXY"];
|
||||
|
||||
// Supports receiving and saving api encryption key
|
||||
bool api_encryption_supported = 19 [(field_ifdef) = "USE_API_NOISE"];
|
||||
|
||||
@@ -72,6 +72,12 @@ static constexpr uint32_t HANDSHAKE_TIMEOUT_MS = 60000;
|
||||
|
||||
static constexpr auto ESPHOME_VERSION_REF = StringRef::from_lit(ESPHOME_VERSION);
|
||||
|
||||
// Cross-validate C++ constants against proto max_data_length annotations in api.proto
|
||||
static_assert(MAC_ADDRESS_PRETTY_BUFFER_SIZE - 1 == 17,
|
||||
"Update max_data_length for mac_address/bluetooth_mac_address in api.proto");
|
||||
static_assert(Application::BUILD_TIME_STR_SIZE - 1 == 25, "Update max_data_length for compilation_time in api.proto");
|
||||
static_assert(sizeof(ESPHOME_VERSION) - 1 <= 32, "Update max_data_length for esphome_version in api.proto");
|
||||
|
||||
static const char *const TAG = "api.connection";
|
||||
#ifdef USE_CAMERA
|
||||
static const int CAMERA_STOP_STREAM = 5000;
|
||||
@@ -1716,6 +1722,7 @@ bool APIConnection::send_device_info_response_() {
|
||||
static constexpr auto MANUFACTURER = StringRef::from_lit(ESPHOME_MANUFACTURER);
|
||||
resp.manufacturer = MANUFACTURER;
|
||||
#endif
|
||||
static_assert(sizeof(ESPHOME_MANUFACTURER) - 1 <= 20, "Update max_data_length for manufacturer in api.proto");
|
||||
#undef ESPHOME_MANUFACTURER
|
||||
|
||||
#ifdef USE_ESP8266
|
||||
|
||||
@@ -35,29 +35,29 @@ uint8_t *HelloResponse::encode(ProtoWriteBuffer &buffer PROTO_ENCODE_DEBUG_PARAM
|
||||
uint8_t *__restrict__ pos = buffer.get_pos();
|
||||
ProtoEncode::encode_uint32(pos PROTO_ENCODE_DEBUG_ARG, 1, this->api_version_major);
|
||||
ProtoEncode::encode_uint32(pos PROTO_ENCODE_DEBUG_ARG, 2, this->api_version_minor);
|
||||
ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 3, this->server_info);
|
||||
ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 4, this->name);
|
||||
ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, this->server_info);
|
||||
ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 34, this->name);
|
||||
return pos;
|
||||
}
|
||||
uint32_t HelloResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_uint32(1, this->api_version_major);
|
||||
size += ProtoSize::calc_uint32(1, this->api_version_minor);
|
||||
size += ProtoSize::calc_length(1, this->server_info.size());
|
||||
size += ProtoSize::calc_length(1, this->name.size());
|
||||
size += 2 + this->server_info.size();
|
||||
size += 2 + this->name.size();
|
||||
return size;
|
||||
}
|
||||
#ifdef USE_AREAS
|
||||
uint8_t *AreaInfo::encode(ProtoWriteBuffer &buffer PROTO_ENCODE_DEBUG_PARAM) const {
|
||||
uint8_t *__restrict__ pos = buffer.get_pos();
|
||||
ProtoEncode::encode_uint32(pos PROTO_ENCODE_DEBUG_ARG, 1, this->area_id);
|
||||
ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 2, this->name);
|
||||
ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 18, this->name);
|
||||
return pos;
|
||||
}
|
||||
uint32_t AreaInfo::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_uint32(1, this->area_id);
|
||||
size += ProtoSize::calc_length(1, this->name.size());
|
||||
size += 2 + this->name.size();
|
||||
return size;
|
||||
}
|
||||
#endif
|
||||
@@ -65,14 +65,14 @@ uint32_t AreaInfo::calculate_size() const {
|
||||
uint8_t *DeviceInfo::encode(ProtoWriteBuffer &buffer PROTO_ENCODE_DEBUG_PARAM) const {
|
||||
uint8_t *__restrict__ pos = buffer.get_pos();
|
||||
ProtoEncode::encode_uint32(pos PROTO_ENCODE_DEBUG_ARG, 1, this->device_id);
|
||||
ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 2, this->name);
|
||||
ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 18, this->name);
|
||||
ProtoEncode::encode_uint32(pos PROTO_ENCODE_DEBUG_ARG, 3, this->area_id);
|
||||
return pos;
|
||||
}
|
||||
uint32_t DeviceInfo::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_uint32(1, this->device_id);
|
||||
size += ProtoSize::calc_length(1, this->name.size());
|
||||
size += 2 + this->name.size();
|
||||
size += ProtoSize::calc_uint32(1, this->area_id);
|
||||
return size;
|
||||
}
|
||||
@@ -93,10 +93,10 @@ uint32_t SerialProxyInfo::calculate_size() const {
|
||||
#endif
|
||||
uint8_t *DeviceInfoResponse::encode(ProtoWriteBuffer &buffer PROTO_ENCODE_DEBUG_PARAM) const {
|
||||
uint8_t *__restrict__ pos = buffer.get_pos();
|
||||
ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 2, this->name);
|
||||
ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 3, this->mac_address);
|
||||
ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 4, this->esphome_version);
|
||||
ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 5, this->compilation_time);
|
||||
ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 18, this->name);
|
||||
ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, this->mac_address);
|
||||
ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 34, this->esphome_version);
|
||||
ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 42, this->compilation_time);
|
||||
ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 6, this->model);
|
||||
#ifdef USE_DEEP_SLEEP
|
||||
ProtoEncode::encode_bool(pos PROTO_ENCODE_DEBUG_ARG, 7, this->has_deep_sleep);
|
||||
@@ -113,8 +113,8 @@ uint8_t *DeviceInfoResponse::encode(ProtoWriteBuffer &buffer PROTO_ENCODE_DEBUG_
|
||||
#ifdef USE_BLUETOOTH_PROXY
|
||||
ProtoEncode::encode_uint32(pos PROTO_ENCODE_DEBUG_ARG, 15, this->bluetooth_proxy_feature_flags);
|
||||
#endif
|
||||
ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 12, this->manufacturer);
|
||||
ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 13, this->friendly_name);
|
||||
ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 98, this->manufacturer);
|
||||
ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 106, this->friendly_name);
|
||||
#ifdef USE_VOICE_ASSISTANT
|
||||
ProtoEncode::encode_uint32(pos PROTO_ENCODE_DEBUG_ARG, 17, this->voice_assistant_feature_flags);
|
||||
#endif
|
||||
@@ -122,7 +122,7 @@ uint8_t *DeviceInfoResponse::encode(ProtoWriteBuffer &buffer PROTO_ENCODE_DEBUG_
|
||||
ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 16, this->suggested_area);
|
||||
#endif
|
||||
#ifdef USE_BLUETOOTH_PROXY
|
||||
ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 18, this->bluetooth_mac_address);
|
||||
ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 18, this->bluetooth_mac_address, true);
|
||||
#endif
|
||||
#ifdef USE_API_NOISE
|
||||
ProtoEncode::encode_bool(pos PROTO_ENCODE_DEBUG_ARG, 19, this->api_encryption_supported);
|
||||
@@ -155,10 +155,10 @@ uint8_t *DeviceInfoResponse::encode(ProtoWriteBuffer &buffer PROTO_ENCODE_DEBUG_
|
||||
}
|
||||
uint32_t DeviceInfoResponse::calculate_size() const {
|
||||
uint32_t size = 0;
|
||||
size += ProtoSize::calc_length(1, this->name.size());
|
||||
size += ProtoSize::calc_length(1, this->mac_address.size());
|
||||
size += ProtoSize::calc_length(1, this->esphome_version.size());
|
||||
size += ProtoSize::calc_length(1, this->compilation_time.size());
|
||||
size += 2 + this->name.size();
|
||||
size += 2 + this->mac_address.size();
|
||||
size += 2 + this->esphome_version.size();
|
||||
size += 2 + this->compilation_time.size();
|
||||
size += ProtoSize::calc_length(1, this->model.size());
|
||||
#ifdef USE_DEEP_SLEEP
|
||||
size += ProtoSize::calc_bool(1, this->has_deep_sleep);
|
||||
@@ -175,8 +175,8 @@ uint32_t DeviceInfoResponse::calculate_size() const {
|
||||
#ifdef USE_BLUETOOTH_PROXY
|
||||
size += ProtoSize::calc_uint32(1, this->bluetooth_proxy_feature_flags);
|
||||
#endif
|
||||
size += ProtoSize::calc_length(1, this->manufacturer.size());
|
||||
size += ProtoSize::calc_length(1, this->friendly_name.size());
|
||||
size += 2 + this->manufacturer.size();
|
||||
size += 2 + this->friendly_name.size();
|
||||
#ifdef USE_VOICE_ASSISTANT
|
||||
size += ProtoSize::calc_uint32(2, this->voice_assistant_feature_flags);
|
||||
#endif
|
||||
@@ -184,7 +184,7 @@ uint32_t DeviceInfoResponse::calculate_size() const {
|
||||
size += ProtoSize::calc_length(2, this->suggested_area.size());
|
||||
#endif
|
||||
#ifdef USE_BLUETOOTH_PROXY
|
||||
size += ProtoSize::calc_length(2, this->bluetooth_mac_address.size());
|
||||
size += 3 + this->bluetooth_mac_address.size();
|
||||
#endif
|
||||
#ifdef USE_API_NOISE
|
||||
size += ProtoSize::calc_bool(2, this->api_encryption_supported);
|
||||
|
||||
Reference in New Issue
Block a user