diff --git a/esphome/components/api/proto.cpp b/esphome/components/api/proto.cpp index ee958e0564..89fdd8c8b2 100644 --- a/esphome/components/api/proto.cpp +++ b/esphome/components/api/proto.cpp @@ -355,11 +355,14 @@ void ProtoMessage::decode(const uint8_t *buffer, size_t length) { decoded = decode_varint_field(field->get_type(), field_addr, value); } - // If not found, try repeated fields + // If not found, try repeated fields (linear search - usually only 1-2 fields) if (!decoded) { - if (const RepeatedFieldMeta *field = find_field_binary(repeated_fields, repeated_count, field_id, 0)) { - void *field_addr = base + field->get_offset(); - decoded = decode_repeated_varint_field(field->get_type(), field_addr, value); + for (uint8_t j = 0; j < repeated_count; j++) { + if (repeated_fields[j].field_num == field_id && repeated_fields[j].get_wire_type() == 0) { + void *field_addr = base + repeated_fields[j].get_offset(); + decoded = decode_repeated_varint_field(repeated_fields[j].get_type(), field_addr, value); + break; + } } } @@ -389,11 +392,15 @@ void ProtoMessage::decode(const uint8_t *buffer, size_t length) { decoded = decode_length_field(field->get_type(), field_addr, value, field->get_message_type_id()); } - // If not found, try repeated fields + // If not found, try repeated fields (linear search - usually only 1-2 fields) if (!decoded) { - if (const RepeatedFieldMeta *field = find_field_binary(repeated_fields, repeated_count, field_id, 2)) { - void *field_addr = base + field->get_offset(); - decoded = decode_repeated_length_field(field->get_type(), field_addr, value, field->get_message_type_id()); + for (uint8_t j = 0; j < repeated_count; j++) { + if (repeated_fields[j].field_num == field_id && repeated_fields[j].get_wire_type() == 2) { + void *field_addr = base + repeated_fields[j].get_offset(); + decoded = decode_repeated_length_field(repeated_fields[j].get_type(), field_addr, value, + repeated_fields[j].get_message_type_id()); + break; + } } } @@ -420,11 +427,14 @@ void ProtoMessage::decode(const uint8_t *buffer, size_t length) { decoded = decode_32bit_field(field->get_type(), field_addr, value); } - // If not found, try repeated fields + // If not found, try repeated fields (linear search - usually only 1-2 fields) if (!decoded) { - if (const RepeatedFieldMeta *field = find_field_binary(repeated_fields, repeated_count, field_id, 5)) { - void *field_addr = base + field->get_offset(); - decoded = decode_repeated_32bit_field(field->get_type(), field_addr, value); + for (uint8_t j = 0; j < repeated_count; j++) { + if (repeated_fields[j].field_num == field_id && repeated_fields[j].get_wire_type() == 5) { + void *field_addr = base + repeated_fields[j].get_offset(); + decoded = decode_repeated_32bit_field(repeated_fields[j].get_type(), field_addr, value); + break; + } } } diff --git a/esphome/components/api/proto.h b/esphome/components/api/proto.h index b0d3d505bd..4dcc25451a 100644 --- a/esphome/components/api/proto.h +++ b/esphome/components/api/proto.h @@ -327,8 +327,7 @@ struct RepeatedFieldMeta { }; // Binary search for field lookup - optimized for performance -template -inline const MetaType *find_field_binary(const MetaType *fields, uint8_t count, uint8_t field_id, uint8_t wire_type) { +inline const FieldMeta *find_field_binary(const FieldMeta *fields, uint8_t count, uint8_t field_id, uint8_t wire_type) { uint8_t left = 0; uint8_t right = count; diff --git a/script/api_protobuf/api_protobuf.py b/script/api_protobuf/api_protobuf.py index cc40f76e67..be71f7653f 100755 --- a/script/api_protobuf/api_protobuf.py +++ b/script/api_protobuf/api_protobuf.py @@ -1893,7 +1893,7 @@ namespace api { cpp += "};\n" if repeated_fields: - # Sort fields by field number for binary search + # Sort fields by field number for consistency (even though using linear search) sorted_fields = sorted( repeated_fields, key=lambda f: int(f.split(",")[0].strip("{")) )