esphome 2025.6.0b1__py3-none-any.whl → 2025.6.0b3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. esphome/components/api/api_connection.cpp +53 -33
  2. esphome/components/api/api_connection.h +24 -25
  3. esphome/components/api/api_pb2.cpp +1 -0
  4. esphome/components/api/api_pb2.h +65 -226
  5. esphome/components/api/client.py +1 -3
  6. esphome/components/api/proto.h +1 -1
  7. esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +2 -2
  8. esphome/components/bluetooth_proxy/bluetooth_proxy.h +1 -1
  9. esphome/components/bme280_base/bme280_base.cpp +2 -3
  10. esphome/components/datetime/date_entity.cpp +5 -5
  11. esphome/components/datetime/datetime_base.h +0 -5
  12. esphome/components/datetime/datetime_entity.cpp +8 -8
  13. esphome/components/datetime/time_entity.cpp +4 -4
  14. esphome/components/esp32/__init__.py +30 -3
  15. esphome/components/esp32_ble/ble.cpp +90 -45
  16. esphome/components/esp32_ble/ble.h +24 -5
  17. esphome/components/esp32_ble/ble_event.h +172 -32
  18. esphome/components/esp32_ble/ble_scan_result.h +24 -0
  19. esphome/components/esp32_ble/queue.h +53 -27
  20. esphome/components/esp32_ble_tracker/__init__.py +1 -0
  21. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +95 -66
  22. esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +16 -16
  23. esphome/components/esp32_camera/esp32_camera.cpp +1 -1
  24. esphome/components/fan/fan.cpp +26 -17
  25. esphome/components/i2s_audio/i2s_audio.cpp +1 -1
  26. esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +47 -29
  27. esphome/components/i2s_audio/microphone/i2s_audio_microphone.h +2 -0
  28. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +28 -10
  29. esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +1 -0
  30. esphome/components/kmeteriso/kmeteriso.cpp +2 -3
  31. esphome/components/light/light_state.h +15 -15
  32. esphome/components/logger/logger.cpp +2 -15
  33. esphome/components/logger/logger.h +1 -2
  34. esphome/components/mqtt/mqtt_component.cpp +1 -1
  35. esphome/components/nextion/binary_sensor/nextion_binarysensor.cpp +1 -1
  36. esphome/components/nextion/nextion_upload_arduino.cpp +12 -9
  37. esphome/components/nextion/nextion_upload_idf.cpp +11 -9
  38. esphome/components/nextion/sensor/nextion_sensor.cpp +1 -1
  39. esphome/components/nextion/text_sensor/nextion_textsensor.cpp +1 -1
  40. esphome/components/number/number.cpp +1 -1
  41. esphome/components/number/number.h +0 -4
  42. esphome/components/prometheus/__init__.py +0 -1
  43. esphome/components/select/select.cpp +1 -1
  44. esphome/components/select/select.h +0 -4
  45. esphome/components/sensor/sensor.cpp +8 -4
  46. esphome/components/sensor/sensor.h +3 -6
  47. esphome/components/spi/spi_arduino.cpp +22 -9
  48. esphome/components/status_led/light/status_led_light.cpp +2 -2
  49. esphome/components/status_led/light/status_led_light.h +1 -1
  50. esphome/components/switch/switch.h +13 -7
  51. esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp +14 -9
  52. esphome/components/template/alarm_control_panel/template_alarm_control_panel.h +1 -0
  53. esphome/components/text/text.cpp +1 -1
  54. esphome/components/text/text.h +0 -4
  55. esphome/components/text_sensor/text_sensor.cpp +8 -4
  56. esphome/components/text_sensor/text_sensor.h +6 -6
  57. esphome/components/update/update_entity.cpp +1 -1
  58. esphome/components/update/update_entity.h +0 -3
  59. esphome/components/uptime/sensor/uptime_timestamp_sensor.cpp +1 -1
  60. esphome/components/web_server_idf/__init__.py +0 -2
  61. esphome/components/web_server_idf/web_server_idf.cpp +6 -2
  62. esphome/components/web_server_idf/web_server_idf.h +7 -0
  63. esphome/components/weikai/weikai.cpp +1 -1
  64. esphome/const.py +1 -1
  65. esphome/core/application.cpp +14 -8
  66. esphome/core/application.h +7 -7
  67. esphome/core/component.cpp +36 -15
  68. esphome/core/component.h +30 -13
  69. esphome/core/entity_base.cpp +4 -16
  70. esphome/core/entity_base.h +27 -13
  71. esphome/core/helpers.h +1 -1
  72. esphome/wizard.py +0 -16
  73. {esphome-2025.6.0b1.dist-info → esphome-2025.6.0b3.dist-info}/METADATA +2 -2
  74. {esphome-2025.6.0b1.dist-info → esphome-2025.6.0b3.dist-info}/RECORD +78 -77
  75. {esphome-2025.6.0b1.dist-info → esphome-2025.6.0b3.dist-info}/WHEEL +0 -0
  76. {esphome-2025.6.0b1.dist-info → esphome-2025.6.0b3.dist-info}/entry_points.txt +0 -0
  77. {esphome-2025.6.0b1.dist-info → esphome-2025.6.0b3.dist-info}/licenses/LICENSE +0 -0
  78. {esphome-2025.6.0b1.dist-info → esphome-2025.6.0b3.dist-info}/top_level.txt +0 -0
@@ -248,25 +248,41 @@ void APIConnection::on_disconnect_response(const DisconnectResponse &value) {
248
248
  uint16_t APIConnection::encode_message_to_buffer(ProtoMessage &msg, uint16_t message_type, APIConnection *conn,
249
249
  uint32_t remaining_size, bool is_single) {
250
250
  // Calculate size
251
- uint32_t size = 0;
252
- msg.calculate_size(size);
251
+ uint32_t calculated_size = 0;
252
+ msg.calculate_size(calculated_size);
253
+
254
+ // Cache frame sizes to avoid repeated virtual calls
255
+ const uint8_t header_padding = conn->helper_->frame_header_padding();
256
+ const uint8_t footer_size = conn->helper_->frame_footer_size();
253
257
 
254
258
  // Calculate total size with padding for buffer allocation
255
- uint16_t total_size =
256
- static_cast<uint16_t>(size) + conn->helper_->frame_header_padding() + conn->helper_->frame_footer_size();
259
+ size_t total_calculated_size = calculated_size + header_padding + footer_size;
257
260
 
258
261
  // Check if it fits
259
- if (total_size > remaining_size) {
262
+ if (total_calculated_size > remaining_size) {
260
263
  return 0; // Doesn't fit
261
264
  }
262
265
 
263
- // Allocate exact buffer space needed (just the payload, not the overhead)
264
- ProtoWriteBuffer buffer =
265
- is_single ? conn->allocate_single_message_buffer(size) : conn->allocate_batch_message_buffer(size);
266
+ // Allocate buffer space - pass payload size, allocation functions add header/footer space
267
+ ProtoWriteBuffer buffer = is_single ? conn->allocate_single_message_buffer(calculated_size)
268
+ : conn->allocate_batch_message_buffer(calculated_size);
269
+
270
+ // Get buffer size after allocation (which includes header padding)
271
+ std::vector<uint8_t> &shared_buf = conn->parent_->get_shared_buffer_ref();
272
+ size_t size_before_encode = shared_buf.size();
266
273
 
267
274
  // Encode directly into buffer
268
275
  msg.encode(buffer);
269
- return total_size;
276
+
277
+ // Calculate actual encoded size (not including header that was already added)
278
+ size_t actual_payload_size = shared_buf.size() - size_before_encode;
279
+
280
+ // Return actual total size (header + actual payload + footer)
281
+ size_t actual_total_size = header_padding + actual_payload_size + footer_size;
282
+
283
+ // Verify that calculate_size() returned the correct value
284
+ assert(calculated_size == actual_payload_size);
285
+ return static_cast<uint16_t>(actual_total_size);
270
286
  }
271
287
 
272
288
  #ifdef USE_BINARY_SENSOR
@@ -285,7 +301,7 @@ uint16_t APIConnection::try_send_binary_sensor_state(EntityBase *entity, APIConn
285
301
  BinarySensorStateResponse resp;
286
302
  resp.state = binary_sensor->state;
287
303
  resp.missing_state = !binary_sensor->has_state();
288
- resp.key = binary_sensor->get_object_id_hash();
304
+ fill_entity_state_base(binary_sensor, resp);
289
305
  return encode_message_to_buffer(resp, BinarySensorStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
290
306
  }
291
307
 
@@ -319,7 +335,7 @@ uint16_t APIConnection::try_send_cover_state(EntityBase *entity, APIConnection *
319
335
  if (traits.get_supports_tilt())
320
336
  msg.tilt = cover->tilt;
321
337
  msg.current_operation = static_cast<enums::CoverOperation>(cover->current_operation);
322
- msg.key = cover->get_object_id_hash();
338
+ fill_entity_state_base(cover, msg);
323
339
  return encode_message_to_buffer(msg, CoverStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
324
340
  }
325
341
  uint16_t APIConnection::try_send_cover_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
@@ -387,7 +403,7 @@ uint16_t APIConnection::try_send_fan_state(EntityBase *entity, APIConnection *co
387
403
  msg.direction = static_cast<enums::FanDirection>(fan->direction);
388
404
  if (traits.supports_preset_modes())
389
405
  msg.preset_mode = fan->preset_mode;
390
- msg.key = fan->get_object_id_hash();
406
+ fill_entity_state_base(fan, msg);
391
407
  return encode_message_to_buffer(msg, FanStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
392
408
  }
393
409
  uint16_t APIConnection::try_send_fan_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
@@ -454,7 +470,7 @@ uint16_t APIConnection::try_send_light_state(EntityBase *entity, APIConnection *
454
470
  resp.warm_white = values.get_warm_white();
455
471
  if (light->supports_effects())
456
472
  resp.effect = light->get_effect_name();
457
- resp.key = light->get_object_id_hash();
473
+ fill_entity_state_base(light, resp);
458
474
  return encode_message_to_buffer(resp, LightStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
459
475
  }
460
476
  uint16_t APIConnection::try_send_light_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
@@ -536,7 +552,7 @@ uint16_t APIConnection::try_send_sensor_state(EntityBase *entity, APIConnection
536
552
  SensorStateResponse resp;
537
553
  resp.state = sensor->state;
538
554
  resp.missing_state = !sensor->has_state();
539
- resp.key = sensor->get_object_id_hash();
555
+ fill_entity_state_base(sensor, resp);
540
556
  return encode_message_to_buffer(resp, SensorStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
541
557
  }
542
558
 
@@ -570,7 +586,7 @@ uint16_t APIConnection::try_send_switch_state(EntityBase *entity, APIConnection
570
586
  auto *a_switch = static_cast<switch_::Switch *>(entity);
571
587
  SwitchStateResponse resp;
572
588
  resp.state = a_switch->state;
573
- resp.key = a_switch->get_object_id_hash();
589
+ fill_entity_state_base(a_switch, resp);
574
590
  return encode_message_to_buffer(resp, SwitchStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
575
591
  }
576
592
 
@@ -613,7 +629,7 @@ uint16_t APIConnection::try_send_text_sensor_state(EntityBase *entity, APIConnec
613
629
  TextSensorStateResponse resp;
614
630
  resp.state = text_sensor->state;
615
631
  resp.missing_state = !text_sensor->has_state();
616
- resp.key = text_sensor->get_object_id_hash();
632
+ fill_entity_state_base(text_sensor, resp);
617
633
  return encode_message_to_buffer(resp, TextSensorStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
618
634
  }
619
635
  uint16_t APIConnection::try_send_text_sensor_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
@@ -637,7 +653,7 @@ uint16_t APIConnection::try_send_climate_state(EntityBase *entity, APIConnection
637
653
  bool is_single) {
638
654
  auto *climate = static_cast<climate::Climate *>(entity);
639
655
  ClimateStateResponse resp;
640
- resp.key = climate->get_object_id_hash();
656
+ fill_entity_state_base(climate, resp);
641
657
  auto traits = climate->get_traits();
642
658
  resp.mode = static_cast<enums::ClimateMode>(climate->mode);
643
659
  resp.action = static_cast<enums::ClimateAction>(climate->action);
@@ -746,7 +762,7 @@ uint16_t APIConnection::try_send_number_state(EntityBase *entity, APIConnection
746
762
  NumberStateResponse resp;
747
763
  resp.state = number->state;
748
764
  resp.missing_state = !number->has_state();
749
- resp.key = number->get_object_id_hash();
765
+ fill_entity_state_base(number, resp);
750
766
  return encode_message_to_buffer(resp, NumberStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
751
767
  }
752
768
 
@@ -787,7 +803,7 @@ uint16_t APIConnection::try_send_date_state(EntityBase *entity, APIConnection *c
787
803
  resp.year = date->year;
788
804
  resp.month = date->month;
789
805
  resp.day = date->day;
790
- resp.key = date->get_object_id_hash();
806
+ fill_entity_state_base(date, resp);
791
807
  return encode_message_to_buffer(resp, DateStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
792
808
  }
793
809
  void APIConnection::send_date_info(datetime::DateEntity *date) {
@@ -824,7 +840,7 @@ uint16_t APIConnection::try_send_time_state(EntityBase *entity, APIConnection *c
824
840
  resp.hour = time->hour;
825
841
  resp.minute = time->minute;
826
842
  resp.second = time->second;
827
- resp.key = time->get_object_id_hash();
843
+ fill_entity_state_base(time, resp);
828
844
  return encode_message_to_buffer(resp, TimeStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
829
845
  }
830
846
  void APIConnection::send_time_info(datetime::TimeEntity *time) {
@@ -863,7 +879,7 @@ uint16_t APIConnection::try_send_datetime_state(EntityBase *entity, APIConnectio
863
879
  ESPTime state = datetime->state_as_esptime();
864
880
  resp.epoch_seconds = state.timestamp;
865
881
  }
866
- resp.key = datetime->get_object_id_hash();
882
+ fill_entity_state_base(datetime, resp);
867
883
  return encode_message_to_buffer(resp, DateTimeStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
868
884
  }
869
885
  void APIConnection::send_datetime_info(datetime::DateTimeEntity *datetime) {
@@ -902,7 +918,7 @@ uint16_t APIConnection::try_send_text_state(EntityBase *entity, APIConnection *c
902
918
  TextStateResponse resp;
903
919
  resp.state = text->state;
904
920
  resp.missing_state = !text->has_state();
905
- resp.key = text->get_object_id_hash();
921
+ fill_entity_state_base(text, resp);
906
922
  return encode_message_to_buffer(resp, TextStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
907
923
  }
908
924
 
@@ -943,7 +959,7 @@ uint16_t APIConnection::try_send_select_state(EntityBase *entity, APIConnection
943
959
  SelectStateResponse resp;
944
960
  resp.state = select->state;
945
961
  resp.missing_state = !select->has_state();
946
- resp.key = select->get_object_id_hash();
962
+ fill_entity_state_base(select, resp);
947
963
  return encode_message_to_buffer(resp, SelectStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
948
964
  }
949
965
 
@@ -1003,7 +1019,7 @@ uint16_t APIConnection::try_send_lock_state(EntityBase *entity, APIConnection *c
1003
1019
  auto *a_lock = static_cast<lock::Lock *>(entity);
1004
1020
  LockStateResponse resp;
1005
1021
  resp.state = static_cast<enums::LockState>(a_lock->state);
1006
- resp.key = a_lock->get_object_id_hash();
1022
+ fill_entity_state_base(a_lock, resp);
1007
1023
  return encode_message_to_buffer(resp, LockStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
1008
1024
  }
1009
1025
 
@@ -1047,7 +1063,7 @@ uint16_t APIConnection::try_send_valve_state(EntityBase *entity, APIConnection *
1047
1063
  ValveStateResponse resp;
1048
1064
  resp.position = valve->position;
1049
1065
  resp.current_operation = static_cast<enums::ValveOperation>(valve->current_operation);
1050
- resp.key = valve->get_object_id_hash();
1066
+ fill_entity_state_base(valve, resp);
1051
1067
  return encode_message_to_buffer(resp, ValveStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
1052
1068
  }
1053
1069
  void APIConnection::send_valve_info(valve::Valve *valve) {
@@ -1095,7 +1111,7 @@ uint16_t APIConnection::try_send_media_player_state(EntityBase *entity, APIConne
1095
1111
  resp.state = static_cast<enums::MediaPlayerState>(report_state);
1096
1112
  resp.volume = media_player->volume;
1097
1113
  resp.muted = media_player->is_muted();
1098
- resp.key = media_player->get_object_id_hash();
1114
+ fill_entity_state_base(media_player, resp);
1099
1115
  return encode_message_to_buffer(resp, MediaPlayerStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
1100
1116
  }
1101
1117
  void APIConnection::send_media_player_info(media_player::MediaPlayer *media_player) {
@@ -1359,7 +1375,7 @@ uint16_t APIConnection::try_send_alarm_control_panel_state(EntityBase *entity, A
1359
1375
  auto *a_alarm_control_panel = static_cast<alarm_control_panel::AlarmControlPanel *>(entity);
1360
1376
  AlarmControlPanelStateResponse resp;
1361
1377
  resp.state = static_cast<enums::AlarmControlPanelState>(a_alarm_control_panel->get_state());
1362
- resp.key = a_alarm_control_panel->get_object_id_hash();
1378
+ fill_entity_state_base(a_alarm_control_panel, resp);
1363
1379
  return encode_message_to_buffer(resp, AlarmControlPanelStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
1364
1380
  }
1365
1381
  void APIConnection::send_alarm_control_panel_info(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) {
@@ -1423,7 +1439,7 @@ uint16_t APIConnection::try_send_event_response(event::Event *event, const std::
1423
1439
  uint32_t remaining_size, bool is_single) {
1424
1440
  EventResponse resp;
1425
1441
  resp.event_type = event_type;
1426
- resp.key = event->get_object_id_hash();
1442
+ fill_entity_state_base(event, resp);
1427
1443
  return encode_message_to_buffer(resp, EventResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
1428
1444
  }
1429
1445
 
@@ -1461,7 +1477,7 @@ uint16_t APIConnection::try_send_update_state(EntityBase *entity, APIConnection
1461
1477
  resp.release_summary = update->update_info.summary;
1462
1478
  resp.release_url = update->update_info.release_url;
1463
1479
  }
1464
- resp.key = update->get_object_id_hash();
1480
+ fill_entity_state_base(update, resp);
1465
1481
  return encode_message_to_buffer(resp, UpdateStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
1466
1482
  }
1467
1483
  void APIConnection::send_update_info(update::UpdateEntity *update) {
@@ -1522,7 +1538,7 @@ bool APIConnection::try_send_log_message(int level, const char *tag, const char
1522
1538
  buffer.encode_string(3, line, line_length); // string message = 3
1523
1539
 
1524
1540
  // SubscribeLogsResponse - 29
1525
- return this->send_buffer(buffer, 29);
1541
+ return this->send_buffer(buffer, SubscribeLogsResponse::MESSAGE_TYPE);
1526
1542
  }
1527
1543
 
1528
1544
  HelloResponse APIConnection::hello(const HelloRequest &msg) {
@@ -1669,7 +1685,7 @@ bool APIConnection::try_to_clear_buffer(bool log_out_of_space) {
1669
1685
  return false;
1670
1686
  }
1671
1687
  bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint16_t message_type) {
1672
- if (!this->try_to_clear_buffer(message_type != 29)) { // SubscribeLogsResponse
1688
+ if (!this->try_to_clear_buffer(message_type != SubscribeLogsResponse::MESSAGE_TYPE)) { // SubscribeLogsResponse
1673
1689
  return false;
1674
1690
  }
1675
1691
 
@@ -1791,7 +1807,7 @@ void APIConnection::process_batch_() {
1791
1807
  this->batch_first_message_ = true;
1792
1808
 
1793
1809
  size_t items_processed = 0;
1794
- uint32_t remaining_size = MAX_PACKET_SIZE;
1810
+ uint16_t remaining_size = std::numeric_limits<uint16_t>::max();
1795
1811
 
1796
1812
  // Track where each message's header padding begins in the buffer
1797
1813
  // For plaintext: this is where the 6-byte header padding starts
@@ -1816,11 +1832,15 @@ void APIConnection::process_batch_() {
1816
1832
  packet_info.emplace_back(item.message_type, current_offset, proto_payload_size);
1817
1833
 
1818
1834
  // Update tracking variables
1835
+ items_processed++;
1836
+ // After first message, set remaining size to MAX_PACKET_SIZE to avoid fragmentation
1837
+ if (items_processed == 1) {
1838
+ remaining_size = MAX_PACKET_SIZE;
1839
+ }
1819
1840
  remaining_size -= payload_size;
1820
1841
  // Calculate where the next message's header padding will start
1821
1842
  // Current buffer size + footer space (that prepare_message_buffer will add for this message)
1822
1843
  current_offset = this->parent_->get_shared_buffer_ref().size() + footer_size;
1823
- items_processed++;
1824
1844
  }
1825
1845
 
1826
1846
  if (items_processed == 0) {
@@ -240,8 +240,8 @@ class APIConnection : public APIServerConnection {
240
240
  // - Header padding: space for protocol headers (7 bytes for Noise, 6 for Plaintext)
241
241
  // - Footer: space for MAC (16 bytes for Noise, 0 for Plaintext)
242
242
  shared_buf.reserve(reserve_size + header_padding + this->helper_->frame_footer_size());
243
- // Insert header padding bytes so message encoding starts at the correct position
244
- shared_buf.insert(shared_buf.begin(), header_padding, 0);
243
+ // Resize to add header padding so message encoding starts at the correct position
244
+ shared_buf.resize(header_padding);
245
245
  return {&shared_buf};
246
246
  }
247
247
 
@@ -249,32 +249,26 @@ class APIConnection : public APIServerConnection {
249
249
  ProtoWriteBuffer prepare_message_buffer(uint16_t message_size, bool is_first_message) {
250
250
  // Get reference to shared buffer (it maintains state between batch messages)
251
251
  std::vector<uint8_t> &shared_buf = this->parent_->get_shared_buffer_ref();
252
- size_t current_size = shared_buf.size();
253
252
 
254
253
  if (is_first_message) {
255
- // For first message, initialize buffer with header padding
256
- uint8_t header_padding = this->helper_->frame_header_padding();
257
254
  shared_buf.clear();
258
- shared_buf.reserve(message_size + header_padding);
259
- shared_buf.resize(header_padding);
260
- // Fill header padding with zeros
261
- std::fill(shared_buf.begin(), shared_buf.end(), 0);
262
- } else {
263
- // For subsequent messages, add footer space for previous message and header for this message
264
- uint8_t footer_size = this->helper_->frame_footer_size();
265
- uint8_t header_padding = this->helper_->frame_header_padding();
266
-
267
- // Reserve additional space for everything
268
- shared_buf.reserve(current_size + footer_size + header_padding + message_size);
269
-
270
- // Single resize to add both footer and header padding
271
- size_t new_size = current_size + footer_size + header_padding;
272
- shared_buf.resize(new_size);
273
-
274
- // Fill the newly added bytes with zeros (footer + header padding)
275
- std::fill(shared_buf.begin() + current_size, shared_buf.end(), 0);
276
255
  }
277
256
 
257
+ size_t current_size = shared_buf.size();
258
+
259
+ // Calculate padding to add:
260
+ // - First message: just header padding
261
+ // - Subsequent messages: footer for previous message + header padding for this message
262
+ size_t padding_to_add = is_first_message
263
+ ? this->helper_->frame_header_padding()
264
+ : this->helper_->frame_header_padding() + this->helper_->frame_footer_size();
265
+
266
+ // Reserve space for padding + message
267
+ shared_buf.reserve(current_size + padding_to_add + message_size);
268
+
269
+ // Resize to add the padding bytes
270
+ shared_buf.resize(current_size + padding_to_add);
271
+
278
272
  return {&shared_buf};
279
273
  }
280
274
 
@@ -288,8 +282,8 @@ class APIConnection : public APIServerConnection {
288
282
  ProtoWriteBuffer allocate_batch_message_buffer(uint16_t size);
289
283
 
290
284
  protected:
291
- // Helper function to fill common entity fields
292
- template<typename ResponseT> static void fill_entity_info_base(esphome::EntityBase *entity, ResponseT &response) {
285
+ // Helper function to fill common entity info fields
286
+ static void fill_entity_info_base(esphome::EntityBase *entity, InfoResponseProtoMessage &response) {
293
287
  // Set common fields that are shared by all entity types
294
288
  response.key = entity->get_object_id_hash();
295
289
  response.object_id = entity->get_object_id();
@@ -303,6 +297,11 @@ class APIConnection : public APIServerConnection {
303
297
  response.entity_category = static_cast<enums::EntityCategory>(entity->get_entity_category());
304
298
  }
305
299
 
300
+ // Helper function to fill common entity state fields
301
+ static void fill_entity_state_base(esphome::EntityBase *entity, StateResponseProtoMessage &response) {
302
+ response.key = entity->get_object_id_hash();
303
+ }
304
+
306
305
  // Non-template helper to encode any ProtoMessage
307
306
  static uint16_t encode_message_to_buffer(ProtoMessage &msg, uint16_t message_type, APIConnection *conn,
308
307
  uint32_t remaining_size, bool is_single);
@@ -628,6 +628,7 @@ template<> const char *proto_enum_to_string<enums::UpdateCommand>(enums::UpdateC
628
628
  }
629
629
  }
630
630
  #endif
631
+
631
632
  bool HelloRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
632
633
  switch (field_id) {
633
634
  case 2: {