esphome 2025.6.0b1__py3-none-any.whl → 2025.6.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.
Files changed (71) 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/microphone/i2s_audio_microphone.cpp +12 -9
  26. esphome/components/kmeteriso/kmeteriso.cpp +2 -3
  27. esphome/components/logger/logger.cpp +2 -15
  28. esphome/components/logger/logger.h +1 -2
  29. esphome/components/mqtt/mqtt_component.cpp +1 -1
  30. esphome/components/nextion/binary_sensor/nextion_binarysensor.cpp +1 -1
  31. esphome/components/nextion/nextion_upload_arduino.cpp +12 -9
  32. esphome/components/nextion/nextion_upload_idf.cpp +11 -9
  33. esphome/components/nextion/sensor/nextion_sensor.cpp +1 -1
  34. esphome/components/nextion/text_sensor/nextion_textsensor.cpp +1 -1
  35. esphome/components/number/number.cpp +1 -1
  36. esphome/components/number/number.h +0 -4
  37. esphome/components/prometheus/__init__.py +0 -1
  38. esphome/components/select/select.cpp +1 -1
  39. esphome/components/select/select.h +0 -4
  40. esphome/components/sensor/sensor.cpp +8 -4
  41. esphome/components/sensor/sensor.h +3 -6
  42. esphome/components/status_led/light/status_led_light.cpp +2 -2
  43. esphome/components/status_led/light/status_led_light.h +1 -1
  44. esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp +14 -9
  45. esphome/components/template/alarm_control_panel/template_alarm_control_panel.h +1 -0
  46. esphome/components/text/text.cpp +1 -1
  47. esphome/components/text/text.h +0 -4
  48. esphome/components/text_sensor/text_sensor.cpp +8 -4
  49. esphome/components/text_sensor/text_sensor.h +6 -6
  50. esphome/components/update/update_entity.cpp +1 -1
  51. esphome/components/update/update_entity.h +0 -3
  52. esphome/components/uptime/sensor/uptime_timestamp_sensor.cpp +1 -1
  53. esphome/components/web_server_idf/__init__.py +0 -2
  54. esphome/components/web_server_idf/web_server_idf.cpp +6 -2
  55. esphome/components/web_server_idf/web_server_idf.h +7 -0
  56. esphome/components/weikai/weikai.cpp +1 -1
  57. esphome/const.py +1 -1
  58. esphome/core/application.cpp +14 -8
  59. esphome/core/application.h +7 -7
  60. esphome/core/component.cpp +36 -15
  61. esphome/core/component.h +30 -13
  62. esphome/core/entity_base.cpp +4 -16
  63. esphome/core/entity_base.h +27 -13
  64. esphome/core/helpers.h +1 -1
  65. esphome/wizard.py +0 -16
  66. {esphome-2025.6.0b1.dist-info → esphome-2025.6.0b2.dist-info}/METADATA +2 -2
  67. {esphome-2025.6.0b1.dist-info → esphome-2025.6.0b2.dist-info}/RECORD +71 -70
  68. {esphome-2025.6.0b1.dist-info → esphome-2025.6.0b2.dist-info}/WHEEL +0 -0
  69. {esphome-2025.6.0b1.dist-info → esphome-2025.6.0b2.dist-info}/entry_points.txt +0 -0
  70. {esphome-2025.6.0b1.dist-info → esphome-2025.6.0b2.dist-info}/licenses/LICENSE +0 -0
  71. {esphome-2025.6.0b1.dist-info → esphome-2025.6.0b2.dist-info}/top_level.txt +0 -0
@@ -8,7 +8,9 @@ static const char *const TAG = "text_sensor";
8
8
 
9
9
  void TextSensor::publish_state(const std::string &state) {
10
10
  this->raw_state = state;
11
- this->raw_callback_.call(state);
11
+ if (this->raw_callback_) {
12
+ this->raw_callback_->call(state);
13
+ }
12
14
 
13
15
  ESP_LOGV(TAG, "'%s': Received new state %s", this->name_.c_str(), state.c_str());
14
16
 
@@ -53,20 +55,22 @@ void TextSensor::add_on_state_callback(std::function<void(std::string)> callback
53
55
  this->callback_.add(std::move(callback));
54
56
  }
55
57
  void TextSensor::add_on_raw_state_callback(std::function<void(std::string)> callback) {
56
- this->raw_callback_.add(std::move(callback));
58
+ if (!this->raw_callback_) {
59
+ this->raw_callback_ = make_unique<CallbackManager<void(std::string)>>();
60
+ }
61
+ this->raw_callback_->add(std::move(callback));
57
62
  }
58
63
 
59
64
  std::string TextSensor::get_state() const { return this->state; }
60
65
  std::string TextSensor::get_raw_state() const { return this->raw_state; }
61
66
  void TextSensor::internal_send_state_to_frontend(const std::string &state) {
62
67
  this->state = state;
63
- this->has_state_ = true;
68
+ this->set_has_state(true);
64
69
  ESP_LOGD(TAG, "'%s': Sending state '%s'", this->name_.c_str(), state.c_str());
65
70
  this->callback_.call(state);
66
71
  }
67
72
 
68
73
  std::string TextSensor::unique_id() { return ""; }
69
- bool TextSensor::has_state() { return this->has_state_; }
70
74
 
71
75
  } // namespace text_sensor
72
76
  } // namespace esphome
@@ -6,6 +6,7 @@
6
6
  #include "esphome/components/text_sensor/filter.h"
7
7
 
8
8
  #include <vector>
9
+ #include <memory>
9
10
 
10
11
  namespace esphome {
11
12
  namespace text_sensor {
@@ -33,6 +34,8 @@ namespace text_sensor {
33
34
 
34
35
  class TextSensor : public EntityBase, public EntityBase_DeviceClass {
35
36
  public:
37
+ TextSensor() = default;
38
+
36
39
  /// Getter-syntax for .state.
37
40
  std::string get_state() const;
38
41
  /// Getter-syntax for .raw_state
@@ -67,17 +70,14 @@ class TextSensor : public EntityBase, public EntityBase_DeviceClass {
67
70
  */
68
71
  virtual std::string unique_id();
69
72
 
70
- bool has_state();
71
-
72
73
  void internal_send_state_to_frontend(const std::string &state);
73
74
 
74
75
  protected:
75
- CallbackManager<void(std::string)> raw_callback_; ///< Storage for raw state callbacks.
76
- CallbackManager<void(std::string)> callback_; ///< Storage for filtered state callbacks.
76
+ std::unique_ptr<CallbackManager<void(std::string)>>
77
+ raw_callback_; ///< Storage for raw state callbacks (lazy allocated).
78
+ CallbackManager<void(std::string)> callback_; ///< Storage for filtered state callbacks.
77
79
 
78
80
  Filter *filter_list_{nullptr}; ///< Store all active filters.
79
-
80
- bool has_state_{false};
81
81
  };
82
82
 
83
83
  } // namespace text_sensor
@@ -30,7 +30,7 @@ void UpdateEntity::publish_state() {
30
30
  ESP_LOGD(TAG, " Progress: %.0f%%", this->update_info_.progress);
31
31
  }
32
32
 
33
- this->has_state_ = true;
33
+ this->set_has_state(true);
34
34
  this->state_callback_.call();
35
35
  }
36
36
 
@@ -28,8 +28,6 @@ enum UpdateState : uint8_t {
28
28
 
29
29
  class UpdateEntity : public EntityBase, public EntityBase_DeviceClass {
30
30
  public:
31
- bool has_state() const { return this->has_state_; }
32
-
33
31
  void publish_state();
34
32
 
35
33
  void perform() { this->perform(false); }
@@ -44,7 +42,6 @@ class UpdateEntity : public EntityBase, public EntityBase_DeviceClass {
44
42
  protected:
45
43
  UpdateState state_{UPDATE_STATE_UNKNOWN};
46
44
  UpdateInfo update_info_;
47
- bool has_state_{false};
48
45
 
49
46
  CallbackManager<void()> state_callback_{};
50
47
  };
@@ -13,7 +13,7 @@ static const char *const TAG = "uptime.sensor";
13
13
 
14
14
  void UptimeTimestampSensor::setup() {
15
15
  this->time_->add_on_time_sync_callback([this]() {
16
- if (this->has_state_)
16
+ if (this->has_state())
17
17
  return; // No need to update the timestamp if it's already set
18
18
 
19
19
  auto now = this->time_->now();
@@ -8,8 +8,6 @@ CONFIG_SCHEMA = cv.All(
8
8
  cv.only_with_esp_idf,
9
9
  )
10
10
 
11
- AUTO_LOAD = ["web_server"]
12
-
13
11
 
14
12
  async def to_code(config):
15
13
  # Increase the maximum supported size of headers section in HTTP request packet to be processed by the server
@@ -9,10 +9,12 @@
9
9
 
10
10
  #include "utils.h"
11
11
 
12
+ #include "web_server_idf.h"
13
+
14
+ #ifdef USE_WEBSERVER
12
15
  #include "esphome/components/web_server/web_server.h"
13
16
  #include "esphome/components/web_server/list_entities.h"
14
-
15
- #include "web_server_idf.h"
17
+ #endif // USE_WEBSERVER
16
18
 
17
19
  namespace esphome {
18
20
  namespace web_server_idf {
@@ -273,6 +275,7 @@ void AsyncResponseStream::printf(const char *fmt, ...) {
273
275
  this->print(str);
274
276
  }
275
277
 
278
+ #ifdef USE_WEBSERVER
276
279
  AsyncEventSource::~AsyncEventSource() {
277
280
  for (auto *ses : this->sessions_) {
278
281
  delete ses; // NOLINT(cppcoreguidelines-owning-memory)
@@ -511,6 +514,7 @@ void AsyncEventSourceResponse::deferrable_send_state(void *source, const char *e
511
514
  }
512
515
  }
513
516
  }
517
+ #endif
514
518
 
515
519
  } // namespace web_server_idf
516
520
  } // namespace esphome
@@ -1,6 +1,7 @@
1
1
  #pragma once
2
2
  #ifdef USE_ESP_IDF
3
3
 
4
+ #include "esphome/core/defines.h"
4
5
  #include <esp_http_server.h>
5
6
 
6
7
  #include <functional>
@@ -12,10 +13,12 @@
12
13
  #include <vector>
13
14
 
14
15
  namespace esphome {
16
+ #ifdef USE_WEBSERVER
15
17
  namespace web_server {
16
18
  class WebServer;
17
19
  class ListEntitiesIterator;
18
20
  }; // namespace web_server
21
+ #endif
19
22
  namespace web_server_idf {
20
23
 
21
24
  #define F(string_literal) (string_literal)
@@ -220,6 +223,7 @@ class AsyncWebHandler {
220
223
  virtual bool isRequestHandlerTrivial() { return true; }
221
224
  };
222
225
 
226
+ #ifdef USE_WEBSERVER
223
227
  class AsyncEventSource;
224
228
  class AsyncEventSourceResponse;
225
229
 
@@ -307,10 +311,13 @@ class AsyncEventSource : public AsyncWebHandler {
307
311
  connect_handler_t on_connect_{};
308
312
  esphome::web_server::WebServer *web_server_;
309
313
  };
314
+ #endif // USE_WEBSERVER
310
315
 
311
316
  class DefaultHeaders {
312
317
  friend class AsyncWebServerRequest;
318
+ #ifdef USE_WEBSERVER
313
319
  friend class AsyncEventSourceResponse;
320
+ #endif
314
321
 
315
322
  public:
316
323
  // NOLINTNEXTLINE(readability-identifier-naming)
@@ -102,7 +102,7 @@ WeikaiRegister &WeikaiRegister::operator|=(uint8_t value) {
102
102
  // The WeikaiComponent methods
103
103
  ///////////////////////////////////////////////////////////////////////////////
104
104
  void WeikaiComponent::loop() {
105
- if ((this->component_state_ & COMPONENT_STATE_MASK) != COMPONENT_STATE_LOOP)
105
+ if (!this->is_in_loop_state())
106
106
  return;
107
107
 
108
108
  // If there are some bytes in the receive FIFO we transfers them to the ring buffers
esphome/const.py CHANGED
@@ -1,6 +1,6 @@
1
1
  """Constants used by esphome."""
2
2
 
3
- __version__ = "2025.6.0b1"
3
+ __version__ = "2025.6.0b2"
4
4
 
5
5
  ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
6
6
  VALID_SUBSTITUTIONS_CHARACTERS = (
@@ -66,7 +66,7 @@ void Application::setup() {
66
66
  [](Component *a, Component *b) { return a->get_loop_priority() > b->get_loop_priority(); });
67
67
 
68
68
  do {
69
- uint32_t new_app_state = STATUS_LED_WARNING;
69
+ uint8_t new_app_state = STATUS_LED_WARNING;
70
70
  this->scheduler.call();
71
71
  this->feed_wdt();
72
72
  for (uint32_t j = 0; j <= i; j++) {
@@ -87,7 +87,7 @@ void Application::setup() {
87
87
  this->calculate_looping_components_();
88
88
  }
89
89
  void Application::loop() {
90
- uint32_t new_app_state = 0;
90
+ uint8_t new_app_state = 0;
91
91
 
92
92
  this->scheduler.call();
93
93
 
@@ -117,7 +117,9 @@ void Application::loop() {
117
117
  // Use the last component's end time instead of calling millis() again
118
118
  auto elapsed = last_op_end_time - this->last_loop_;
119
119
  if (elapsed >= this->loop_interval_ || HighFrequencyLoopRequester::is_high_frequency()) {
120
- yield();
120
+ // Even if we overran the loop interval, we still need to select()
121
+ // to know if any sockets have data ready
122
+ this->yield_with_select_(0);
121
123
  } else {
122
124
  uint32_t delay_time = this->loop_interval_ - elapsed;
123
125
  uint32_t next_schedule = this->scheduler.next_schedule_in().value_or(delay_time);
@@ -126,7 +128,7 @@ void Application::loop() {
126
128
  next_schedule = std::max(next_schedule, delay_time / 2);
127
129
  delay_time = std::min(next_schedule, delay_time);
128
130
 
129
- this->delay_with_select_(delay_time);
131
+ this->yield_with_select_(delay_time);
130
132
  }
131
133
  this->last_loop_ = last_op_end_time;
132
134
 
@@ -215,7 +217,7 @@ void Application::teardown_components(uint32_t timeout_ms) {
215
217
 
216
218
  // Give some time for I/O operations if components are still pending
217
219
  if (!pending_components.empty()) {
218
- this->delay_with_select_(1);
220
+ this->yield_with_select_(1);
219
221
  }
220
222
 
221
223
  // Update time for next iteration
@@ -293,8 +295,6 @@ bool Application::is_socket_ready(int fd) const {
293
295
  // This function is thread-safe for reading the result of select()
294
296
  // However, it should only be called after select() has been executed in the main loop
295
297
  // The read_fds_ is only modified by select() in the main loop
296
- if (HighFrequencyLoopRequester::is_high_frequency())
297
- return true; // fd sets via select are not updated in high frequency looping - so force true fallback behavior
298
298
  if (fd < 0 || fd >= FD_SETSIZE)
299
299
  return false;
300
300
 
@@ -302,7 +302,9 @@ bool Application::is_socket_ready(int fd) const {
302
302
  }
303
303
  #endif
304
304
 
305
- void Application::delay_with_select_(uint32_t delay_ms) {
305
+ void Application::yield_with_select_(uint32_t delay_ms) {
306
+ // Delay while monitoring sockets. When delay_ms is 0, always yield() to ensure other tasks run
307
+ // since select() with 0 timeout only polls without yielding.
306
308
  #ifdef USE_SOCKET_SELECT_SUPPORT
307
309
  if (!this->socket_fds_.empty()) {
308
310
  // Update fd_set if socket list has changed
@@ -340,6 +342,10 @@ void Application::delay_with_select_(uint32_t delay_ms) {
340
342
  ESP_LOGW(TAG, "select() failed with errno %d", errno);
341
343
  delay(delay_ms);
342
344
  }
345
+ // When delay_ms is 0, we need to yield since select(0) doesn't yield
346
+ if (delay_ms == 0) {
347
+ yield();
348
+ }
343
349
  } else {
344
350
  // No sockets registered, use regular delay
345
351
  delay(delay_ms);
@@ -87,8 +87,8 @@ static const uint32_t TEARDOWN_TIMEOUT_REBOOT_MS = 1000; // 1 second for quick
87
87
 
88
88
  class Application {
89
89
  public:
90
- void pre_setup(const std::string &name, const std::string &friendly_name, const std::string &area,
91
- const char *comment, const char *compilation_time, bool name_add_mac_suffix) {
90
+ void pre_setup(const std::string &name, const std::string &friendly_name, const char *area, const char *comment,
91
+ const char *compilation_time, bool name_add_mac_suffix) {
92
92
  arch_init();
93
93
  this->name_add_mac_suffix_ = name_add_mac_suffix;
94
94
  if (name_add_mac_suffix) {
@@ -285,7 +285,7 @@ class Application {
285
285
  const std::string &get_friendly_name() const { return this->friendly_name_; }
286
286
 
287
287
  /// Get the area of this Application set by pre_setup().
288
- const std::string &get_area() const { return this->area_; }
288
+ std::string get_area() const { return this->area_ == nullptr ? "" : this->area_; }
289
289
 
290
290
  /// Get the comment of this Application set by pre_setup().
291
291
  std::string get_comment() const { return this->comment_; }
@@ -332,7 +332,7 @@ class Application {
332
332
  */
333
333
  void teardown_components(uint32_t timeout_ms);
334
334
 
335
- uint32_t get_app_state() const { return this->app_state_; }
335
+ uint8_t get_app_state() const { return this->app_state_; }
336
336
 
337
337
  #ifdef USE_BINARY_SENSOR
338
338
  const std::vector<binary_sensor::BinarySensor *> &get_binary_sensors() { return this->binary_sensors_; }
@@ -575,7 +575,7 @@ class Application {
575
575
  void feed_wdt_arch_();
576
576
 
577
577
  /// Perform a delay while also monitoring socket file descriptors for readiness
578
- void delay_with_select_(uint32_t delay_ms);
578
+ void yield_with_select_(uint32_t delay_ms);
579
579
 
580
580
  std::vector<Component *> components_{};
581
581
  std::vector<Component *> looping_components_{};
@@ -646,14 +646,14 @@ class Application {
646
646
 
647
647
  std::string name_;
648
648
  std::string friendly_name_;
649
- std::string area_;
649
+ const char *area_{nullptr};
650
650
  const char *comment_{nullptr};
651
651
  const char *compilation_time_{nullptr};
652
652
  bool name_add_mac_suffix_;
653
653
  uint32_t last_loop_{0};
654
654
  uint32_t loop_interval_{16};
655
655
  size_t dump_config_at_{SIZE_MAX};
656
- uint32_t app_state_{0};
656
+ uint8_t app_state_{0};
657
657
  Component *current_component_{nullptr};
658
658
  uint32_t loop_component_start_time_{0};
659
659
 
@@ -1,6 +1,7 @@
1
1
  #include "esphome/core/component.h"
2
2
 
3
3
  #include <cinttypes>
4
+ #include <limits>
4
5
  #include <utility>
5
6
  #include "esphome/core/application.h"
6
7
  #include "esphome/core/hal.h"
@@ -29,18 +30,20 @@ const float LATE = -100.0f;
29
30
 
30
31
  } // namespace setup_priority
31
32
 
32
- const uint32_t COMPONENT_STATE_MASK = 0xFF;
33
- const uint32_t COMPONENT_STATE_CONSTRUCTION = 0x00;
34
- const uint32_t COMPONENT_STATE_SETUP = 0x01;
35
- const uint32_t COMPONENT_STATE_LOOP = 0x02;
36
- const uint32_t COMPONENT_STATE_FAILED = 0x03;
37
- const uint32_t STATUS_LED_MASK = 0xFF00;
38
- const uint32_t STATUS_LED_OK = 0x0000;
39
- const uint32_t STATUS_LED_WARNING = 0x0100;
40
- const uint32_t STATUS_LED_ERROR = 0x0200;
41
-
42
- const uint32_t WARN_IF_BLOCKING_OVER_MS = 50U; ///< Initial blocking time allowed without warning
43
- const uint32_t WARN_IF_BLOCKING_INCREMENT_MS = 10U; ///< How long the blocking time must be larger to warn again
33
+ // Component state uses bits 0-1 (4 states)
34
+ const uint8_t COMPONENT_STATE_MASK = 0x03;
35
+ const uint8_t COMPONENT_STATE_CONSTRUCTION = 0x00;
36
+ const uint8_t COMPONENT_STATE_SETUP = 0x01;
37
+ const uint8_t COMPONENT_STATE_LOOP = 0x02;
38
+ const uint8_t COMPONENT_STATE_FAILED = 0x03;
39
+ // Status LED uses bits 2-3
40
+ const uint8_t STATUS_LED_MASK = 0x0C;
41
+ const uint8_t STATUS_LED_OK = 0x00;
42
+ const uint8_t STATUS_LED_WARNING = 0x04; // Bit 2
43
+ const uint8_t STATUS_LED_ERROR = 0x08; // Bit 3
44
+
45
+ const uint16_t WARN_IF_BLOCKING_OVER_MS = 50U; ///< Initial blocking time allowed without warning
46
+ const uint16_t WARN_IF_BLOCKING_INCREMENT_MS = 10U; ///< How long the blocking time must be larger to warn again
44
47
 
45
48
  uint32_t global_state = 0; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
46
49
 
@@ -86,9 +89,9 @@ void Component::call_dump_config() {
86
89
  }
87
90
  }
88
91
 
89
- uint32_t Component::get_component_state() const { return this->component_state_; }
92
+ uint8_t Component::get_component_state() const { return this->component_state_; }
90
93
  void Component::call() {
91
- uint32_t state = this->component_state_ & COMPONENT_STATE_MASK;
94
+ uint8_t state = this->component_state_ & COMPONENT_STATE_MASK;
92
95
  switch (state) {
93
96
  case COMPONENT_STATE_CONSTRUCTION:
94
97
  // State Construction: Call setup and set state to setup
@@ -120,7 +123,13 @@ const char *Component::get_component_source() const {
120
123
  }
121
124
  bool Component::should_warn_of_blocking(uint32_t blocking_time) {
122
125
  if (blocking_time > this->warn_if_blocking_over_) {
123
- this->warn_if_blocking_over_ = blocking_time + WARN_IF_BLOCKING_INCREMENT_MS;
126
+ // Prevent overflow when adding increment - if we're about to overflow, just max out
127
+ if (blocking_time + WARN_IF_BLOCKING_INCREMENT_MS < blocking_time ||
128
+ blocking_time + WARN_IF_BLOCKING_INCREMENT_MS > std::numeric_limits<uint16_t>::max()) {
129
+ this->warn_if_blocking_over_ = std::numeric_limits<uint16_t>::max();
130
+ } else {
131
+ this->warn_if_blocking_over_ = static_cast<uint16_t>(blocking_time + WARN_IF_BLOCKING_INCREMENT_MS);
132
+ }
124
133
  return true;
125
134
  }
126
135
  return false;
@@ -131,6 +140,18 @@ void Component::mark_failed() {
131
140
  this->component_state_ |= COMPONENT_STATE_FAILED;
132
141
  this->status_set_error();
133
142
  }
143
+ void Component::reset_to_construction_state() {
144
+ if ((this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_FAILED) {
145
+ ESP_LOGI(TAG, "Component %s is being reset to construction state.", this->get_component_source());
146
+ this->component_state_ &= ~COMPONENT_STATE_MASK;
147
+ this->component_state_ |= COMPONENT_STATE_CONSTRUCTION;
148
+ // Clear error status when resetting
149
+ this->status_clear_error();
150
+ }
151
+ }
152
+ bool Component::is_in_loop_state() const {
153
+ return (this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_LOOP;
154
+ }
134
155
  void Component::defer(std::function<void()> &&f) { // NOLINT
135
156
  App.scheduler.set_timeout(this, "", 0, std::move(f));
136
157
  }
esphome/core/component.h CHANGED
@@ -53,19 +53,19 @@ static const uint32_t SCHEDULER_DONT_RUN = 4294967295UL;
53
53
  ESP_LOGCONFIG(TAG, " Update Interval: %.1fs", this->get_update_interval() / 1000.0f); \
54
54
  }
55
55
 
56
- extern const uint32_t COMPONENT_STATE_MASK;
57
- extern const uint32_t COMPONENT_STATE_CONSTRUCTION;
58
- extern const uint32_t COMPONENT_STATE_SETUP;
59
- extern const uint32_t COMPONENT_STATE_LOOP;
60
- extern const uint32_t COMPONENT_STATE_FAILED;
61
- extern const uint32_t STATUS_LED_MASK;
62
- extern const uint32_t STATUS_LED_OK;
63
- extern const uint32_t STATUS_LED_WARNING;
64
- extern const uint32_t STATUS_LED_ERROR;
56
+ extern const uint8_t COMPONENT_STATE_MASK;
57
+ extern const uint8_t COMPONENT_STATE_CONSTRUCTION;
58
+ extern const uint8_t COMPONENT_STATE_SETUP;
59
+ extern const uint8_t COMPONENT_STATE_LOOP;
60
+ extern const uint8_t COMPONENT_STATE_FAILED;
61
+ extern const uint8_t STATUS_LED_MASK;
62
+ extern const uint8_t STATUS_LED_OK;
63
+ extern const uint8_t STATUS_LED_WARNING;
64
+ extern const uint8_t STATUS_LED_ERROR;
65
65
 
66
66
  enum class RetryResult { DONE, RETRY };
67
67
 
68
- extern const uint32_t WARN_IF_BLOCKING_OVER_MS;
68
+ extern const uint16_t WARN_IF_BLOCKING_OVER_MS;
69
69
 
70
70
  class Component {
71
71
  public:
@@ -123,7 +123,19 @@ class Component {
123
123
  */
124
124
  virtual void on_powerdown() {}
125
125
 
126
- uint32_t get_component_state() const;
126
+ uint8_t get_component_state() const;
127
+
128
+ /** Reset this component back to the construction state to allow setup to run again.
129
+ *
130
+ * This can be used by components that have recoverable failures to attempt setup again.
131
+ */
132
+ void reset_to_construction_state();
133
+
134
+ /** Check if this component has completed setup and is in the loop state.
135
+ *
136
+ * @return True if in loop state, false otherwise.
137
+ */
138
+ bool is_in_loop_state() const;
127
139
 
128
140
  /** Mark this component as failed. Any future timeouts/intervals/setup/loop will no longer be called.
129
141
  *
@@ -298,10 +310,15 @@ class Component {
298
310
  /// Cancel a defer callback using the specified name, name must not be empty.
299
311
  bool cancel_defer(const std::string &name); // NOLINT
300
312
 
301
- uint32_t component_state_{0x0000}; ///< State of this component.
313
+ /// State of this component - each bit has a purpose:
314
+ /// Bits 0-1: Component state (0x00=CONSTRUCTION, 0x01=SETUP, 0x02=LOOP, 0x03=FAILED)
315
+ /// Bit 2: STATUS_LED_WARNING
316
+ /// Bit 3: STATUS_LED_ERROR
317
+ /// Bits 4-7: Unused - reserved for future expansion (50% of the bits are free)
318
+ uint8_t component_state_{0x00};
302
319
  float setup_priority_override_{NAN};
303
320
  const char *component_source_{nullptr};
304
- uint32_t warn_if_blocking_over_{WARN_IF_BLOCKING_OVER_MS};
321
+ uint16_t warn_if_blocking_over_{WARN_IF_BLOCKING_OVER_MS}; ///< Warn if blocked for this many ms (max 65.5s)
305
322
  std::string error_message_{};
306
323
  };
307
324
 
@@ -12,20 +12,12 @@ void EntityBase::set_name(const char *name) {
12
12
  this->name_ = StringRef(name);
13
13
  if (this->name_.empty()) {
14
14
  this->name_ = StringRef(App.get_friendly_name());
15
- this->has_own_name_ = false;
15
+ this->flags_.has_own_name = false;
16
16
  } else {
17
- this->has_own_name_ = true;
17
+ this->flags_.has_own_name = true;
18
18
  }
19
19
  }
20
20
 
21
- // Entity Internal
22
- bool EntityBase::is_internal() const { return this->internal_; }
23
- void EntityBase::set_internal(bool internal) { this->internal_ = internal; }
24
-
25
- // Entity Disabled by Default
26
- bool EntityBase::is_disabled_by_default() const { return this->disabled_by_default_; }
27
- void EntityBase::set_disabled_by_default(bool disabled_by_default) { this->disabled_by_default_ = disabled_by_default; }
28
-
29
21
  // Entity Icon
30
22
  std::string EntityBase::get_icon() const {
31
23
  if (this->icon_c_str_ == nullptr) {
@@ -35,14 +27,10 @@ std::string EntityBase::get_icon() const {
35
27
  }
36
28
  void EntityBase::set_icon(const char *icon) { this->icon_c_str_ = icon; }
37
29
 
38
- // Entity Category
39
- EntityCategory EntityBase::get_entity_category() const { return this->entity_category_; }
40
- void EntityBase::set_entity_category(EntityCategory entity_category) { this->entity_category_ = entity_category; }
41
-
42
30
  // Entity Object ID
43
31
  std::string EntityBase::get_object_id() const {
44
32
  // Check if `App.get_friendly_name()` is constant or dynamic.
45
- if (!this->has_own_name_ && App.is_name_add_mac_suffix_enabled()) {
33
+ if (!this->flags_.has_own_name && App.is_name_add_mac_suffix_enabled()) {
46
34
  // `App.get_friendly_name()` is dynamic.
47
35
  return str_sanitize(str_snake_case(App.get_friendly_name()));
48
36
  } else {
@@ -61,7 +49,7 @@ void EntityBase::set_object_id(const char *object_id) {
61
49
  // Calculate Object ID Hash from Entity Name
62
50
  void EntityBase::calc_object_id_() {
63
51
  // Check if `App.get_friendly_name()` is constant or dynamic.
64
- if (!this->has_own_name_ && App.is_name_add_mac_suffix_enabled()) {
52
+ if (!this->flags_.has_own_name && App.is_name_add_mac_suffix_enabled()) {
65
53
  // `App.get_friendly_name()` is dynamic.
66
54
  const auto object_id = str_sanitize(str_snake_case(App.get_friendly_name()));
67
55
  // FNV-1 hash
@@ -20,7 +20,7 @@ class EntityBase {
20
20
  void set_name(const char *name);
21
21
 
22
22
  // Get whether this Entity has its own name or it should use the device friendly_name.
23
- bool has_own_name() const { return this->has_own_name_; }
23
+ bool has_own_name() const { return this->flags_.has_own_name; }
24
24
 
25
25
  // Get the sanitized name of this Entity as an ID.
26
26
  std::string get_object_id() const;
@@ -29,24 +29,32 @@ class EntityBase {
29
29
  // Get the unique Object ID of this Entity
30
30
  uint32_t get_object_id_hash();
31
31
 
32
- // Get/set whether this Entity should be hidden from outside of ESPHome
33
- bool is_internal() const;
34
- void set_internal(bool internal);
32
+ // Get/set whether this Entity should be hidden outside ESPHome
33
+ bool is_internal() const { return this->flags_.internal; }
34
+ void set_internal(bool internal) { this->flags_.internal = internal; }
35
35
 
36
36
  // Check if this object is declared to be disabled by default.
37
37
  // That means that when the device gets added to Home Assistant (or other clients) it should
38
38
  // not be added to the default view by default, and a user action is necessary to manually add it.
39
- bool is_disabled_by_default() const;
40
- void set_disabled_by_default(bool disabled_by_default);
39
+ bool is_disabled_by_default() const { return this->flags_.disabled_by_default; }
40
+ void set_disabled_by_default(bool disabled_by_default) { this->flags_.disabled_by_default = disabled_by_default; }
41
41
 
42
42
  // Get/set the entity category.
43
- EntityCategory get_entity_category() const;
44
- void set_entity_category(EntityCategory entity_category);
43
+ EntityCategory get_entity_category() const { return static_cast<EntityCategory>(this->flags_.entity_category); }
44
+ void set_entity_category(EntityCategory entity_category) {
45
+ this->flags_.entity_category = static_cast<uint8_t>(entity_category);
46
+ }
45
47
 
46
48
  // Get/set this entity's icon
47
49
  std::string get_icon() const;
48
50
  void set_icon(const char *icon);
49
51
 
52
+ // Check if this entity has state
53
+ bool has_state() const { return this->flags_.has_state; }
54
+
55
+ // Set has_state - for components that need to manually set this
56
+ void set_has_state(bool state) { this->flags_.has_state = state; }
57
+
50
58
  protected:
51
59
  /// The hash_base() function has been deprecated. It is kept in this
52
60
  /// class for now, to prevent external components from not compiling.
@@ -56,11 +64,17 @@ class EntityBase {
56
64
  StringRef name_;
57
65
  const char *object_id_c_str_{nullptr};
58
66
  const char *icon_c_str_{nullptr};
59
- uint32_t object_id_hash_;
60
- bool has_own_name_{false};
61
- bool internal_{false};
62
- bool disabled_by_default_{false};
63
- EntityCategory entity_category_{ENTITY_CATEGORY_NONE};
67
+ uint32_t object_id_hash_{};
68
+
69
+ // Bit-packed flags to save memory (1 byte instead of 5)
70
+ struct EntityFlags {
71
+ uint8_t has_own_name : 1;
72
+ uint8_t internal : 1;
73
+ uint8_t disabled_by_default : 1;
74
+ uint8_t has_state : 1;
75
+ uint8_t entity_category : 2; // Supports up to 4 categories
76
+ uint8_t reserved : 2; // Reserved for future use
77
+ } flags_{};
64
78
  };
65
79
 
66
80
  class EntityBase_DeviceClass { // NOLINT(readability-identifier-naming)
esphome/core/helpers.h CHANGED
@@ -438,7 +438,7 @@ template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0> std::stri
438
438
  }
439
439
 
440
440
  /// Return values for parse_on_off().
441
- enum ParseOnOffState {
441
+ enum ParseOnOffState : uint8_t {
442
442
  PARSE_NONE = 0,
443
443
  PARSE_ON,
444
444
  PARSE_OFF,
esphome/wizard.py CHANGED
@@ -67,20 +67,6 @@ esp8266:
67
67
  """
68
68
 
69
69
  ESP32_CONFIG = """
70
- esp32:
71
- board: {board}
72
- framework:
73
- type: arduino
74
- """
75
-
76
- ESP32S2_CONFIG = """
77
- esp32:
78
- board: {board}
79
- framework:
80
- type: esp-idf
81
- """
82
-
83
- ESP32C3_CONFIG = """
84
70
  esp32:
85
71
  board: {board}
86
72
  framework:
@@ -105,8 +91,6 @@ rtl87xx:
105
91
  HARDWARE_BASE_CONFIGS = {
106
92
  "ESP8266": ESP8266_CONFIG,
107
93
  "ESP32": ESP32_CONFIG,
108
- "ESP32S2": ESP32S2_CONFIG,
109
- "ESP32C3": ESP32C3_CONFIG,
110
94
  "RP2040": RP2040_CONFIG,
111
95
  "BK72XX": BK72XX_CONFIG,
112
96
  "RTL87XX": RTL87XX_CONFIG,