esphome 2025.7.0b1__py3-none-any.whl → 2025.7.0b2__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.

Potentially problematic release.


This version of esphome might be problematic. Click here for more details.

Files changed (49) hide show
  1. esphome/components/api/__init__.py +19 -5
  2. esphome/components/api/api_connection.cpp +53 -175
  3. esphome/components/api/api_connection.h +28 -25
  4. esphome/components/api/api_frame_helper.cpp +2 -3
  5. esphome/components/api/api_frame_helper.h +7 -9
  6. esphome/components/api/api_pb2.cpp +1862 -5133
  7. esphome/components/api/api_pb2.h +291 -533
  8. esphome/components/api/api_pb2_dump.cpp +99 -0
  9. esphome/components/api/api_pb2_service.cpp +4 -0
  10. esphome/components/api/api_pb2_service.h +6 -0
  11. esphome/components/api/api_server.cpp +2 -9
  12. esphome/components/api/api_server.h +7 -33
  13. esphome/components/api/custom_api_device.h +8 -0
  14. esphome/components/api/list_entities.cpp +2 -0
  15. esphome/components/api/list_entities.h +3 -1
  16. esphome/components/api/proto.h +506 -23
  17. esphome/components/api/user_services.h +2 -0
  18. esphome/components/debug/debug_esp32.cpp +2 -0
  19. esphome/components/esp32/__init__.py +1 -0
  20. esphome/components/esp32_camera/__init__.py +1 -1
  21. esphome/components/esp32_touch/esp32_touch_v1.cpp +12 -10
  22. esphome/components/esp8266/__init__.py +1 -0
  23. esphome/components/host/__init__.py +1 -0
  24. esphome/components/ld2410/ld2410.cpp +12 -28
  25. esphome/components/libretiny/__init__.py +1 -0
  26. esphome/components/mqtt/mqtt_backend_esp32.cpp +6 -2
  27. esphome/components/packet_transport/packet_transport.cpp +3 -0
  28. esphome/components/rp2040/__init__.py +1 -0
  29. esphome/components/sx126x/__init__.py +3 -3
  30. esphome/components/sx127x/__init__.py +2 -2
  31. esphome/components/usb_host/usb_host_client.cpp +10 -10
  32. esphome/components/usb_uart/cp210x.cpp +1 -1
  33. esphome/components/usb_uart/usb_uart.cpp +41 -44
  34. esphome/components/usb_uart/usb_uart.h +4 -3
  35. esphome/const.py +1 -1
  36. esphome/core/component_iterator.cpp +4 -2
  37. esphome/core/component_iterator.h +3 -3
  38. esphome/core/defines.h +1 -1
  39. esphome/core/entity_helpers.py +6 -0
  40. esphome/core/scheduler.cpp +9 -12
  41. esphome/core/scheduler.h +0 -3
  42. esphome/wizard.py +1 -1
  43. {esphome-2025.7.0b1.dist-info → esphome-2025.7.0b2.dist-info}/METADATA +2 -2
  44. {esphome-2025.7.0b1.dist-info → esphome-2025.7.0b2.dist-info}/RECORD +48 -49
  45. esphome/components/api/api_pb2_size.h +0 -359
  46. {esphome-2025.7.0b1.dist-info → esphome-2025.7.0b2.dist-info}/WHEEL +0 -0
  47. {esphome-2025.7.0b1.dist-info → esphome-2025.7.0b2.dist-info}/entry_points.txt +0 -0
  48. {esphome-2025.7.0b1.dist-info → esphome-2025.7.0b2.dist-info}/licenses/LICENSE +0 -0
  49. {esphome-2025.7.0b1.dist-info → esphome-2025.7.0b2.dist-info}/top_level.txt +0 -0
@@ -24,8 +24,9 @@ from esphome.const import (
24
24
  CONF_TRIGGER_ID,
25
25
  CONF_VARIABLES,
26
26
  )
27
- from esphome.core import coroutine_with_priority
27
+ from esphome.core import CORE, coroutine_with_priority
28
28
 
29
+ DOMAIN = "api"
29
30
  DEPENDENCIES = ["network"]
30
31
  AUTO_LOAD = ["socket"]
31
32
  CODEOWNERS = ["@OttoWinter"]
@@ -51,6 +52,7 @@ SERVICE_ARG_NATIVE_TYPES = {
51
52
  }
52
53
  CONF_ENCRYPTION = "encryption"
53
54
  CONF_BATCH_DELAY = "batch_delay"
55
+ CONF_CUSTOM_SERVICES = "custom_services"
54
56
 
55
57
 
56
58
  def validate_encryption_key(value):
@@ -115,6 +117,7 @@ CONFIG_SCHEMA = cv.All(
115
117
  cv.positive_time_period_milliseconds,
116
118
  cv.Range(max=cv.TimePeriod(milliseconds=65535)),
117
119
  ),
120
+ cv.Optional(CONF_CUSTOM_SERVICES, default=False): cv.boolean,
118
121
  cv.Optional(CONF_ON_CLIENT_CONNECTED): automation.validate_automation(
119
122
  single=True
120
123
  ),
@@ -139,8 +142,11 @@ async def to_code(config):
139
142
  cg.add(var.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT]))
140
143
  cg.add(var.set_batch_delay(config[CONF_BATCH_DELAY]))
141
144
 
145
+ # Set USE_API_SERVICES if any services are enabled
146
+ if config.get(CONF_ACTIONS) or config[CONF_CUSTOM_SERVICES]:
147
+ cg.add_define("USE_API_SERVICES")
148
+
142
149
  if actions := config.get(CONF_ACTIONS, []):
143
- cg.add_define("USE_API_YAML_SERVICES")
144
150
  for conf in actions:
145
151
  template_args = []
146
152
  func_args = []
@@ -317,7 +323,10 @@ async def api_connected_to_code(config, condition_id, template_arg, args):
317
323
 
318
324
 
319
325
  def FILTER_SOURCE_FILES() -> list[str]:
320
- """Filter out api_pb2_dump.cpp when proto message dumping is not enabled."""
326
+ """Filter out api_pb2_dump.cpp when proto message dumping is not enabled
327
+ and user_services.cpp when no services are defined."""
328
+ files_to_filter = []
329
+
321
330
  # api_pb2_dump.cpp is only needed when HAS_PROTO_MESSAGE_DUMP is defined
322
331
  # This is a particularly large file that still needs to be opened and read
323
332
  # all the way to the end even when ifdef'd out
@@ -325,6 +334,11 @@ def FILTER_SOURCE_FILES() -> list[str]:
325
334
  # HAS_PROTO_MESSAGE_DUMP is defined when ESPHOME_LOG_HAS_VERY_VERBOSE is set,
326
335
  # which happens when the logger level is VERY_VERBOSE
327
336
  if get_logger_level() != "VERY_VERBOSE":
328
- return ["api_pb2_dump.cpp"]
337
+ files_to_filter.append("api_pb2_dump.cpp")
338
+
339
+ # user_services.cpp is only needed when services are defined
340
+ config = CORE.config.get(DOMAIN, {})
341
+ if config and not config.get(CONF_ACTIONS) and not config[CONF_CUSTOM_SERVICES]:
342
+ files_to_filter.append("user_services.cpp")
329
343
 
330
- return []
344
+ return files_to_filter
@@ -193,14 +193,15 @@ void APIConnection::loop() {
193
193
  // If we can't send the ping request directly (tx_buffer full),
194
194
  // schedule it at the front of the batch so it will be sent with priority
195
195
  ESP_LOGW(TAG, "Buffer full, ping queued");
196
- this->schedule_message_front_(nullptr, &APIConnection::try_send_ping_request, PingRequest::MESSAGE_TYPE);
196
+ this->schedule_message_front_(nullptr, &APIConnection::try_send_ping_request, PingRequest::MESSAGE_TYPE,
197
+ PingRequest::ESTIMATED_SIZE);
197
198
  this->flags_.sent_ping = true; // Mark as sent to avoid scheduling multiple pings
198
199
  }
199
200
  }
200
201
 
201
202
  #ifdef USE_CAMERA
202
203
  if (this->image_reader_ && this->image_reader_->available() && this->helper_->can_write_without_blocking()) {
203
- uint32_t to_send = std::min((size_t) MAX_PACKET_SIZE, this->image_reader_->available());
204
+ uint32_t to_send = std::min((size_t) MAX_BATCH_PACKET_SIZE, this->image_reader_->available());
204
205
  bool done = this->image_reader_->available() == to_send;
205
206
  uint32_t msg_size = 0;
206
207
  ProtoSize::add_fixed_field<4>(msg_size, 1, true);
@@ -265,7 +266,7 @@ void APIConnection::on_disconnect_response(const DisconnectResponse &value) {
265
266
 
266
267
  // Encodes a message to the buffer and returns the total number of bytes used,
267
268
  // including header and footer overhead. Returns 0 if the message doesn't fit.
268
- uint16_t APIConnection::encode_message_to_buffer(ProtoMessage &msg, uint16_t message_type, APIConnection *conn,
269
+ uint16_t APIConnection::encode_message_to_buffer(ProtoMessage &msg, uint8_t message_type, APIConnection *conn,
269
270
  uint32_t remaining_size, bool is_single) {
270
271
  #ifdef HAS_PROTO_MESSAGE_DUMP
271
272
  // If in log-only mode, just log and return
@@ -316,7 +317,7 @@ uint16_t APIConnection::encode_message_to_buffer(ProtoMessage &msg, uint16_t mes
316
317
  #ifdef USE_BINARY_SENSOR
317
318
  bool APIConnection::send_binary_sensor_state(binary_sensor::BinarySensor *binary_sensor) {
318
319
  return this->send_message_smart_(binary_sensor, &APIConnection::try_send_binary_sensor_state,
319
- BinarySensorStateResponse::MESSAGE_TYPE);
320
+ BinarySensorStateResponse::MESSAGE_TYPE, BinarySensorStateResponse::ESTIMATED_SIZE);
320
321
  }
321
322
 
322
323
  uint16_t APIConnection::try_send_binary_sensor_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
@@ -343,7 +344,8 @@ uint16_t APIConnection::try_send_binary_sensor_info(EntityBase *entity, APIConne
343
344
 
344
345
  #ifdef USE_COVER
345
346
  bool APIConnection::send_cover_state(cover::Cover *cover) {
346
- return this->send_message_smart_(cover, &APIConnection::try_send_cover_state, CoverStateResponse::MESSAGE_TYPE);
347
+ return this->send_message_smart_(cover, &APIConnection::try_send_cover_state, CoverStateResponse::MESSAGE_TYPE,
348
+ CoverStateResponse::ESTIMATED_SIZE);
347
349
  }
348
350
  uint16_t APIConnection::try_send_cover_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
349
351
  bool is_single) {
@@ -400,7 +402,8 @@ void APIConnection::cover_command(const CoverCommandRequest &msg) {
400
402
 
401
403
  #ifdef USE_FAN
402
404
  bool APIConnection::send_fan_state(fan::Fan *fan) {
403
- return this->send_message_smart_(fan, &APIConnection::try_send_fan_state, FanStateResponse::MESSAGE_TYPE);
405
+ return this->send_message_smart_(fan, &APIConnection::try_send_fan_state, FanStateResponse::MESSAGE_TYPE,
406
+ FanStateResponse::ESTIMATED_SIZE);
404
407
  }
405
408
  uint16_t APIConnection::try_send_fan_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
406
409
  bool is_single) {
@@ -455,7 +458,8 @@ void APIConnection::fan_command(const FanCommandRequest &msg) {
455
458
 
456
459
  #ifdef USE_LIGHT
457
460
  bool APIConnection::send_light_state(light::LightState *light) {
458
- return this->send_message_smart_(light, &APIConnection::try_send_light_state, LightStateResponse::MESSAGE_TYPE);
461
+ return this->send_message_smart_(light, &APIConnection::try_send_light_state, LightStateResponse::MESSAGE_TYPE,
462
+ LightStateResponse::ESTIMATED_SIZE);
459
463
  }
460
464
  uint16_t APIConnection::try_send_light_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
461
465
  bool is_single) {
@@ -543,7 +547,8 @@ void APIConnection::light_command(const LightCommandRequest &msg) {
543
547
 
544
548
  #ifdef USE_SENSOR
545
549
  bool APIConnection::send_sensor_state(sensor::Sensor *sensor) {
546
- return this->send_message_smart_(sensor, &APIConnection::try_send_sensor_state, SensorStateResponse::MESSAGE_TYPE);
550
+ return this->send_message_smart_(sensor, &APIConnection::try_send_sensor_state, SensorStateResponse::MESSAGE_TYPE,
551
+ SensorStateResponse::ESTIMATED_SIZE);
547
552
  }
548
553
 
549
554
  uint16_t APIConnection::try_send_sensor_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
@@ -575,7 +580,8 @@ uint16_t APIConnection::try_send_sensor_info(EntityBase *entity, APIConnection *
575
580
 
576
581
  #ifdef USE_SWITCH
577
582
  bool APIConnection::send_switch_state(switch_::Switch *a_switch) {
578
- return this->send_message_smart_(a_switch, &APIConnection::try_send_switch_state, SwitchStateResponse::MESSAGE_TYPE);
583
+ return this->send_message_smart_(a_switch, &APIConnection::try_send_switch_state, SwitchStateResponse::MESSAGE_TYPE,
584
+ SwitchStateResponse::ESTIMATED_SIZE);
579
585
  }
580
586
 
581
587
  uint16_t APIConnection::try_send_switch_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
@@ -611,7 +617,7 @@ void APIConnection::switch_command(const SwitchCommandRequest &msg) {
611
617
  #ifdef USE_TEXT_SENSOR
612
618
  bool APIConnection::send_text_sensor_state(text_sensor::TextSensor *text_sensor) {
613
619
  return this->send_message_smart_(text_sensor, &APIConnection::try_send_text_sensor_state,
614
- TextSensorStateResponse::MESSAGE_TYPE);
620
+ TextSensorStateResponse::MESSAGE_TYPE, TextSensorStateResponse::ESTIMATED_SIZE);
615
621
  }
616
622
 
617
623
  uint16_t APIConnection::try_send_text_sensor_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
@@ -638,7 +644,8 @@ uint16_t APIConnection::try_send_text_sensor_info(EntityBase *entity, APIConnect
638
644
 
639
645
  #ifdef USE_CLIMATE
640
646
  bool APIConnection::send_climate_state(climate::Climate *climate) {
641
- return this->send_message_smart_(climate, &APIConnection::try_send_climate_state, ClimateStateResponse::MESSAGE_TYPE);
647
+ return this->send_message_smart_(climate, &APIConnection::try_send_climate_state, ClimateStateResponse::MESSAGE_TYPE,
648
+ ClimateStateResponse::ESTIMATED_SIZE);
642
649
  }
643
650
  uint16_t APIConnection::try_send_climate_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
644
651
  bool is_single) {
@@ -734,7 +741,8 @@ void APIConnection::climate_command(const ClimateCommandRequest &msg) {
734
741
 
735
742
  #ifdef USE_NUMBER
736
743
  bool APIConnection::send_number_state(number::Number *number) {
737
- return this->send_message_smart_(number, &APIConnection::try_send_number_state, NumberStateResponse::MESSAGE_TYPE);
744
+ return this->send_message_smart_(number, &APIConnection::try_send_number_state, NumberStateResponse::MESSAGE_TYPE,
745
+ NumberStateResponse::ESTIMATED_SIZE);
738
746
  }
739
747
 
740
748
  uint16_t APIConnection::try_send_number_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
@@ -770,7 +778,8 @@ void APIConnection::number_command(const NumberCommandRequest &msg) {
770
778
 
771
779
  #ifdef USE_DATETIME_DATE
772
780
  bool APIConnection::send_date_state(datetime::DateEntity *date) {
773
- return this->send_message_smart_(date, &APIConnection::try_send_date_state, DateStateResponse::MESSAGE_TYPE);
781
+ return this->send_message_smart_(date, &APIConnection::try_send_date_state, DateStateResponse::MESSAGE_TYPE,
782
+ DateStateResponse::ESTIMATED_SIZE);
774
783
  }
775
784
  uint16_t APIConnection::try_send_date_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
776
785
  bool is_single) {
@@ -800,7 +809,8 @@ void APIConnection::date_command(const DateCommandRequest &msg) {
800
809
 
801
810
  #ifdef USE_DATETIME_TIME
802
811
  bool APIConnection::send_time_state(datetime::TimeEntity *time) {
803
- return this->send_message_smart_(time, &APIConnection::try_send_time_state, TimeStateResponse::MESSAGE_TYPE);
812
+ return this->send_message_smart_(time, &APIConnection::try_send_time_state, TimeStateResponse::MESSAGE_TYPE,
813
+ TimeStateResponse::ESTIMATED_SIZE);
804
814
  }
805
815
  uint16_t APIConnection::try_send_time_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
806
816
  bool is_single) {
@@ -831,7 +841,7 @@ void APIConnection::time_command(const TimeCommandRequest &msg) {
831
841
  #ifdef USE_DATETIME_DATETIME
832
842
  bool APIConnection::send_datetime_state(datetime::DateTimeEntity *datetime) {
833
843
  return this->send_message_smart_(datetime, &APIConnection::try_send_datetime_state,
834
- DateTimeStateResponse::MESSAGE_TYPE);
844
+ DateTimeStateResponse::MESSAGE_TYPE, DateTimeStateResponse::ESTIMATED_SIZE);
835
845
  }
836
846
  uint16_t APIConnection::try_send_datetime_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
837
847
  bool is_single) {
@@ -862,7 +872,8 @@ void APIConnection::datetime_command(const DateTimeCommandRequest &msg) {
862
872
 
863
873
  #ifdef USE_TEXT
864
874
  bool APIConnection::send_text_state(text::Text *text) {
865
- return this->send_message_smart_(text, &APIConnection::try_send_text_state, TextStateResponse::MESSAGE_TYPE);
875
+ return this->send_message_smart_(text, &APIConnection::try_send_text_state, TextStateResponse::MESSAGE_TYPE,
876
+ TextStateResponse::ESTIMATED_SIZE);
866
877
  }
867
878
 
868
879
  uint16_t APIConnection::try_send_text_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
@@ -896,7 +907,8 @@ void APIConnection::text_command(const TextCommandRequest &msg) {
896
907
 
897
908
  #ifdef USE_SELECT
898
909
  bool APIConnection::send_select_state(select::Select *select) {
899
- return this->send_message_smart_(select, &APIConnection::try_send_select_state, SelectStateResponse::MESSAGE_TYPE);
910
+ return this->send_message_smart_(select, &APIConnection::try_send_select_state, SelectStateResponse::MESSAGE_TYPE,
911
+ SelectStateResponse::ESTIMATED_SIZE);
900
912
  }
901
913
 
902
914
  uint16_t APIConnection::try_send_select_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
@@ -944,7 +956,8 @@ void esphome::api::APIConnection::button_command(const ButtonCommandRequest &msg
944
956
 
945
957
  #ifdef USE_LOCK
946
958
  bool APIConnection::send_lock_state(lock::Lock *a_lock) {
947
- return this->send_message_smart_(a_lock, &APIConnection::try_send_lock_state, LockStateResponse::MESSAGE_TYPE);
959
+ return this->send_message_smart_(a_lock, &APIConnection::try_send_lock_state, LockStateResponse::MESSAGE_TYPE,
960
+ LockStateResponse::ESTIMATED_SIZE);
948
961
  }
949
962
 
950
963
  uint16_t APIConnection::try_send_lock_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
@@ -986,7 +999,8 @@ void APIConnection::lock_command(const LockCommandRequest &msg) {
986
999
 
987
1000
  #ifdef USE_VALVE
988
1001
  bool APIConnection::send_valve_state(valve::Valve *valve) {
989
- return this->send_message_smart_(valve, &APIConnection::try_send_valve_state, ValveStateResponse::MESSAGE_TYPE);
1002
+ return this->send_message_smart_(valve, &APIConnection::try_send_valve_state, ValveStateResponse::MESSAGE_TYPE,
1003
+ ValveStateResponse::ESTIMATED_SIZE);
990
1004
  }
991
1005
  uint16_t APIConnection::try_send_valve_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
992
1006
  bool is_single) {
@@ -1023,7 +1037,7 @@ void APIConnection::valve_command(const ValveCommandRequest &msg) {
1023
1037
  #ifdef USE_MEDIA_PLAYER
1024
1038
  bool APIConnection::send_media_player_state(media_player::MediaPlayer *media_player) {
1025
1039
  return this->send_message_smart_(media_player, &APIConnection::try_send_media_player_state,
1026
- MediaPlayerStateResponse::MESSAGE_TYPE);
1040
+ MediaPlayerStateResponse::MESSAGE_TYPE, MediaPlayerStateResponse::ESTIMATED_SIZE);
1027
1041
  }
1028
1042
  uint16_t APIConnection::try_send_media_player_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
1029
1043
  bool is_single) {
@@ -1262,7 +1276,8 @@ void APIConnection::voice_assistant_set_configuration(const VoiceAssistantSetCon
1262
1276
  #ifdef USE_ALARM_CONTROL_PANEL
1263
1277
  bool APIConnection::send_alarm_control_panel_state(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) {
1264
1278
  return this->send_message_smart_(a_alarm_control_panel, &APIConnection::try_send_alarm_control_panel_state,
1265
- AlarmControlPanelStateResponse::MESSAGE_TYPE);
1279
+ AlarmControlPanelStateResponse::MESSAGE_TYPE,
1280
+ AlarmControlPanelStateResponse::ESTIMATED_SIZE);
1266
1281
  }
1267
1282
  uint16_t APIConnection::try_send_alarm_control_panel_state(EntityBase *entity, APIConnection *conn,
1268
1283
  uint32_t remaining_size, bool is_single) {
@@ -1316,7 +1331,8 @@ void APIConnection::alarm_control_panel_command(const AlarmControlPanelCommandRe
1316
1331
 
1317
1332
  #ifdef USE_EVENT
1318
1333
  void APIConnection::send_event(event::Event *event, const std::string &event_type) {
1319
- this->schedule_message_(event, MessageCreator(event_type), EventResponse::MESSAGE_TYPE);
1334
+ this->schedule_message_(event, MessageCreator(event_type), EventResponse::MESSAGE_TYPE,
1335
+ EventResponse::ESTIMATED_SIZE);
1320
1336
  }
1321
1337
  uint16_t APIConnection::try_send_event_response(event::Event *event, const std::string &event_type, APIConnection *conn,
1322
1338
  uint32_t remaining_size, bool is_single) {
@@ -1341,7 +1357,8 @@ uint16_t APIConnection::try_send_event_info(EntityBase *entity, APIConnection *c
1341
1357
 
1342
1358
  #ifdef USE_UPDATE
1343
1359
  bool APIConnection::send_update_state(update::UpdateEntity *update) {
1344
- return this->send_message_smart_(update, &APIConnection::try_send_update_state, UpdateStateResponse::MESSAGE_TYPE);
1360
+ return this->send_message_smart_(update, &APIConnection::try_send_update_state, UpdateStateResponse::MESSAGE_TYPE,
1361
+ UpdateStateResponse::ESTIMATED_SIZE);
1345
1362
  }
1346
1363
  uint16_t APIConnection::try_send_update_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
1347
1364
  bool is_single) {
@@ -1534,6 +1551,7 @@ void APIConnection::on_home_assistant_state_response(const HomeAssistantStateRes
1534
1551
  }
1535
1552
  }
1536
1553
  }
1554
+ #ifdef USE_API_SERVICES
1537
1555
  void APIConnection::execute_service(const ExecuteServiceRequest &msg) {
1538
1556
  bool found = false;
1539
1557
  for (auto *service : this->parent_->get_user_services()) {
@@ -1545,6 +1563,7 @@ void APIConnection::execute_service(const ExecuteServiceRequest &msg) {
1545
1563
  ESP_LOGV(TAG, "Could not find service");
1546
1564
  }
1547
1565
  }
1566
+ #endif
1548
1567
  #ifdef USE_API_NOISE
1549
1568
  NoiseEncryptionSetKeyResponse APIConnection::noise_encryption_set_key(const NoiseEncryptionSetKeyRequest &msg) {
1550
1569
  psk_t psk{};
@@ -1588,7 +1607,7 @@ bool APIConnection::try_to_clear_buffer(bool log_out_of_space) {
1588
1607
  }
1589
1608
  return false;
1590
1609
  }
1591
- bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint16_t message_type) {
1610
+ bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint8_t message_type) {
1592
1611
  if (!this->try_to_clear_buffer(message_type != SubscribeLogsResponse::MESSAGE_TYPE)) { // SubscribeLogsResponse
1593
1612
  return false;
1594
1613
  }
@@ -1622,7 +1641,8 @@ void APIConnection::on_fatal_error() {
1622
1641
  this->flags_.remove = true;
1623
1642
  }
1624
1643
 
1625
- void APIConnection::DeferredBatch::add_item(EntityBase *entity, MessageCreator creator, uint16_t message_type) {
1644
+ void APIConnection::DeferredBatch::add_item(EntityBase *entity, MessageCreator creator, uint8_t message_type,
1645
+ uint8_t estimated_size) {
1626
1646
  // Check if we already have a message of this type for this entity
1627
1647
  // This provides deduplication per entity/message_type combination
1628
1648
  // O(n) but optimized for RAM and not performance.
@@ -1637,12 +1657,13 @@ void APIConnection::DeferredBatch::add_item(EntityBase *entity, MessageCreator c
1637
1657
  }
1638
1658
 
1639
1659
  // No existing item found, add new one
1640
- items.emplace_back(entity, std::move(creator), message_type);
1660
+ items.emplace_back(entity, std::move(creator), message_type, estimated_size);
1641
1661
  }
1642
1662
 
1643
- void APIConnection::DeferredBatch::add_item_front(EntityBase *entity, MessageCreator creator, uint16_t message_type) {
1663
+ void APIConnection::DeferredBatch::add_item_front(EntityBase *entity, MessageCreator creator, uint8_t message_type,
1664
+ uint8_t estimated_size) {
1644
1665
  // Insert at front for high priority messages (no deduplication check)
1645
- items.insert(items.begin(), BatchItem(entity, std::move(creator), message_type));
1666
+ items.insert(items.begin(), BatchItem(entity, std::move(creator), message_type, estimated_size));
1646
1667
  }
1647
1668
 
1648
1669
  bool APIConnection::schedule_batch_() {
@@ -1714,7 +1735,7 @@ void APIConnection::process_batch_() {
1714
1735
  uint32_t total_estimated_size = 0;
1715
1736
  for (size_t i = 0; i < this->deferred_batch_.size(); i++) {
1716
1737
  const auto &item = this->deferred_batch_[i];
1717
- total_estimated_size += get_estimated_message_size(item.message_type);
1738
+ total_estimated_size += item.estimated_size;
1718
1739
  }
1719
1740
 
1720
1741
  // Calculate total overhead for all messages
@@ -1752,9 +1773,9 @@ void APIConnection::process_batch_() {
1752
1773
 
1753
1774
  // Update tracking variables
1754
1775
  items_processed++;
1755
- // After first message, set remaining size to MAX_PACKET_SIZE to avoid fragmentation
1776
+ // After first message, set remaining size to MAX_BATCH_PACKET_SIZE to avoid fragmentation
1756
1777
  if (items_processed == 1) {
1757
- remaining_size = MAX_PACKET_SIZE;
1778
+ remaining_size = MAX_BATCH_PACKET_SIZE;
1758
1779
  }
1759
1780
  remaining_size -= payload_size;
1760
1781
  // Calculate where the next message's header padding will start
@@ -1808,7 +1829,7 @@ void APIConnection::process_batch_() {
1808
1829
  }
1809
1830
 
1810
1831
  uint16_t APIConnection::MessageCreator::operator()(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
1811
- bool is_single, uint16_t message_type) const {
1832
+ bool is_single, uint8_t message_type) const {
1812
1833
  #ifdef USE_EVENT
1813
1834
  // Special case: EventResponse uses string pointer
1814
1835
  if (message_type == EventResponse::MESSAGE_TYPE) {
@@ -1839,149 +1860,6 @@ uint16_t APIConnection::try_send_ping_request(EntityBase *entity, APIConnection
1839
1860
  return encode_message_to_buffer(req, PingRequest::MESSAGE_TYPE, conn, remaining_size, is_single);
1840
1861
  }
1841
1862
 
1842
- uint16_t APIConnection::get_estimated_message_size(uint16_t message_type) {
1843
- // Use generated ESTIMATED_SIZE constants from each message type
1844
- switch (message_type) {
1845
- #ifdef USE_BINARY_SENSOR
1846
- case BinarySensorStateResponse::MESSAGE_TYPE:
1847
- return BinarySensorStateResponse::ESTIMATED_SIZE;
1848
- case ListEntitiesBinarySensorResponse::MESSAGE_TYPE:
1849
- return ListEntitiesBinarySensorResponse::ESTIMATED_SIZE;
1850
- #endif
1851
- #ifdef USE_SENSOR
1852
- case SensorStateResponse::MESSAGE_TYPE:
1853
- return SensorStateResponse::ESTIMATED_SIZE;
1854
- case ListEntitiesSensorResponse::MESSAGE_TYPE:
1855
- return ListEntitiesSensorResponse::ESTIMATED_SIZE;
1856
- #endif
1857
- #ifdef USE_SWITCH
1858
- case SwitchStateResponse::MESSAGE_TYPE:
1859
- return SwitchStateResponse::ESTIMATED_SIZE;
1860
- case ListEntitiesSwitchResponse::MESSAGE_TYPE:
1861
- return ListEntitiesSwitchResponse::ESTIMATED_SIZE;
1862
- #endif
1863
- #ifdef USE_TEXT_SENSOR
1864
- case TextSensorStateResponse::MESSAGE_TYPE:
1865
- return TextSensorStateResponse::ESTIMATED_SIZE;
1866
- case ListEntitiesTextSensorResponse::MESSAGE_TYPE:
1867
- return ListEntitiesTextSensorResponse::ESTIMATED_SIZE;
1868
- #endif
1869
- #ifdef USE_NUMBER
1870
- case NumberStateResponse::MESSAGE_TYPE:
1871
- return NumberStateResponse::ESTIMATED_SIZE;
1872
- case ListEntitiesNumberResponse::MESSAGE_TYPE:
1873
- return ListEntitiesNumberResponse::ESTIMATED_SIZE;
1874
- #endif
1875
- #ifdef USE_TEXT
1876
- case TextStateResponse::MESSAGE_TYPE:
1877
- return TextStateResponse::ESTIMATED_SIZE;
1878
- case ListEntitiesTextResponse::MESSAGE_TYPE:
1879
- return ListEntitiesTextResponse::ESTIMATED_SIZE;
1880
- #endif
1881
- #ifdef USE_SELECT
1882
- case SelectStateResponse::MESSAGE_TYPE:
1883
- return SelectStateResponse::ESTIMATED_SIZE;
1884
- case ListEntitiesSelectResponse::MESSAGE_TYPE:
1885
- return ListEntitiesSelectResponse::ESTIMATED_SIZE;
1886
- #endif
1887
- #ifdef USE_LOCK
1888
- case LockStateResponse::MESSAGE_TYPE:
1889
- return LockStateResponse::ESTIMATED_SIZE;
1890
- case ListEntitiesLockResponse::MESSAGE_TYPE:
1891
- return ListEntitiesLockResponse::ESTIMATED_SIZE;
1892
- #endif
1893
- #ifdef USE_EVENT
1894
- case EventResponse::MESSAGE_TYPE:
1895
- return EventResponse::ESTIMATED_SIZE;
1896
- case ListEntitiesEventResponse::MESSAGE_TYPE:
1897
- return ListEntitiesEventResponse::ESTIMATED_SIZE;
1898
- #endif
1899
- #ifdef USE_COVER
1900
- case CoverStateResponse::MESSAGE_TYPE:
1901
- return CoverStateResponse::ESTIMATED_SIZE;
1902
- case ListEntitiesCoverResponse::MESSAGE_TYPE:
1903
- return ListEntitiesCoverResponse::ESTIMATED_SIZE;
1904
- #endif
1905
- #ifdef USE_FAN
1906
- case FanStateResponse::MESSAGE_TYPE:
1907
- return FanStateResponse::ESTIMATED_SIZE;
1908
- case ListEntitiesFanResponse::MESSAGE_TYPE:
1909
- return ListEntitiesFanResponse::ESTIMATED_SIZE;
1910
- #endif
1911
- #ifdef USE_LIGHT
1912
- case LightStateResponse::MESSAGE_TYPE:
1913
- return LightStateResponse::ESTIMATED_SIZE;
1914
- case ListEntitiesLightResponse::MESSAGE_TYPE:
1915
- return ListEntitiesLightResponse::ESTIMATED_SIZE;
1916
- #endif
1917
- #ifdef USE_CLIMATE
1918
- case ClimateStateResponse::MESSAGE_TYPE:
1919
- return ClimateStateResponse::ESTIMATED_SIZE;
1920
- case ListEntitiesClimateResponse::MESSAGE_TYPE:
1921
- return ListEntitiesClimateResponse::ESTIMATED_SIZE;
1922
- #endif
1923
- #ifdef USE_ESP32_CAMERA
1924
- case ListEntitiesCameraResponse::MESSAGE_TYPE:
1925
- return ListEntitiesCameraResponse::ESTIMATED_SIZE;
1926
- #endif
1927
- #ifdef USE_BUTTON
1928
- case ListEntitiesButtonResponse::MESSAGE_TYPE:
1929
- return ListEntitiesButtonResponse::ESTIMATED_SIZE;
1930
- #endif
1931
- #ifdef USE_MEDIA_PLAYER
1932
- case MediaPlayerStateResponse::MESSAGE_TYPE:
1933
- return MediaPlayerStateResponse::ESTIMATED_SIZE;
1934
- case ListEntitiesMediaPlayerResponse::MESSAGE_TYPE:
1935
- return ListEntitiesMediaPlayerResponse::ESTIMATED_SIZE;
1936
- #endif
1937
- #ifdef USE_ALARM_CONTROL_PANEL
1938
- case AlarmControlPanelStateResponse::MESSAGE_TYPE:
1939
- return AlarmControlPanelStateResponse::ESTIMATED_SIZE;
1940
- case ListEntitiesAlarmControlPanelResponse::MESSAGE_TYPE:
1941
- return ListEntitiesAlarmControlPanelResponse::ESTIMATED_SIZE;
1942
- #endif
1943
- #ifdef USE_DATETIME_DATE
1944
- case DateStateResponse::MESSAGE_TYPE:
1945
- return DateStateResponse::ESTIMATED_SIZE;
1946
- case ListEntitiesDateResponse::MESSAGE_TYPE:
1947
- return ListEntitiesDateResponse::ESTIMATED_SIZE;
1948
- #endif
1949
- #ifdef USE_DATETIME_TIME
1950
- case TimeStateResponse::MESSAGE_TYPE:
1951
- return TimeStateResponse::ESTIMATED_SIZE;
1952
- case ListEntitiesTimeResponse::MESSAGE_TYPE:
1953
- return ListEntitiesTimeResponse::ESTIMATED_SIZE;
1954
- #endif
1955
- #ifdef USE_DATETIME_DATETIME
1956
- case DateTimeStateResponse::MESSAGE_TYPE:
1957
- return DateTimeStateResponse::ESTIMATED_SIZE;
1958
- case ListEntitiesDateTimeResponse::MESSAGE_TYPE:
1959
- return ListEntitiesDateTimeResponse::ESTIMATED_SIZE;
1960
- #endif
1961
- #ifdef USE_VALVE
1962
- case ValveStateResponse::MESSAGE_TYPE:
1963
- return ValveStateResponse::ESTIMATED_SIZE;
1964
- case ListEntitiesValveResponse::MESSAGE_TYPE:
1965
- return ListEntitiesValveResponse::ESTIMATED_SIZE;
1966
- #endif
1967
- #ifdef USE_UPDATE
1968
- case UpdateStateResponse::MESSAGE_TYPE:
1969
- return UpdateStateResponse::ESTIMATED_SIZE;
1970
- case ListEntitiesUpdateResponse::MESSAGE_TYPE:
1971
- return ListEntitiesUpdateResponse::ESTIMATED_SIZE;
1972
- #endif
1973
- case ListEntitiesServicesResponse::MESSAGE_TYPE:
1974
- return ListEntitiesServicesResponse::ESTIMATED_SIZE;
1975
- case ListEntitiesDoneResponse::MESSAGE_TYPE:
1976
- return ListEntitiesDoneResponse::ESTIMATED_SIZE;
1977
- case DisconnectRequest::MESSAGE_TYPE:
1978
- return DisconnectRequest::ESTIMATED_SIZE;
1979
- default:
1980
- // Fallback for unknown message types
1981
- return 24;
1982
- }
1983
- }
1984
-
1985
1863
  } // namespace api
1986
1864
  } // namespace esphome
1987
1865
  #endif
@@ -33,7 +33,7 @@ class APIConnection : public APIServerConnection {
33
33
 
34
34
  bool send_list_info_done() {
35
35
  return this->schedule_message_(nullptr, &APIConnection::try_send_list_info_done,
36
- ListEntitiesDoneResponse::MESSAGE_TYPE);
36
+ ListEntitiesDoneResponse::MESSAGE_TYPE, ListEntitiesDoneResponse::ESTIMATED_SIZE);
37
37
  }
38
38
  #ifdef USE_BINARY_SENSOR
39
39
  bool send_binary_sensor_state(binary_sensor::BinarySensor *binary_sensor);
@@ -195,7 +195,9 @@ class APIConnection : public APIServerConnection {
195
195
  // TODO
196
196
  return {};
197
197
  }
198
+ #ifdef USE_API_SERVICES
198
199
  void execute_service(const ExecuteServiceRequest &msg) override;
200
+ #endif
199
201
  #ifdef USE_API_NOISE
200
202
  NoiseEncryptionSetKeyResponse noise_encryption_set_key(const NoiseEncryptionSetKeyRequest &msg) override;
201
203
  #endif
@@ -256,7 +258,7 @@ class APIConnection : public APIServerConnection {
256
258
  }
257
259
 
258
260
  bool try_to_clear_buffer(bool log_out_of_space);
259
- bool send_buffer(ProtoWriteBuffer buffer, uint16_t message_type) override;
261
+ bool send_buffer(ProtoWriteBuffer buffer, uint8_t message_type) override;
260
262
 
261
263
  std::string get_client_combined_info() const {
262
264
  if (this->client_info_ == this->client_peername_) {
@@ -298,7 +300,7 @@ class APIConnection : public APIServerConnection {
298
300
  }
299
301
 
300
302
  // Non-template helper to encode any ProtoMessage
301
- static uint16_t encode_message_to_buffer(ProtoMessage &msg, uint16_t message_type, APIConnection *conn,
303
+ static uint16_t encode_message_to_buffer(ProtoMessage &msg, uint8_t message_type, APIConnection *conn,
302
304
  uint32_t remaining_size, bool is_single);
303
305
 
304
306
  #ifdef USE_VOICE_ASSISTANT
@@ -443,9 +445,6 @@ class APIConnection : public APIServerConnection {
443
445
  static uint16_t try_send_disconnect_request(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
444
446
  bool is_single);
445
447
 
446
- // Helper function to get estimated message size for buffer pre-allocation
447
- static uint16_t get_estimated_message_size(uint16_t message_type);
448
-
449
448
  // Batch message method for ping requests
450
449
  static uint16_t try_send_ping_request(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
451
450
  bool is_single);
@@ -505,10 +504,10 @@ class APIConnection : public APIServerConnection {
505
504
 
506
505
  // Call operator - uses message_type to determine union type
507
506
  uint16_t operator()(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, bool is_single,
508
- uint16_t message_type) const;
507
+ uint8_t message_type) const;
509
508
 
510
509
  // Manual cleanup method - must be called before destruction for string types
511
- void cleanup(uint16_t message_type) {
510
+ void cleanup(uint8_t message_type) {
512
511
  #ifdef USE_EVENT
513
512
  if (message_type == EventResponse::MESSAGE_TYPE && data_.string_ptr != nullptr) {
514
513
  delete data_.string_ptr;
@@ -529,11 +528,12 @@ class APIConnection : public APIServerConnection {
529
528
  struct BatchItem {
530
529
  EntityBase *entity; // Entity pointer
531
530
  MessageCreator creator; // Function that creates the message when needed
532
- uint16_t message_type; // Message type for overhead calculation
531
+ uint8_t message_type; // Message type for overhead calculation (max 255)
532
+ uint8_t estimated_size; // Estimated message size (max 255 bytes)
533
533
 
534
534
  // Constructor for creating BatchItem
535
- BatchItem(EntityBase *entity, MessageCreator creator, uint16_t message_type)
536
- : entity(entity), creator(std::move(creator)), message_type(message_type) {}
535
+ BatchItem(EntityBase *entity, MessageCreator creator, uint8_t message_type, uint8_t estimated_size)
536
+ : entity(entity), creator(std::move(creator)), message_type(message_type), estimated_size(estimated_size) {}
537
537
  };
538
538
 
539
539
  std::vector<BatchItem> items;
@@ -559,9 +559,9 @@ class APIConnection : public APIServerConnection {
559
559
  }
560
560
 
561
561
  // Add item to the batch
562
- void add_item(EntityBase *entity, MessageCreator creator, uint16_t message_type);
562
+ void add_item(EntityBase *entity, MessageCreator creator, uint8_t message_type, uint8_t estimated_size);
563
563
  // Add item to the front of the batch (for high priority messages like ping)
564
- void add_item_front(EntityBase *entity, MessageCreator creator, uint16_t message_type);
564
+ void add_item_front(EntityBase *entity, MessageCreator creator, uint8_t message_type, uint8_t estimated_size);
565
565
 
566
566
  // Clear all items with proper cleanup
567
567
  void clear() {
@@ -630,7 +630,7 @@ class APIConnection : public APIServerConnection {
630
630
  // to send in one go. This is the maximum size of a single packet
631
631
  // that can be sent over the network.
632
632
  // This is to avoid fragmentation of the packet.
633
- static constexpr size_t MAX_PACKET_SIZE = 1390; // MTU
633
+ static constexpr size_t MAX_BATCH_PACKET_SIZE = 1390; // MTU
634
634
 
635
635
  bool schedule_batch_();
636
636
  void process_batch_();
@@ -641,9 +641,9 @@ class APIConnection : public APIServerConnection {
641
641
 
642
642
  #ifdef HAS_PROTO_MESSAGE_DUMP
643
643
  // Helper to log a proto message from a MessageCreator object
644
- void log_proto_message_(EntityBase *entity, const MessageCreator &creator, uint16_t message_type) {
644
+ void log_proto_message_(EntityBase *entity, const MessageCreator &creator, uint8_t message_type) {
645
645
  this->flags_.log_only_mode = true;
646
- creator(entity, this, MAX_PACKET_SIZE, true, message_type);
646
+ creator(entity, this, MAX_BATCH_PACKET_SIZE, true, message_type);
647
647
  this->flags_.log_only_mode = false;
648
648
  }
649
649
 
@@ -654,7 +654,8 @@ class APIConnection : public APIServerConnection {
654
654
  #endif
655
655
 
656
656
  // Helper method to send a message either immediately or via batching
657
- bool send_message_smart_(EntityBase *entity, MessageCreatorPtr creator, uint16_t message_type) {
657
+ bool send_message_smart_(EntityBase *entity, MessageCreatorPtr creator, uint8_t message_type,
658
+ uint8_t estimated_size) {
658
659
  // Try to send immediately if:
659
660
  // 1. We should try to send immediately (should_try_send_immediately = true)
660
661
  // 2. Batch delay is 0 (user has opted in to immediate sending)
@@ -662,7 +663,7 @@ class APIConnection : public APIServerConnection {
662
663
  if (this->flags_.should_try_send_immediately && this->get_batch_delay_ms_() == 0 &&
663
664
  this->helper_->can_write_without_blocking()) {
664
665
  // Now actually encode and send
665
- if (creator(entity, this, MAX_PACKET_SIZE, true) &&
666
+ if (creator(entity, this, MAX_BATCH_PACKET_SIZE, true) &&
666
667
  this->send_buffer(ProtoWriteBuffer{&this->parent_->get_shared_buffer_ref()}, message_type)) {
667
668
  #ifdef HAS_PROTO_MESSAGE_DUMP
668
669
  // Log the message in verbose mode
@@ -675,23 +676,25 @@ class APIConnection : public APIServerConnection {
675
676
  }
676
677
 
677
678
  // Fall back to scheduled batching
678
- return this->schedule_message_(entity, creator, message_type);
679
+ return this->schedule_message_(entity, creator, message_type, estimated_size);
679
680
  }
680
681
 
681
682
  // Helper function to schedule a deferred message with known message type
682
- bool schedule_message_(EntityBase *entity, MessageCreator creator, uint16_t message_type) {
683
- this->deferred_batch_.add_item(entity, std::move(creator), message_type);
683
+ bool schedule_message_(EntityBase *entity, MessageCreator creator, uint8_t message_type, uint8_t estimated_size) {
684
+ this->deferred_batch_.add_item(entity, std::move(creator), message_type, estimated_size);
684
685
  return this->schedule_batch_();
685
686
  }
686
687
 
687
688
  // Overload for function pointers (for info messages and current state reads)
688
- bool schedule_message_(EntityBase *entity, MessageCreatorPtr function_ptr, uint16_t message_type) {
689
- return schedule_message_(entity, MessageCreator(function_ptr), message_type);
689
+ bool schedule_message_(EntityBase *entity, MessageCreatorPtr function_ptr, uint8_t message_type,
690
+ uint8_t estimated_size) {
691
+ return schedule_message_(entity, MessageCreator(function_ptr), message_type, estimated_size);
690
692
  }
691
693
 
692
694
  // Helper function to schedule a high priority message at the front of the batch
693
- bool schedule_message_front_(EntityBase *entity, MessageCreatorPtr function_ptr, uint16_t message_type) {
694
- this->deferred_batch_.add_item_front(entity, MessageCreator(function_ptr), message_type);
695
+ bool schedule_message_front_(EntityBase *entity, MessageCreatorPtr function_ptr, uint8_t message_type,
696
+ uint8_t estimated_size) {
697
+ this->deferred_batch_.add_item_front(entity, MessageCreator(function_ptr), message_type, estimated_size);
695
698
  return this->schedule_batch_();
696
699
  }
697
700
  };