1
0
mirror of https://github.com/esphome/esphome.git synced 2026-02-08 00:31:58 +00:00

[api] Use stack buffer for bytes field dumping in proto message logs (#13162)

This commit is contained in:
J. Nick Koston
2026-01-12 07:37:58 -10:00
committed by GitHub
parent 353daa97d0
commit 7ea6bcef88
2 changed files with 64 additions and 50 deletions

View File

@@ -100,6 +100,16 @@ template<typename T> static void dump_field(std::string &out, const char *field_
out.append("\n");
}
// Helper for bytes fields - uses stack buffer to avoid heap allocation
// Buffer sized for 160 bytes of data (480 chars with separators) to fit typical log buffer
static void dump_bytes_field(std::string &out, const char *field_name, const uint8_t *data, size_t len,
int indent = 2) {
char hex_buf[format_hex_pretty_size(160)];
append_field_prefix(out, field_name, indent);
format_hex_pretty_to(hex_buf, data, len);
append_with_newline(out, hex_buf);
}
template<> const char *proto_enum_to_string<enums::EntityCategory>(enums::EntityCategory value) {
switch (value) {
case enums::ENTITY_CATEGORY_NONE:
@@ -1127,16 +1137,12 @@ void SubscribeLogsRequest::dump_to(std::string &out) const {
void SubscribeLogsResponse::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "SubscribeLogsResponse");
dump_field(out, "level", static_cast<enums::LogLevel>(this->level));
out.append(" message: ");
out.append(format_hex_pretty(this->message_ptr_, this->message_len_));
out.append("\n");
dump_bytes_field(out, "message", this->message_ptr_, this->message_len_);
}
#ifdef USE_API_NOISE
void NoiseEncryptionSetKeyRequest::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "NoiseEncryptionSetKeyRequest");
out.append(" key: ");
out.append(format_hex_pretty(this->key, this->key_len));
out.append("\n");
dump_bytes_field(out, "key", this->key, this->key_len);
}
void NoiseEncryptionSetKeyResponse::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "NoiseEncryptionSetKeyResponse");
@@ -1189,9 +1195,7 @@ void HomeassistantActionResponse::dump_to(std::string &out) const {
dump_field(out, "success", this->success);
dump_field(out, "error_message", this->error_message);
#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON
out.append(" response_data: ");
out.append(format_hex_pretty(this->response_data, this->response_data_len));
out.append("\n");
dump_bytes_field(out, "response_data", this->response_data, this->response_data_len);
#endif
}
#endif
@@ -1278,9 +1282,7 @@ void ExecuteServiceResponse::dump_to(std::string &out) const {
dump_field(out, "success", this->success);
dump_field(out, "error_message", this->error_message);
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
out.append(" response_data: ");
out.append(format_hex_pretty(this->response_data, this->response_data_len));
out.append("\n");
dump_bytes_field(out, "response_data", this->response_data, this->response_data_len);
#endif
}
#endif
@@ -1302,9 +1304,7 @@ void ListEntitiesCameraResponse::dump_to(std::string &out) const {
void CameraImageResponse::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "CameraImageResponse");
dump_field(out, "key", this->key);
out.append(" data: ");
out.append(format_hex_pretty(this->data_ptr_, this->data_len_));
out.append("\n");
dump_bytes_field(out, "data", this->data_ptr_, this->data_len_);
dump_field(out, "done", this->done);
#ifdef USE_DEVICES
dump_field(out, "device_id", this->device_id);
@@ -1705,9 +1705,7 @@ void BluetoothLERawAdvertisement::dump_to(std::string &out) const {
dump_field(out, "address", this->address);
dump_field(out, "rssi", this->rssi);
dump_field(out, "address_type", this->address_type);
out.append(" data: ");
out.append(format_hex_pretty(this->data, this->data_len));
out.append("\n");
dump_bytes_field(out, "data", this->data, this->data_len);
}
void BluetoothLERawAdvertisementsResponse::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "BluetoothLERawAdvertisementsResponse");
@@ -1792,18 +1790,14 @@ void BluetoothGATTReadResponse::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "BluetoothGATTReadResponse");
dump_field(out, "address", this->address);
dump_field(out, "handle", this->handle);
out.append(" data: ");
out.append(format_hex_pretty(this->data_ptr_, this->data_len_));
out.append("\n");
dump_bytes_field(out, "data", this->data_ptr_, this->data_len_);
}
void BluetoothGATTWriteRequest::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "BluetoothGATTWriteRequest");
dump_field(out, "address", this->address);
dump_field(out, "handle", this->handle);
dump_field(out, "response", this->response);
out.append(" data: ");
out.append(format_hex_pretty(this->data, this->data_len));
out.append("\n");
dump_bytes_field(out, "data", this->data, this->data_len);
}
void BluetoothGATTReadDescriptorRequest::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "BluetoothGATTReadDescriptorRequest");
@@ -1814,9 +1808,7 @@ void BluetoothGATTWriteDescriptorRequest::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "BluetoothGATTWriteDescriptorRequest");
dump_field(out, "address", this->address);
dump_field(out, "handle", this->handle);
out.append(" data: ");
out.append(format_hex_pretty(this->data, this->data_len));
out.append("\n");
dump_bytes_field(out, "data", this->data, this->data_len);
}
void BluetoothGATTNotifyRequest::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "BluetoothGATTNotifyRequest");
@@ -1828,9 +1820,7 @@ void BluetoothGATTNotifyDataResponse::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "BluetoothGATTNotifyDataResponse");
dump_field(out, "address", this->address);
dump_field(out, "handle", this->handle);
out.append(" data: ");
out.append(format_hex_pretty(this->data_ptr_, this->data_len_));
out.append("\n");
dump_bytes_field(out, "data", this->data_ptr_, this->data_len_);
}
void SubscribeBluetoothConnectionsFreeRequest::dump_to(std::string &out) const {
out.append("SubscribeBluetoothConnectionsFreeRequest {}");
@@ -1934,9 +1924,7 @@ void VoiceAssistantEventResponse::dump_to(std::string &out) const {
}
void VoiceAssistantAudio::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "VoiceAssistantAudio");
out.append(" data: ");
out.append(format_hex_pretty(this->data, this->data_len));
out.append("\n");
dump_bytes_field(out, "data", this->data, this->data_len);
dump_field(out, "end", this->end);
}
void VoiceAssistantTimerEventResponse::dump_to(std::string &out) const {
@@ -2297,16 +2285,12 @@ void UpdateCommandRequest::dump_to(std::string &out) const {
#ifdef USE_ZWAVE_PROXY
void ZWaveProxyFrame::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "ZWaveProxyFrame");
out.append(" data: ");
out.append(format_hex_pretty(this->data, this->data_len));
out.append("\n");
dump_bytes_field(out, "data", this->data, this->data_len);
}
void ZWaveProxyRequest::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "ZWaveProxyRequest");
dump_field(out, "type", static_cast<enums::ZWaveProxyRequestType>(this->type));
out.append(" data: ");
out.append(format_hex_pretty(this->data, this->data_len));
out.append("\n");
dump_bytes_field(out, "data", this->data, this->data_len);
}
#endif
#ifdef USE_INFRARED

View File

@@ -786,10 +786,32 @@ class BytesType(TypeInfo):
@property
def dump_content(self) -> str:
o = f'out.append(" {self.name}: ");\n'
o += self.dump(f"this->{self.field_name}") + "\n"
o += 'out.append("\\n");'
return o
# For SOURCE_CLIENT only, always use std::string
if not self._needs_encode:
return (
f'dump_bytes_field(out, "{self.name}", '
f"reinterpret_cast<const uint8_t*>(this->{self.field_name}.data()), "
f"this->{self.field_name}.size());"
)
# For SOURCE_SERVER, always use pointer/length
if not self._needs_decode:
return (
f'dump_bytes_field(out, "{self.name}", '
f"this->{self.field_name}_ptr_, this->{self.field_name}_len_);"
)
# For SOURCE_BOTH, check if pointer is set (sending) or use string (received)
return (
f"if (this->{self.field_name}_ptr_ != nullptr) {{\n"
f' dump_bytes_field(out, "{self.name}", '
f"this->{self.field_name}_ptr_, this->{self.field_name}_len_);\n"
f"}} else {{\n"
f' dump_bytes_field(out, "{self.name}", '
f"reinterpret_cast<const uint8_t*>(this->{self.field_name}.data()), "
f"this->{self.field_name}.size());\n"
f"}}"
)
def get_size_calculation(self, name: str, force: bool = False) -> str:
return f"size.add_length({self.calculate_field_id_size()}, this->{self.field_name}_len_);"
@@ -862,9 +884,8 @@ class PointerToBytesBufferType(PointerToBufferTypeBase):
@property
def dump_content(self) -> str:
return (
f'out.append(" {self.name}: ");\n'
+ f"out.append({self.dump(self.field_name)});\n"
+ 'out.append("\\n");'
f'dump_bytes_field(out, "{self.name}", '
f"this->{self.field_name}, this->{self.field_name}_len);"
)
def get_size_calculation(self, name: str, force: bool = False) -> str:
@@ -1062,10 +1083,10 @@ class FixedArrayBytesType(TypeInfo):
@property
def dump_content(self) -> str:
o = f'out.append(" {self.name}: ");\n'
o += f"out.append(format_hex_pretty(this->{self.field_name}, this->{self.field_name}_len));\n"
o += 'out.append("\\n");'
return o
return (
f'dump_bytes_field(out, "{self.name}", '
f"this->{self.field_name}, this->{self.field_name}_len);"
)
def get_size_calculation(self, name: str, force: bool = False) -> str:
# Use the actual length stored in the _len field
@@ -2658,6 +2679,15 @@ static void dump_field(std::string &out, const char *field_name, T value, int in
out.append("\\n");
}
// Helper for bytes fields - uses stack buffer to avoid heap allocation
// Buffer sized for 160 bytes of data (480 chars with separators) to fit typical log buffer
static void dump_bytes_field(std::string &out, const char *field_name, const uint8_t *data, size_t len, int indent = 2) {
char hex_buf[format_hex_pretty_size(160)];
append_field_prefix(out, field_name, indent);
format_hex_pretty_to(hex_buf, data, len);
append_with_newline(out, hex_buf);
}
"""
content += "namespace enums {\n\n"