esphome 2025.2.0b6__py3-none-any.whl → 2025.2.2__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.
@@ -15,6 +15,8 @@ namespace audio {
15
15
 
16
16
  static const uint32_t READ_WRITE_TIMEOUT_MS = 20;
17
17
 
18
+ static const uint32_t CONNECTION_TIMEOUT_MS = 5000;
19
+
18
20
  // The number of times the http read times out with no data before throwing an error
19
21
  static const uint32_t ERROR_COUNT_NO_DATA_READ_TIMEOUT = 100;
20
22
 
@@ -97,7 +99,7 @@ esp_err_t AudioReader::start(const std::string &uri, AudioFileType &file_type) {
97
99
  client_config.user_data = this;
98
100
  client_config.buffer_size = HTTP_STREAM_BUFFER_SIZE;
99
101
  client_config.keep_alive_enable = true;
100
- client_config.timeout_ms = 5000; // Shouldn't trigger watchdog resets if caller runs in a task
102
+ client_config.timeout_ms = CONNECTION_TIMEOUT_MS; // Shouldn't trigger watchdog resets if caller runs in a task
101
103
 
102
104
  #if CONFIG_MBEDTLS_CERTIFICATE_BUNDLE
103
105
  if (uri.find("https:") != std::string::npos) {
@@ -189,7 +191,7 @@ esp_err_t AudioReader::start(const std::string &uri, AudioFileType &file_type) {
189
191
  file_type = this->audio_file_type_;
190
192
  }
191
193
 
192
- this->no_data_read_count_ = 0;
194
+ this->last_data_read_ms_ = millis();
193
195
 
194
196
  this->output_transfer_buffer_ = AudioSinkTransferBuffer::create(this->buffer_size_);
195
197
  if (this->output_transfer_buffer_ == nullptr) {
@@ -271,8 +273,7 @@ AudioReaderState AudioReader::http_read_() {
271
273
 
272
274
  if (received_len > 0) {
273
275
  this->output_transfer_buffer_->increase_buffer_length(received_len);
274
-
275
- this->no_data_read_count_ = 0;
276
+ this->last_data_read_ms_ = millis();
276
277
  } else if (received_len < 0) {
277
278
  // HTTP read error
278
279
  this->cleanup_connection_();
@@ -280,12 +281,11 @@ AudioReaderState AudioReader::http_read_() {
280
281
  } else {
281
282
  if (bytes_to_read > 0) {
282
283
  // Read timed out
283
- ++this->no_data_read_count_;
284
- if (this->no_data_read_count_ >= ERROR_COUNT_NO_DATA_READ_TIMEOUT) {
285
- // Timed out with no data read too many times, so the http read has failed
284
+ if ((millis() - this->last_data_read_ms_) > CONNECTION_TIMEOUT_MS) {
286
285
  this->cleanup_connection_();
287
286
  return AudioReaderState::FAILED;
288
287
  }
288
+
289
289
  delay(READ_WRITE_TIMEOUT_MS);
290
290
  }
291
291
  }
@@ -71,7 +71,7 @@ class AudioReader {
71
71
  void cleanup_connection_();
72
72
 
73
73
  size_t buffer_size_;
74
- uint32_t no_data_read_count_;
74
+ uint32_t last_data_read_ms_;
75
75
 
76
76
  esp_http_client_handle_t client_{nullptr};
77
77
 
@@ -123,12 +123,49 @@ void BLEClientBase::connect() {
123
123
  esp_err_t BLEClientBase::pair() { return esp_ble_set_encryption(this->remote_bda_, ESP_BLE_SEC_ENCRYPT); }
124
124
 
125
125
  void BLEClientBase::disconnect() {
126
- if (this->state_ == espbt::ClientState::IDLE || this->state_ == espbt::ClientState::DISCONNECTING)
126
+ if (this->state_ == espbt::ClientState::IDLE) {
127
+ ESP_LOGI(TAG, "[%d] [%s] Disconnect requested, but already idle.", this->connection_index_,
128
+ this->address_str_.c_str());
127
129
  return;
128
- ESP_LOGI(TAG, "[%d] [%s] Disconnecting.", this->connection_index_, this->address_str_.c_str());
130
+ }
131
+ if (this->state_ == espbt::ClientState::DISCONNECTING) {
132
+ ESP_LOGI(TAG, "[%d] [%s] Disconnect requested, but already disconnecting.", this->connection_index_,
133
+ this->address_str_.c_str());
134
+ return;
135
+ }
136
+ if (this->state_ == espbt::ClientState::CONNECTING || this->conn_id_ == UNSET_CONN_ID) {
137
+ ESP_LOGW(TAG, "[%d] [%s] Disconnecting before connected, disconnect scheduled.", this->connection_index_,
138
+ this->address_str_.c_str());
139
+ this->want_disconnect_ = true;
140
+ return;
141
+ }
142
+ this->unconditional_disconnect();
143
+ }
144
+
145
+ void BLEClientBase::unconditional_disconnect() {
146
+ // Disconnect without checking the state.
147
+ ESP_LOGI(TAG, "[%d] [%s] Disconnecting (conn_id: %d).", this->connection_index_, this->address_str_.c_str(),
148
+ this->conn_id_);
149
+ if (this->state_ == espbt::ClientState::DISCONNECTING) {
150
+ ESP_LOGE(TAG, "[%d] [%s] Tried to disconnect while already disconnecting.", this->connection_index_,
151
+ this->address_str_.c_str());
152
+ return;
153
+ }
154
+ if (this->conn_id_ == UNSET_CONN_ID) {
155
+ ESP_LOGE(TAG, "[%d] [%s] No connection ID set, cannot disconnect.", this->connection_index_,
156
+ this->address_str_.c_str());
157
+ return;
158
+ }
129
159
  auto err = esp_ble_gattc_close(this->gattc_if_, this->conn_id_);
130
160
  if (err != ESP_OK) {
131
- ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_close error, err=%d", this->connection_index_, this->address_str_.c_str(),
161
+ //
162
+ // This is a fatal error, but we can't do anything about it
163
+ // and it likely means the BLE stack is in a bad state.
164
+ //
165
+ // In the future we might consider App.reboot() here since
166
+ // the BLE stack is in an indeterminate state.
167
+ //
168
+ ESP_LOGE(TAG, "[%d] [%s] esp_ble_gattc_close error, err=%d", this->connection_index_, this->address_str_.c_str(),
132
169
  err);
133
170
  }
134
171
 
@@ -184,12 +221,38 @@ bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
184
221
  this->log_event_("ESP_GATTC_OPEN_EVT");
185
222
  this->conn_id_ = param->open.conn_id;
186
223
  this->service_count_ = 0;
224
+ if (this->state_ != espbt::ClientState::CONNECTING) {
225
+ // This should not happen but lets log it in case it does
226
+ // because it means we have a bad assumption about how the
227
+ // ESP BT stack works.
228
+ if (this->state_ == espbt::ClientState::CONNECTED) {
229
+ ESP_LOGE(TAG, "[%d] [%s] Got ESP_GATTC_OPEN_EVT while already connected, status=%d", this->connection_index_,
230
+ this->address_str_.c_str(), param->open.status);
231
+ } else if (this->state_ == espbt::ClientState::ESTABLISHED) {
232
+ ESP_LOGE(TAG, "[%d] [%s] Got ESP_GATTC_OPEN_EVT while already established, status=%d",
233
+ this->connection_index_, this->address_str_.c_str(), param->open.status);
234
+ } else if (this->state_ == espbt::ClientState::DISCONNECTING) {
235
+ ESP_LOGE(TAG, "[%d] [%s] Got ESP_GATTC_OPEN_EVT while disconnecting, status=%d", this->connection_index_,
236
+ this->address_str_.c_str(), param->open.status);
237
+ } else {
238
+ ESP_LOGE(TAG, "[%d] [%s] Got ESP_GATTC_OPEN_EVT while not in connecting state, status=%d",
239
+ this->connection_index_, this->address_str_.c_str(), param->open.status);
240
+ }
241
+ }
187
242
  if (param->open.status != ESP_GATT_OK && param->open.status != ESP_GATT_ALREADY_OPEN) {
188
243
  ESP_LOGW(TAG, "[%d] [%s] Connection failed, status=%d", this->connection_index_, this->address_str_.c_str(),
189
244
  param->open.status);
190
245
  this->set_state(espbt::ClientState::IDLE);
191
246
  break;
192
247
  }
248
+ if (this->want_disconnect_) {
249
+ // Disconnect was requested after connecting started,
250
+ // but before the connection was established. Now that we have
251
+ // this->conn_id_ set, we can disconnect it.
252
+ this->unconditional_disconnect();
253
+ this->conn_id_ = UNSET_CONN_ID;
254
+ break;
255
+ }
193
256
  auto ret = esp_ble_gattc_send_mtu_req(this->gattc_if_, param->open.conn_id);
194
257
  if (ret) {
195
258
  ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_send_mtu_req failed, status=%x", this->connection_index_,
@@ -241,6 +304,7 @@ bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
241
304
  this->log_event_("ESP_GATTC_CLOSE_EVT");
242
305
  this->release_services();
243
306
  this->set_state(espbt::ClientState::IDLE);
307
+ this->conn_id_ = UNSET_CONN_ID;
244
308
  break;
245
309
  }
246
310
  case ESP_GATTC_SEARCH_RES_EVT: {
@@ -21,6 +21,8 @@ namespace esp32_ble_client {
21
21
 
22
22
  namespace espbt = esphome::esp32_ble_tracker;
23
23
 
24
+ static const int UNSET_CONN_ID = 0xFFFF;
25
+
24
26
  class BLEClientBase : public espbt::ESPBTClient, public Component {
25
27
  public:
26
28
  void setup() override;
@@ -37,6 +39,7 @@ class BLEClientBase : public espbt::ESPBTClient, public Component {
37
39
  void connect() override;
38
40
  esp_err_t pair();
39
41
  void disconnect() override;
42
+ void unconditional_disconnect();
40
43
  void release_services();
41
44
 
42
45
  bool connected() { return this->state_ == espbt::ClientState::ESTABLISHED; }
@@ -94,7 +97,7 @@ class BLEClientBase : public espbt::ESPBTClient, public Component {
94
97
  int gattc_if_;
95
98
  esp_bd_addr_t remote_bda_;
96
99
  esp_ble_addr_type_t remote_addr_type_{BLE_ADDR_TYPE_PUBLIC};
97
- uint16_t conn_id_{0xFFFF};
100
+ uint16_t conn_id_{UNSET_CONN_ID};
98
101
  uint64_t address_{0};
99
102
  bool auto_connect_{false};
100
103
  std::string address_str_{};
@@ -238,6 +238,12 @@ async def to_code(config):
238
238
  else:
239
239
  add_idf_sdkconfig_option("CONFIG_BTU_TASK_STACK_SIZE", 8192)
240
240
  add_idf_sdkconfig_option("CONFIG_BT_ACL_CONNECTIONS", 9)
241
+ # CONFIG_BT_GATTC_NOTIF_REG_MAX controls the number of
242
+ # max notifications in 5.x, setting CONFIG_BT_ACL_CONNECTIONS
243
+ # is enough in 4.x
244
+ # https://github.com/esphome/issues/issues/6808
245
+ if CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] >= cv.Version(5, 0, 0):
246
+ add_idf_sdkconfig_option("CONFIG_BT_GATTC_NOTIF_REG_MAX", 9)
241
247
 
242
248
  cg.add_define("USE_OTA_STATE_CALLBACK") # To be notified when an OTA update starts
243
249
  cg.add_define("USE_ESP32_BLE_CLIENT")
@@ -176,9 +176,9 @@ void ESP32BLETracker::loop() {
176
176
  https://github.com/espressif/esp-idf/issues/6688
177
177
 
178
178
  */
179
- if (!connecting && !disconnecting && xSemaphoreTake(this->scan_end_lock_, 0L)) {
179
+ if (!connecting && xSemaphoreTake(this->scan_end_lock_, 0L)) {
180
180
  if (this->scan_continuous_) {
181
- if (!promote_to_connecting && !this->scan_start_failed_ && !this->scan_set_param_failed_) {
181
+ if (!disconnecting && !promote_to_connecting && !this->scan_start_failed_ && !this->scan_set_param_failed_) {
182
182
  this->start_scan_(false);
183
183
  } else {
184
184
  // We didn't start the scan, so we need to release the lock
@@ -173,12 +173,22 @@ class ESPBTClient : public ESPBTDeviceListener {
173
173
  virtual void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) = 0;
174
174
  virtual void connect() = 0;
175
175
  virtual void disconnect() = 0;
176
- virtual void set_state(ClientState st) { this->state_ = st; }
176
+ virtual void set_state(ClientState st) {
177
+ this->state_ = st;
178
+ if (st == ClientState::IDLE) {
179
+ this->want_disconnect_ = false;
180
+ }
181
+ }
177
182
  ClientState state() const { return state_; }
178
183
  int app_id;
179
184
 
180
185
  protected:
181
186
  ClientState state_{ClientState::INIT};
187
+ // want_disconnect_ is set to true when a disconnect is requested
188
+ // while the client is connecting. This is used to disconnect the
189
+ // client as soon as we get the connection id (conn_id_) from the
190
+ // ESP_GATTC_OPEN_EVT event.
191
+ bool want_disconnect_{false};
182
192
  };
183
193
 
184
194
  class ESP32BLETracker : public Component,
@@ -52,7 +52,7 @@ void ESP32TouchComponent::setup() {
52
52
  }
53
53
  #endif
54
54
 
55
- #if ESP_IDF_VERSION_MAJOR >= 5
55
+ #if ESP_IDF_VERSION_MAJOR >= 5 && defined(USE_ESP32_VARIANT_ESP32)
56
56
  touch_pad_set_measurement_clock_cycles(this->meas_cycle_);
57
57
  touch_pad_set_measurement_interval(this->sleep_cycle_);
58
58
  #else
@@ -1,7 +1,7 @@
1
1
  #include "ltr390.h"
2
+ #include <bitset>
2
3
  #include "esphome/core/hal.h"
3
4
  #include "esphome/core/log.h"
4
- #include <bitset>
5
5
 
6
6
  namespace esphome {
7
7
  namespace ltr390 {
@@ -91,7 +91,12 @@ void LTR390Component::read_uvs_() {
91
91
  uint32_t uv = *val;
92
92
 
93
93
  if (this->uvi_sensor_ != nullptr) {
94
- this->uvi_sensor_->publish_state((uv / this->sensitivity_uv_) * this->wfac_);
94
+ // Set sensitivity by linearly scaling against known value in the datasheet
95
+ float gain_scale_uv = GAINVALUES[this->gain_uv_] / GAIN_MAX;
96
+ float intg_scale_uv = (RESOLUTIONVALUE[this->res_uv_] * 100) / INTG_MAX;
97
+ float sensitivity_uv = SENSITIVITY_MAX * gain_scale_uv * intg_scale_uv;
98
+
99
+ this->uvi_sensor_->publish_state((uv / sensitivity_uv) * this->wfac_);
95
100
  }
96
101
 
97
102
  if (this->uv_sensor_ != nullptr) {
@@ -166,11 +171,6 @@ void LTR390Component::setup() {
166
171
  return;
167
172
  }
168
173
 
169
- // Set sensitivity by linearly scaling against known value in the datasheet
170
- float gain_scale_uv = GAINVALUES[this->gain_uv_] / GAIN_MAX;
171
- float intg_scale_uv = (RESOLUTIONVALUE[this->res_uv_] * 100) / INTG_MAX;
172
- this->sensitivity_uv_ = SENSITIVITY_MAX * gain_scale_uv * intg_scale_uv;
173
-
174
174
  // Set sensor read state
175
175
  this->reading_ = false;
176
176
 
@@ -77,7 +77,6 @@ class LTR390Component : public PollingComponent, public i2c::I2CDevice {
77
77
  LTR390GAIN gain_uv_;
78
78
  LTR390RESOLUTION res_als_;
79
79
  LTR390RESOLUTION res_uv_;
80
- float sensitivity_uv_;
81
80
  float wfac_;
82
81
 
83
82
  sensor::Sensor *light_sensor_{nullptr};