esphome 2025.6.0b1__py3-none-any.whl → 2025.6.0b3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/i2s_audio.cpp +1 -1
- esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +47 -29
- esphome/components/i2s_audio/microphone/i2s_audio_microphone.h +2 -0
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +28 -10
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +1 -0
- esphome/components/kmeteriso/kmeteriso.cpp +2 -3
- esphome/components/light/light_state.h +15 -15
- 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/spi/spi_arduino.cpp +22 -9
- esphome/components/status_led/light/status_led_light.cpp +2 -2
- esphome/components/status_led/light/status_led_light.h +1 -1
- esphome/components/switch/switch.h +13 -7
- 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.0b3.dist-info}/METADATA +2 -2
- {esphome-2025.6.0b1.dist-info → esphome-2025.6.0b3.dist-info}/RECORD +78 -77
- {esphome-2025.6.0b1.dist-info → esphome-2025.6.0b3.dist-info}/WHEEL +0 -0
- {esphome-2025.6.0b1.dist-info → esphome-2025.6.0b3.dist-info}/entry_points.txt +0 -0
- {esphome-2025.6.0b1.dist-info → esphome-2025.6.0b3.dist-info}/licenses/LICENSE +0 -0
- {esphome-2025.6.0b1.dist-info → esphome-2025.6.0b3.dist-info}/top_level.txt +0 -0
@@ -6,6 +6,7 @@
|
|
6
6
|
#include "esphome/core/helpers.h"
|
7
7
|
|
8
8
|
#include <array>
|
9
|
+
#include <atomic>
|
9
10
|
#include <string>
|
10
11
|
#include <vector>
|
11
12
|
|
@@ -62,7 +63,7 @@ class ESPBLEiBeacon {
|
|
62
63
|
|
63
64
|
class ESPBTDevice {
|
64
65
|
public:
|
65
|
-
void parse_scan_rst(const
|
66
|
+
void parse_scan_rst(const BLEScanResult &scan_result);
|
66
67
|
|
67
68
|
std::string address_str() const;
|
68
69
|
|
@@ -84,8 +85,6 @@ class ESPBTDevice {
|
|
84
85
|
|
85
86
|
const std::vector<ServiceData> &get_service_datas() const { return service_datas_; }
|
86
87
|
|
87
|
-
const esp_ble_gap_cb_param_t::ble_scan_result_evt_param &get_scan_result() const { return scan_result_; }
|
88
|
-
|
89
88
|
bool resolve_irk(const uint8_t *irk) const;
|
90
89
|
|
91
90
|
optional<ESPBLEiBeacon> get_ibeacon() const {
|
@@ -98,7 +97,7 @@ class ESPBTDevice {
|
|
98
97
|
}
|
99
98
|
|
100
99
|
protected:
|
101
|
-
void parse_adv_(const
|
100
|
+
void parse_adv_(const uint8_t *payload, uint8_t len);
|
102
101
|
|
103
102
|
esp_bd_addr_t address_{
|
104
103
|
0,
|
@@ -112,7 +111,6 @@ class ESPBTDevice {
|
|
112
111
|
std::vector<ESPBTUUID> service_uuids_{};
|
113
112
|
std::vector<ServiceData> manufacturer_datas_{};
|
114
113
|
std::vector<ServiceData> service_datas_{};
|
115
|
-
esp_ble_gap_cb_param_t::ble_scan_result_evt_param scan_result_{};
|
116
114
|
};
|
117
115
|
|
118
116
|
class ESP32BLETracker;
|
@@ -121,9 +119,7 @@ class ESPBTDeviceListener {
|
|
121
119
|
public:
|
122
120
|
virtual void on_scan_end() {}
|
123
121
|
virtual bool parse_device(const ESPBTDevice &device) = 0;
|
124
|
-
virtual bool parse_devices(
|
125
|
-
return false;
|
126
|
-
};
|
122
|
+
virtual bool parse_devices(const BLEScanResult *scan_results, size_t count) { return false; };
|
127
123
|
virtual AdvertisementParserType get_advertisement_parser_type() {
|
128
124
|
return AdvertisementParserType::PARSED_ADVERTISEMENTS;
|
129
125
|
};
|
@@ -210,6 +206,7 @@ class ESPBTClient : public ESPBTDeviceListener {
|
|
210
206
|
|
211
207
|
class ESP32BLETracker : public Component,
|
212
208
|
public GAPEventHandler,
|
209
|
+
public GAPScanEventHandler,
|
213
210
|
public GATTcEventHandler,
|
214
211
|
public BLEStatusEventHandler,
|
215
212
|
public Parented<ESP32BLE> {
|
@@ -240,6 +237,7 @@ class ESP32BLETracker : public Component,
|
|
240
237
|
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
|
241
238
|
esp_ble_gattc_cb_param_t *param) override;
|
242
239
|
void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) override;
|
240
|
+
void gap_scan_event_handler(const BLEScanResult &scan_result) override;
|
243
241
|
void ble_before_disabled_event_handler() override;
|
244
242
|
|
245
243
|
void add_scanner_state_callback(std::function<void(ScannerState)> &&callback) {
|
@@ -285,14 +283,16 @@ class ESP32BLETracker : public Component,
|
|
285
283
|
bool ble_was_disabled_{true};
|
286
284
|
bool raw_advertisements_{false};
|
287
285
|
bool parse_advertisements_{false};
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
286
|
+
|
287
|
+
// Lock-free Single-Producer Single-Consumer (SPSC) ring buffer for scan results
|
288
|
+
// Producer: ESP-IDF Bluetooth stack callback (gap_scan_event_handler)
|
289
|
+
// Consumer: ESPHome main loop (loop() method)
|
290
|
+
// This design ensures zero blocking in the BT callback and prevents scan result loss
|
291
|
+
BLEScanResult *scan_ring_buffer_;
|
292
|
+
std::atomic<size_t> ring_write_index_{0}; // Written only by BT callback (producer)
|
293
|
+
std::atomic<size_t> ring_read_index_{0}; // Written only by main loop (consumer)
|
294
|
+
std::atomic<size_t> scan_results_dropped_{0}; // Tracks buffer overflow events
|
295
|
+
|
296
296
|
esp_bt_status_t scan_start_failed_{ESP_BT_STATUS_SUCCESS};
|
297
297
|
esp_bt_status_t scan_set_param_failed_{ESP_BT_STATUS_SUCCESS};
|
298
298
|
int connecting_{0};
|
@@ -57,7 +57,7 @@ void ESP32Camera::dump_config() {
|
|
57
57
|
" External Clock: Pin:%d Frequency:%u\n"
|
58
58
|
" I2C Pins: SDA:%d SCL:%d\n"
|
59
59
|
" Reset Pin: %d",
|
60
|
-
this->name_.c_str(), YESNO(this->
|
60
|
+
this->name_.c_str(), YESNO(this->is_internal()), conf.pin_d0, conf.pin_d1, conf.pin_d2, conf.pin_d3,
|
61
61
|
conf.pin_d4, conf.pin_d5, conf.pin_d6, conf.pin_d7, conf.pin_vsync, conf.pin_href, conf.pin_pclk,
|
62
62
|
conf.pin_xclk, conf.xclk_freq_hz, conf.pin_sccb_sda, conf.pin_sccb_scl, conf.pin_reset);
|
63
63
|
switch (this->config_.frame_size) {
|
esphome/components/fan/fan.cpp
CHANGED
@@ -41,39 +41,48 @@ void FanCall::perform() {
|
|
41
41
|
void FanCall::validate_() {
|
42
42
|
auto traits = this->parent_.get_traits();
|
43
43
|
|
44
|
-
if (this->speed_.has_value())
|
44
|
+
if (this->speed_.has_value()) {
|
45
45
|
this->speed_ = clamp(*this->speed_, 1, traits.supported_speed_count());
|
46
46
|
|
47
|
-
|
48
|
-
//
|
49
|
-
|
50
|
-
|
47
|
+
// https://developers.home-assistant.io/docs/core/entity/fan/#preset-modes
|
48
|
+
// "Manually setting a speed must disable any set preset mode"
|
49
|
+
this->preset_mode_.clear();
|
50
|
+
}
|
51
|
+
|
52
|
+
if (!this->preset_mode_.empty()) {
|
53
|
+
const auto &preset_modes = traits.supported_preset_modes();
|
54
|
+
if (preset_modes.find(this->preset_mode_) == preset_modes.end()) {
|
55
|
+
ESP_LOGW(TAG, "%s: Preset mode '%s' not supported", this->parent_.get_name().c_str(), this->preset_mode_.c_str());
|
56
|
+
this->preset_mode_.clear();
|
51
57
|
}
|
52
58
|
}
|
53
59
|
|
60
|
+
// when turning on...
|
61
|
+
if (!this->parent_.state && this->binary_state_.has_value() &&
|
62
|
+
*this->binary_state_
|
63
|
+
// ..,and no preset mode will be active...
|
64
|
+
&& this->preset_mode_.empty() &&
|
65
|
+
this->parent_.preset_mode.empty()
|
66
|
+
// ...and neither current nor new speed is available...
|
67
|
+
&& traits.supports_speed() && this->parent_.speed == 0 && !this->speed_.has_value()) {
|
68
|
+
// ...set speed to 100%
|
69
|
+
this->speed_ = traits.supported_speed_count();
|
70
|
+
}
|
71
|
+
|
54
72
|
if (this->oscillating_.has_value() && !traits.supports_oscillation()) {
|
55
|
-
ESP_LOGW(TAG, "
|
73
|
+
ESP_LOGW(TAG, "%s: Oscillation not supported", this->parent_.get_name().c_str());
|
56
74
|
this->oscillating_.reset();
|
57
75
|
}
|
58
76
|
|
59
77
|
if (this->speed_.has_value() && !traits.supports_speed()) {
|
60
|
-
ESP_LOGW(TAG, "
|
78
|
+
ESP_LOGW(TAG, "%s: Speed control not supported", this->parent_.get_name().c_str());
|
61
79
|
this->speed_.reset();
|
62
80
|
}
|
63
81
|
|
64
82
|
if (this->direction_.has_value() && !traits.supports_direction()) {
|
65
|
-
ESP_LOGW(TAG, "
|
83
|
+
ESP_LOGW(TAG, "%s: Direction control not supported", this->parent_.get_name().c_str());
|
66
84
|
this->direction_.reset();
|
67
85
|
}
|
68
|
-
|
69
|
-
if (!this->preset_mode_.empty()) {
|
70
|
-
const auto &preset_modes = traits.supported_preset_modes();
|
71
|
-
if (preset_modes.find(this->preset_mode_) == preset_modes.end()) {
|
72
|
-
ESP_LOGW(TAG, "'%s' - This fan does not support preset mode '%s'!", this->parent_.get_name().c_str(),
|
73
|
-
this->preset_mode_.c_str());
|
74
|
-
this->preset_mode_.clear();
|
75
|
-
}
|
76
|
-
}
|
77
86
|
}
|
78
87
|
|
79
88
|
FanCall FanRestoreState::to_call(Fan &fan) {
|
@@ -45,7 +45,7 @@ void I2SAudioMicrophone::setup() {
|
|
45
45
|
#if SOC_I2S_SUPPORTS_ADC
|
46
46
|
if (this->adc_) {
|
47
47
|
if (this->parent_->get_port() != I2S_NUM_0) {
|
48
|
-
ESP_LOGE(TAG, "Internal ADC only works on I2S0
|
48
|
+
ESP_LOGE(TAG, "Internal ADC only works on I2S0");
|
49
49
|
this->mark_failed();
|
50
50
|
return;
|
51
51
|
}
|
@@ -55,7 +55,7 @@ void I2SAudioMicrophone::setup() {
|
|
55
55
|
{
|
56
56
|
if (this->pdm_) {
|
57
57
|
if (this->parent_->get_port() != I2S_NUM_0) {
|
58
|
-
ESP_LOGE(TAG, "PDM only works on I2S0
|
58
|
+
ESP_LOGE(TAG, "PDM only works on I2S0");
|
59
59
|
this->mark_failed();
|
60
60
|
return;
|
61
61
|
}
|
@@ -64,14 +64,14 @@ void I2SAudioMicrophone::setup() {
|
|
64
64
|
|
65
65
|
this->active_listeners_semaphore_ = xSemaphoreCreateCounting(MAX_LISTENERS, MAX_LISTENERS);
|
66
66
|
if (this->active_listeners_semaphore_ == nullptr) {
|
67
|
-
ESP_LOGE(TAG, "
|
67
|
+
ESP_LOGE(TAG, "Creating semaphore failed");
|
68
68
|
this->mark_failed();
|
69
69
|
return;
|
70
70
|
}
|
71
71
|
|
72
72
|
this->event_group_ = xEventGroupCreate();
|
73
73
|
if (this->event_group_ == nullptr) {
|
74
|
-
ESP_LOGE(TAG, "
|
74
|
+
ESP_LOGE(TAG, "Creating event group failed");
|
75
75
|
this->mark_failed();
|
76
76
|
return;
|
77
77
|
}
|
@@ -79,6 +79,15 @@ void I2SAudioMicrophone::setup() {
|
|
79
79
|
this->configure_stream_settings_();
|
80
80
|
}
|
81
81
|
|
82
|
+
void I2SAudioMicrophone::dump_config() {
|
83
|
+
ESP_LOGCONFIG(TAG,
|
84
|
+
"Microphone:\n"
|
85
|
+
" Pin: %d\n"
|
86
|
+
" PDM: %s\n"
|
87
|
+
" DC offset correction: %s",
|
88
|
+
static_cast<int8_t>(this->din_pin_), YESNO(this->pdm_), YESNO(this->correct_dc_offset_));
|
89
|
+
}
|
90
|
+
|
82
91
|
void I2SAudioMicrophone::configure_stream_settings_() {
|
83
92
|
uint8_t channel_count = 1;
|
84
93
|
#ifdef USE_I2S_LEGACY
|
@@ -127,6 +136,7 @@ bool I2SAudioMicrophone::start_driver_() {
|
|
127
136
|
if (!this->parent_->try_lock()) {
|
128
137
|
return false; // Waiting for another i2s to return lock
|
129
138
|
}
|
139
|
+
this->locked_driver_ = true;
|
130
140
|
esp_err_t err;
|
131
141
|
|
132
142
|
#ifdef USE_I2S_LEGACY
|
@@ -151,7 +161,7 @@ bool I2SAudioMicrophone::start_driver_() {
|
|
151
161
|
config.mode = (i2s_mode_t) (config.mode | I2S_MODE_ADC_BUILT_IN);
|
152
162
|
err = i2s_driver_install(this->parent_->get_port(), &config, 0, nullptr);
|
153
163
|
if (err != ESP_OK) {
|
154
|
-
ESP_LOGE(TAG, "Error installing
|
164
|
+
ESP_LOGE(TAG, "Error installing driver: %s", esp_err_to_name(err));
|
155
165
|
return false;
|
156
166
|
}
|
157
167
|
|
@@ -174,7 +184,7 @@ bool I2SAudioMicrophone::start_driver_() {
|
|
174
184
|
|
175
185
|
err = i2s_driver_install(this->parent_->get_port(), &config, 0, nullptr);
|
176
186
|
if (err != ESP_OK) {
|
177
|
-
ESP_LOGE(TAG, "Error installing
|
187
|
+
ESP_LOGE(TAG, "Error installing driver: %s", esp_err_to_name(err));
|
178
188
|
return false;
|
179
189
|
}
|
180
190
|
|
@@ -183,7 +193,7 @@ bool I2SAudioMicrophone::start_driver_() {
|
|
183
193
|
|
184
194
|
err = i2s_set_pin(this->parent_->get_port(), &pin_config);
|
185
195
|
if (err != ESP_OK) {
|
186
|
-
ESP_LOGE(TAG, "Error setting
|
196
|
+
ESP_LOGE(TAG, "Error setting pin: %s", esp_err_to_name(err));
|
187
197
|
return false;
|
188
198
|
}
|
189
199
|
}
|
@@ -198,7 +208,7 @@ bool I2SAudioMicrophone::start_driver_() {
|
|
198
208
|
/* Allocate a new RX channel and get the handle of this channel */
|
199
209
|
err = i2s_new_channel(&chan_cfg, NULL, &this->rx_handle_);
|
200
210
|
if (err != ESP_OK) {
|
201
|
-
ESP_LOGE(TAG, "Error creating
|
211
|
+
ESP_LOGE(TAG, "Error creating channel: %s", esp_err_to_name(err));
|
202
212
|
return false;
|
203
213
|
}
|
204
214
|
|
@@ -270,14 +280,14 @@ bool I2SAudioMicrophone::start_driver_() {
|
|
270
280
|
err = i2s_channel_init_std_mode(this->rx_handle_, &std_cfg);
|
271
281
|
}
|
272
282
|
if (err != ESP_OK) {
|
273
|
-
ESP_LOGE(TAG, "Error initializing
|
283
|
+
ESP_LOGE(TAG, "Error initializing channel: %s", esp_err_to_name(err));
|
274
284
|
return false;
|
275
285
|
}
|
276
286
|
|
277
287
|
/* Before reading data, start the RX channel first */
|
278
288
|
i2s_channel_enable(this->rx_handle_);
|
279
289
|
if (err != ESP_OK) {
|
280
|
-
ESP_LOGE(TAG, "
|
290
|
+
ESP_LOGE(TAG, "Enabling failed: %s", esp_err_to_name(err));
|
281
291
|
return false;
|
282
292
|
}
|
283
293
|
#endif
|
@@ -304,31 +314,37 @@ void I2SAudioMicrophone::stop_driver_() {
|
|
304
314
|
if (this->adc_) {
|
305
315
|
err = i2s_adc_disable(this->parent_->get_port());
|
306
316
|
if (err != ESP_OK) {
|
307
|
-
ESP_LOGW(TAG, "Error disabling ADC
|
317
|
+
ESP_LOGW(TAG, "Error disabling ADC: %s", esp_err_to_name(err));
|
308
318
|
}
|
309
319
|
}
|
310
320
|
#endif
|
311
321
|
err = i2s_stop(this->parent_->get_port());
|
312
322
|
if (err != ESP_OK) {
|
313
|
-
ESP_LOGW(TAG, "Error stopping
|
323
|
+
ESP_LOGW(TAG, "Error stopping: %s", esp_err_to_name(err));
|
314
324
|
}
|
315
325
|
err = i2s_driver_uninstall(this->parent_->get_port());
|
316
326
|
if (err != ESP_OK) {
|
317
|
-
ESP_LOGW(TAG, "Error uninstalling
|
327
|
+
ESP_LOGW(TAG, "Error uninstalling driver: %s", esp_err_to_name(err));
|
318
328
|
}
|
319
329
|
#else
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
330
|
+
if (this->rx_handle_ != nullptr) {
|
331
|
+
/* Have to stop the channel before deleting it */
|
332
|
+
err = i2s_channel_disable(this->rx_handle_);
|
333
|
+
if (err != ESP_OK) {
|
334
|
+
ESP_LOGW(TAG, "Error stopping: %s", esp_err_to_name(err));
|
335
|
+
}
|
336
|
+
/* If the handle is not needed any more, delete it to release the channel resources */
|
337
|
+
err = i2s_del_channel(this->rx_handle_);
|
338
|
+
if (err != ESP_OK) {
|
339
|
+
ESP_LOGW(TAG, "Error deleting channel: %s", esp_err_to_name(err));
|
340
|
+
}
|
341
|
+
this->rx_handle_ = nullptr;
|
329
342
|
}
|
330
343
|
#endif
|
331
|
-
this->
|
344
|
+
if (this->locked_driver_) {
|
345
|
+
this->parent_->unlock();
|
346
|
+
this->locked_driver_ = false;
|
347
|
+
}
|
332
348
|
}
|
333
349
|
|
334
350
|
void I2SAudioMicrophone::mic_task(void *params) {
|
@@ -400,7 +416,7 @@ size_t I2SAudioMicrophone::read_(uint8_t *buf, size_t len, TickType_t ticks_to_w
|
|
400
416
|
// Ignore ESP_ERR_TIMEOUT if ticks_to_wait = 0, as it will read the data on the next call
|
401
417
|
if (!this->status_has_warning()) {
|
402
418
|
// Avoid spamming the logs with the error message if its repeated
|
403
|
-
ESP_LOGW(TAG, "
|
419
|
+
ESP_LOGW(TAG, "Read error: %s", esp_err_to_name(err));
|
404
420
|
}
|
405
421
|
this->status_set_warning();
|
406
422
|
return 0;
|
@@ -428,19 +444,19 @@ void I2SAudioMicrophone::loop() {
|
|
428
444
|
uint32_t event_group_bits = xEventGroupGetBits(this->event_group_);
|
429
445
|
|
430
446
|
if (event_group_bits & MicrophoneEventGroupBits::TASK_STARTING) {
|
431
|
-
|
447
|
+
ESP_LOGV(TAG, "Task started, attempting to allocate buffer");
|
432
448
|
xEventGroupClearBits(this->event_group_, MicrophoneEventGroupBits::TASK_STARTING);
|
433
449
|
}
|
434
450
|
|
435
451
|
if (event_group_bits & MicrophoneEventGroupBits::TASK_RUNNING) {
|
436
|
-
|
452
|
+
ESP_LOGV(TAG, "Task is running and reading data");
|
437
453
|
|
438
454
|
xEventGroupClearBits(this->event_group_, MicrophoneEventGroupBits::TASK_RUNNING);
|
439
455
|
this->state_ = microphone::STATE_RUNNING;
|
440
456
|
}
|
441
457
|
|
442
458
|
if ((event_group_bits & MicrophoneEventGroupBits::TASK_STOPPED)) {
|
443
|
-
|
459
|
+
ESP_LOGV(TAG, "Task finished, freeing resources and uninstalling driver");
|
444
460
|
|
445
461
|
vTaskDelete(this->task_handle_);
|
446
462
|
this->task_handle_ = nullptr;
|
@@ -470,7 +486,8 @@ void I2SAudioMicrophone::loop() {
|
|
470
486
|
}
|
471
487
|
|
472
488
|
if (!this->start_driver_()) {
|
473
|
-
|
489
|
+
ESP_LOGE(TAG, "Driver failed to start; retrying in 1 second");
|
490
|
+
this->status_momentary_error("driver_fail", 1000);
|
474
491
|
this->stop_driver_(); // Stop/frees whatever possibly started
|
475
492
|
break;
|
476
493
|
}
|
@@ -480,7 +497,8 @@ void I2SAudioMicrophone::loop() {
|
|
480
497
|
&this->task_handle_);
|
481
498
|
|
482
499
|
if (this->task_handle_ == nullptr) {
|
483
|
-
|
500
|
+
ESP_LOGE(TAG, "Task failed to start, retrying in 1 second");
|
501
|
+
this->status_momentary_error("task_fail", 1000);
|
484
502
|
this->stop_driver_(); // Stops the driver to return the lock; will be reloaded in next attempt
|
485
503
|
}
|
486
504
|
}
|
@@ -18,6 +18,7 @@ namespace i2s_audio {
|
|
18
18
|
class I2SAudioMicrophone : public I2SAudioIn, public microphone::Microphone, public Component {
|
19
19
|
public:
|
20
20
|
void setup() override;
|
21
|
+
void dump_config() override;
|
21
22
|
void start() override;
|
22
23
|
void stop() override;
|
23
24
|
|
@@ -80,6 +81,7 @@ class I2SAudioMicrophone : public I2SAudioIn, public microphone::Microphone, pub
|
|
80
81
|
bool pdm_{false};
|
81
82
|
|
82
83
|
bool correct_dc_offset_;
|
84
|
+
bool locked_driver_{false};
|
83
85
|
int32_t dc_offset_{0};
|
84
86
|
};
|
85
87
|
|
@@ -110,29 +110,48 @@ void I2SAudioSpeaker::setup() {
|
|
110
110
|
}
|
111
111
|
}
|
112
112
|
|
113
|
+
void I2SAudioSpeaker::dump_config() {
|
114
|
+
ESP_LOGCONFIG(TAG,
|
115
|
+
"Speaker:\n"
|
116
|
+
" Pin: %d\n"
|
117
|
+
" Buffer duration: %" PRIu32,
|
118
|
+
static_cast<int8_t>(this->dout_pin_), this->buffer_duration_ms_);
|
119
|
+
if (this->timeout_.has_value()) {
|
120
|
+
ESP_LOGCONFIG(TAG, " Timeout: %" PRIu32 " ms", this->timeout_.value());
|
121
|
+
}
|
122
|
+
#ifdef USE_I2S_LEGACY
|
123
|
+
#if SOC_I2S_SUPPORTS_DAC
|
124
|
+
ESP_LOGCONFIG(TAG, " Internal DAC mode: %d", static_cast<int8_t>(this->internal_dac_mode_));
|
125
|
+
#endif
|
126
|
+
ESP_LOGCONFIG(TAG, " Communication format: %d", static_cast<int8_t>(this->i2s_comm_fmt_));
|
127
|
+
#else
|
128
|
+
ESP_LOGCONFIG(TAG, " Communication format: %s", this->i2s_comm_fmt_.c_str());
|
129
|
+
#endif
|
130
|
+
}
|
131
|
+
|
113
132
|
void I2SAudioSpeaker::loop() {
|
114
133
|
uint32_t event_group_bits = xEventGroupGetBits(this->event_group_);
|
115
134
|
|
116
135
|
if (event_group_bits & SpeakerEventGroupBits::STATE_STARTING) {
|
117
|
-
ESP_LOGD(TAG, "Starting
|
136
|
+
ESP_LOGD(TAG, "Starting");
|
118
137
|
this->state_ = speaker::STATE_STARTING;
|
119
138
|
xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::STATE_STARTING);
|
120
139
|
}
|
121
140
|
if (event_group_bits & SpeakerEventGroupBits::STATE_RUNNING) {
|
122
|
-
ESP_LOGD(TAG, "Started
|
141
|
+
ESP_LOGD(TAG, "Started");
|
123
142
|
this->state_ = speaker::STATE_RUNNING;
|
124
143
|
xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::STATE_RUNNING);
|
125
144
|
this->status_clear_warning();
|
126
145
|
this->status_clear_error();
|
127
146
|
}
|
128
147
|
if (event_group_bits & SpeakerEventGroupBits::STATE_STOPPING) {
|
129
|
-
ESP_LOGD(TAG, "Stopping
|
148
|
+
ESP_LOGD(TAG, "Stopping");
|
130
149
|
this->state_ = speaker::STATE_STOPPING;
|
131
150
|
xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::STATE_STOPPING);
|
132
151
|
}
|
133
152
|
if (event_group_bits & SpeakerEventGroupBits::STATE_STOPPED) {
|
134
153
|
if (!this->task_created_) {
|
135
|
-
ESP_LOGD(TAG, "Stopped
|
154
|
+
ESP_LOGD(TAG, "Stopped");
|
136
155
|
this->state_ = speaker::STATE_STOPPED;
|
137
156
|
xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::ALL_BITS);
|
138
157
|
this->speaker_task_handle_ = nullptr;
|
@@ -140,20 +159,19 @@ void I2SAudioSpeaker::loop() {
|
|
140
159
|
}
|
141
160
|
|
142
161
|
if (event_group_bits & SpeakerEventGroupBits::ERR_TASK_FAILED_TO_START) {
|
143
|
-
this->status_set_error("Failed to start
|
162
|
+
this->status_set_error("Failed to start task");
|
144
163
|
xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::ERR_TASK_FAILED_TO_START);
|
145
164
|
}
|
146
165
|
|
147
166
|
if (event_group_bits & SpeakerEventGroupBits::ALL_ERR_ESP_BITS) {
|
148
167
|
uint32_t error_bits = event_group_bits & SpeakerEventGroupBits::ALL_ERR_ESP_BITS;
|
149
|
-
ESP_LOGW(TAG, "
|
168
|
+
ESP_LOGW(TAG, "Writing failed: %s", esp_err_to_name(err_bit_to_esp_err(error_bits)));
|
150
169
|
this->status_set_warning();
|
151
170
|
}
|
152
171
|
|
153
172
|
if (event_group_bits & SpeakerEventGroupBits::ERR_ESP_NOT_SUPPORTED) {
|
154
|
-
this->status_set_error("Failed to adjust
|
155
|
-
ESP_LOGE(TAG,
|
156
|
-
"Incompatible audio format: sample rate = %" PRIu32 ", channels = %" PRIu8 ", bits per sample = %" PRIu8,
|
173
|
+
this->status_set_error("Failed to adjust bus to match incoming audio");
|
174
|
+
ESP_LOGE(TAG, "Incompatible audio format: sample rate = %" PRIu32 ", channels = %u, bits per sample = %u",
|
157
175
|
this->audio_stream_info_.get_sample_rate(), this->audio_stream_info_.get_channels(),
|
158
176
|
this->audio_stream_info_.get_bits_per_sample());
|
159
177
|
}
|
@@ -202,7 +220,7 @@ void I2SAudioSpeaker::set_mute_state(bool mute_state) {
|
|
202
220
|
|
203
221
|
size_t I2SAudioSpeaker::play(const uint8_t *data, size_t length, TickType_t ticks_to_wait) {
|
204
222
|
if (this->is_failed()) {
|
205
|
-
ESP_LOGE(TAG, "
|
223
|
+
ESP_LOGE(TAG, "Setup failed; cannot play audio");
|
206
224
|
return 0;
|
207
225
|
}
|
208
226
|
if (this->state_ != speaker::STATE_RUNNING && this->state_ != speaker::STATE_STARTING) {
|
@@ -24,6 +24,7 @@ class I2SAudioSpeaker : public I2SAudioOut, public speaker::Speaker, public Comp
|
|
24
24
|
float get_setup_priority() const override { return esphome::setup_priority::PROCESSOR; }
|
25
25
|
|
26
26
|
void setup() override;
|
27
|
+
void dump_config() override;
|
27
28
|
void loop() override;
|
28
29
|
|
29
30
|
void set_buffer_duration(uint32_t buffer_duration_ms) { this->buffer_duration_ms_ = buffer_duration_ms; }
|
@@ -19,9 +19,8 @@ void KMeterISOComponent::setup() {
|
|
19
19
|
|
20
20
|
// Mark as not failed before initializing. Some devices will turn off sensors to save on batteries
|
21
21
|
// and when they come back on, the COMPONENT_STATE_FAILED bit must be unset on the component.
|
22
|
-
if (
|
23
|
-
this->
|
24
|
-
this->component_state_ |= COMPONENT_STATE_CONSTRUCTION;
|
22
|
+
if (this->is_failed()) {
|
23
|
+
this->reset_to_construction_state();
|
25
24
|
}
|
26
25
|
|
27
26
|
auto err = this->bus_->writev(this->address_, nullptr, 0);
|
@@ -17,7 +17,7 @@ namespace light {
|
|
17
17
|
|
18
18
|
class LightOutput;
|
19
19
|
|
20
|
-
enum LightRestoreMode {
|
20
|
+
enum LightRestoreMode : uint8_t {
|
21
21
|
LIGHT_RESTORE_DEFAULT_OFF,
|
22
22
|
LIGHT_RESTORE_DEFAULT_ON,
|
23
23
|
LIGHT_ALWAYS_OFF,
|
@@ -212,12 +212,18 @@ class LightState : public EntityBase, public Component {
|
|
212
212
|
|
213
213
|
/// Store the output to allow effects to have more access.
|
214
214
|
LightOutput *output_;
|
215
|
-
/// Value for storing the index of the currently active effect. 0 if no effect is active
|
216
|
-
uint32_t active_effect_index_{};
|
217
215
|
/// The currently active transformer for this light (transition/flash).
|
218
216
|
std::unique_ptr<LightTransformer> transformer_{nullptr};
|
219
|
-
///
|
220
|
-
|
217
|
+
/// List of effects for this light.
|
218
|
+
std::vector<LightEffect *> effects_;
|
219
|
+
/// Value for storing the index of the currently active effect. 0 if no effect is active
|
220
|
+
uint32_t active_effect_index_{};
|
221
|
+
/// Default transition length for all transitions in ms.
|
222
|
+
uint32_t default_transition_length_{};
|
223
|
+
/// Transition length to use for flash transitions.
|
224
|
+
uint32_t flash_transition_length_{};
|
225
|
+
/// Gamma correction factor for the light.
|
226
|
+
float gamma_correct_{};
|
221
227
|
|
222
228
|
/// Object used to store the persisted values of the light.
|
223
229
|
ESPPreferenceObject rtc_;
|
@@ -236,19 +242,13 @@ class LightState : public EntityBase, public Component {
|
|
236
242
|
*/
|
237
243
|
CallbackManager<void()> target_state_reached_callback_{};
|
238
244
|
|
239
|
-
/// Default transition length for all transitions in ms.
|
240
|
-
uint32_t default_transition_length_{};
|
241
|
-
/// Transition length to use for flash transitions.
|
242
|
-
uint32_t flash_transition_length_{};
|
243
|
-
/// Gamma correction factor for the light.
|
244
|
-
float gamma_correct_{};
|
245
|
-
/// Restore mode of the light.
|
246
|
-
LightRestoreMode restore_mode_;
|
247
245
|
/// Initial state of the light.
|
248
246
|
optional<LightStateRTCState> initial_state_{};
|
249
|
-
/// List of effects for this light.
|
250
|
-
std::vector<LightEffect *> effects_;
|
251
247
|
|
248
|
+
/// Restore mode of the light.
|
249
|
+
LightRestoreMode restore_mode_;
|
250
|
+
/// Whether the light value should be written in the next cycle.
|
251
|
+
bool next_write_{true};
|
252
252
|
// for effects, true if a transformer (transition) is active.
|
253
253
|
bool is_transformer_active_ = false;
|
254
254
|
};
|
@@ -116,7 +116,7 @@ void Logger::log_vprintf_(int level, const char *tag, int line, const __FlashStr
|
|
116
116
|
if (this->baud_rate_ > 0) {
|
117
117
|
this->write_msg_(this->tx_buffer_ + msg_start);
|
118
118
|
}
|
119
|
-
this->
|
119
|
+
this->log_callback_.call(level, tag, this->tx_buffer_ + msg_start);
|
120
120
|
|
121
121
|
global_recursion_guard_ = false;
|
122
122
|
}
|
@@ -129,19 +129,6 @@ inline int Logger::level_for(const char *tag) {
|
|
129
129
|
return this->current_level_;
|
130
130
|
}
|
131
131
|
|
132
|
-
void HOT Logger::call_log_callbacks_(int level, const char *tag, const char *msg) {
|
133
|
-
#ifdef USE_ESP32
|
134
|
-
// Suppress network-logging if memory constrained
|
135
|
-
// In some configurations (eg BLE enabled) there may be some transient
|
136
|
-
// memory exhaustion, and trying to log when OOM can lead to a crash. Skipping
|
137
|
-
// here usually allows the stack to recover instead.
|
138
|
-
// See issue #1234 for analysis.
|
139
|
-
if (xPortGetFreeHeapSize() < 2048)
|
140
|
-
return;
|
141
|
-
#endif
|
142
|
-
this->log_callback_.call(level, tag, msg);
|
143
|
-
}
|
144
|
-
|
145
132
|
Logger::Logger(uint32_t baud_rate, size_t tx_buffer_size) : baud_rate_(baud_rate), tx_buffer_size_(tx_buffer_size) {
|
146
133
|
// add 1 to buffer size for null terminator
|
147
134
|
this->tx_buffer_ = new char[this->tx_buffer_size_ + 1]; // NOLINT
|
@@ -189,7 +176,7 @@ void Logger::loop() {
|
|
189
176
|
this->tx_buffer_size_);
|
190
177
|
this->write_footer_to_buffer_(this->tx_buffer_, &this->tx_buffer_at_, this->tx_buffer_size_);
|
191
178
|
this->tx_buffer_[this->tx_buffer_at_] = '\0';
|
192
|
-
this->
|
179
|
+
this->log_callback_.call(message->level, message->tag, this->tx_buffer_);
|
193
180
|
// At this point all the data we need from message has been transferred to the tx_buffer
|
194
181
|
// so we can release the message to allow other tasks to use it as soon as possible.
|
195
182
|
this->log_buffer_->release_message_main_loop(received_token);
|
@@ -156,7 +156,6 @@ class Logger : public Component {
|
|
156
156
|
#endif
|
157
157
|
|
158
158
|
protected:
|
159
|
-
void call_log_callbacks_(int level, const char *tag, const char *msg);
|
160
159
|
void write_msg_(const char *msg);
|
161
160
|
|
162
161
|
// Format a log message with printf-style arguments and write it to a buffer with header, footer, and null terminator
|
@@ -191,7 +190,7 @@ class Logger : public Component {
|
|
191
190
|
if (this->baud_rate_ > 0) {
|
192
191
|
this->write_msg_(this->tx_buffer_); // If logging is enabled, write to console
|
193
192
|
}
|
194
|
-
this->
|
193
|
+
this->log_callback_.call(level, tag, this->tx_buffer_);
|
195
194
|
}
|
196
195
|
|
197
196
|
// Write the body of the log message to the buffer
|
@@ -153,7 +153,7 @@ bool MQTTComponent::send_discovery_() {
|
|
153
153
|
if (node_friendly_name.empty()) {
|
154
154
|
node_friendly_name = node_name;
|
155
155
|
}
|
156
|
-
|
156
|
+
std::string node_area = App.get_area();
|
157
157
|
|
158
158
|
JsonObject device_info = root.createNestedObject(MQTT_DEVICE);
|
159
159
|
const auto mac = get_mac_address();
|