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.
- esphome/components/api/api_connection.cpp +53 -33
- esphome/components/api/api_connection.h +24 -25
- esphome/components/api/api_pb2.cpp +1 -0
- esphome/components/api/api_pb2.h +65 -226
- esphome/components/api/client.py +1 -3
- esphome/components/api/proto.h +1 -1
- esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +2 -2
- esphome/components/bluetooth_proxy/bluetooth_proxy.h +1 -1
- esphome/components/bme280_base/bme280_base.cpp +2 -3
- esphome/components/datetime/date_entity.cpp +5 -5
- esphome/components/datetime/datetime_base.h +0 -5
- esphome/components/datetime/datetime_entity.cpp +8 -8
- esphome/components/datetime/time_entity.cpp +4 -4
- esphome/components/esp32/__init__.py +30 -3
- esphome/components/esp32_ble/ble.cpp +90 -45
- esphome/components/esp32_ble/ble.h +24 -5
- esphome/components/esp32_ble/ble_event.h +172 -32
- esphome/components/esp32_ble/ble_scan_result.h +24 -0
- esphome/components/esp32_ble/queue.h +53 -27
- esphome/components/esp32_ble_tracker/__init__.py +1 -0
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +95 -66
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +16 -16
- esphome/components/esp32_camera/esp32_camera.cpp +1 -1
- esphome/components/fan/fan.cpp +26 -17
- esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +12 -9
- esphome/components/kmeteriso/kmeteriso.cpp +2 -3
- esphome/components/logger/logger.cpp +2 -15
- esphome/components/logger/logger.h +1 -2
- esphome/components/mqtt/mqtt_component.cpp +1 -1
- esphome/components/nextion/binary_sensor/nextion_binarysensor.cpp +1 -1
- esphome/components/nextion/nextion_upload_arduino.cpp +12 -9
- esphome/components/nextion/nextion_upload_idf.cpp +11 -9
- esphome/components/nextion/sensor/nextion_sensor.cpp +1 -1
- esphome/components/nextion/text_sensor/nextion_textsensor.cpp +1 -1
- esphome/components/number/number.cpp +1 -1
- esphome/components/number/number.h +0 -4
- esphome/components/prometheus/__init__.py +0 -1
- esphome/components/select/select.cpp +1 -1
- esphome/components/select/select.h +0 -4
- esphome/components/sensor/sensor.cpp +8 -4
- esphome/components/sensor/sensor.h +3 -6
- esphome/components/status_led/light/status_led_light.cpp +2 -2
- esphome/components/status_led/light/status_led_light.h +1 -1
- esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp +14 -9
- esphome/components/template/alarm_control_panel/template_alarm_control_panel.h +1 -0
- esphome/components/text/text.cpp +1 -1
- esphome/components/text/text.h +0 -4
- esphome/components/text_sensor/text_sensor.cpp +8 -4
- esphome/components/text_sensor/text_sensor.h +6 -6
- esphome/components/update/update_entity.cpp +1 -1
- esphome/components/update/update_entity.h +0 -3
- esphome/components/uptime/sensor/uptime_timestamp_sensor.cpp +1 -1
- esphome/components/web_server_idf/__init__.py +0 -2
- esphome/components/web_server_idf/web_server_idf.cpp +6 -2
- esphome/components/web_server_idf/web_server_idf.h +7 -0
- esphome/components/weikai/weikai.cpp +1 -1
- esphome/const.py +1 -1
- esphome/core/application.cpp +14 -8
- esphome/core/application.h +7 -7
- esphome/core/component.cpp +36 -15
- esphome/core/component.h +30 -13
- esphome/core/entity_base.cpp +4 -16
- esphome/core/entity_base.h +27 -13
- esphome/core/helpers.h +1 -1
- esphome/wizard.py +0 -16
- {esphome-2025.6.0b1.dist-info → esphome-2025.6.0b2.dist-info}/METADATA +2 -2
- {esphome-2025.6.0b1.dist-info → esphome-2025.6.0b2.dist-info}/RECORD +71 -70
- {esphome-2025.6.0b1.dist-info → esphome-2025.6.0b2.dist-info}/WHEEL +0 -0
- {esphome-2025.6.0b1.dist-info → esphome-2025.6.0b2.dist-info}/entry_points.txt +0 -0
- {esphome-2025.6.0b1.dist-info → esphome-2025.6.0b2.dist-info}/licenses/LICENSE +0 -0
- {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_
|
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_
|
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->
|
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)
|
76
|
-
|
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
|
@@ -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->
|
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();
|
@@ -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 (
|
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
esphome/core/application.cpp
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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->
|
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->
|
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::
|
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);
|
esphome/core/application.h
CHANGED
@@ -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
|
91
|
-
const char *
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
656
|
+
uint8_t app_state_{0};
|
657
657
|
Component *current_component_{nullptr};
|
658
658
|
uint32_t loop_component_start_time_{0};
|
659
659
|
|
esphome/core/component.cpp
CHANGED
@@ -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
|
-
|
33
|
-
const
|
34
|
-
const
|
35
|
-
const
|
36
|
-
const
|
37
|
-
const
|
38
|
-
|
39
|
-
const
|
40
|
-
const
|
41
|
-
|
42
|
-
const
|
43
|
-
|
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
|
-
|
92
|
+
uint8_t Component::get_component_state() const { return this->component_state_; }
|
90
93
|
void Component::call() {
|
91
|
-
|
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
|
-
|
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
|
57
|
-
extern const
|
58
|
-
extern const
|
59
|
-
extern const
|
60
|
-
extern const
|
61
|
-
extern const
|
62
|
-
extern const
|
63
|
-
extern const
|
64
|
-
extern const
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
|
esphome/core/entity_base.cpp
CHANGED
@@ -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->
|
15
|
+
this->flags_.has_own_name = false;
|
16
16
|
} else {
|
17
|
-
this->
|
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->
|
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->
|
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
|
esphome/core/entity_base.h
CHANGED
@@ -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->
|
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
|
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
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
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
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,
|