esphome 2025.7.0b2__py3-none-any.whl → 2025.7.0b4__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 (62) hide show
  1. esphome/components/async_tcp/__init__.py +1 -1
  2. esphome/components/esp_ldo/__init__.py +10 -8
  3. esphome/components/esp_ldo/esp_ldo.h +3 -0
  4. esphome/components/fan/fan.cpp +4 -0
  5. esphome/components/gpio/binary_sensor/__init__.py +24 -3
  6. esphome/components/http_request/update/http_request_update.cpp +7 -7
  7. esphome/components/i2s_audio/speaker/__init__.py +1 -1
  8. esphome/components/json/__init__.py +1 -1
  9. esphome/components/json/json_util.cpp +56 -63
  10. esphome/components/ld2420/binary_sensor/ld2420_binary_sensor.cpp +2 -2
  11. esphome/components/ld2420/button/reconfig_buttons.cpp +1 -1
  12. esphome/components/ld2420/ld2420.cpp +66 -57
  13. esphome/components/ld2420/ld2420.h +9 -11
  14. esphome/components/ld2420/number/gate_config_number.cpp +1 -1
  15. esphome/components/ld2420/select/operating_mode_select.cpp +1 -1
  16. esphome/components/ld2420/sensor/ld2420_sensor.cpp +2 -2
  17. esphome/components/ld2420/text_sensor/text_sensor.cpp +2 -2
  18. esphome/components/light/light_json_schema.cpp +17 -16
  19. esphome/components/lvgl/widgets/meter.py +20 -13
  20. esphome/components/mqtt/mqtt_alarm_control_panel.cpp +2 -1
  21. esphome/components/mqtt/mqtt_binary_sensor.cpp +1 -0
  22. esphome/components/mqtt/mqtt_button.cpp +4 -1
  23. esphome/components/mqtt/mqtt_client.cpp +2 -0
  24. esphome/components/mqtt/mqtt_climate.cpp +6 -4
  25. esphome/components/mqtt/mqtt_component.cpp +3 -1
  26. esphome/components/mqtt/mqtt_cover.cpp +1 -0
  27. esphome/components/mqtt/mqtt_date.cpp +4 -3
  28. esphome/components/mqtt/mqtt_datetime.cpp +7 -6
  29. esphome/components/mqtt/mqtt_event.cpp +6 -3
  30. esphome/components/mqtt/mqtt_fan.cpp +1 -0
  31. esphome/components/mqtt/mqtt_light.cpp +8 -4
  32. esphome/components/mqtt/mqtt_lock.cpp +3 -1
  33. esphome/components/mqtt/mqtt_number.cpp +1 -0
  34. esphome/components/mqtt/mqtt_select.cpp +2 -1
  35. esphome/components/mqtt/mqtt_sensor.cpp +3 -1
  36. esphome/components/mqtt/mqtt_switch.cpp +3 -1
  37. esphome/components/mqtt/mqtt_text.cpp +1 -0
  38. esphome/components/mqtt/mqtt_text_sensor.cpp +3 -1
  39. esphome/components/mqtt/mqtt_time.cpp +4 -3
  40. esphome/components/mqtt/mqtt_update.cpp +1 -0
  41. esphome/components/mqtt/mqtt_valve.cpp +3 -1
  42. esphome/components/ms8607/ms8607.cpp +1 -1
  43. esphome/components/online_image/__init__.py +4 -1
  44. esphome/components/online_image/online_image.cpp +11 -5
  45. esphome/components/online_image/online_image.h +6 -1
  46. esphome/components/opentherm/output/output.cpp +1 -1
  47. esphome/components/servo/servo.cpp +2 -2
  48. esphome/components/substitutions/__init__.py +5 -2
  49. esphome/components/web_server/web_server.cpp +13 -9
  50. esphome/components/web_server_base/__init__.py +1 -1
  51. esphome/components/web_server_idf/web_server_idf.cpp +2 -0
  52. esphome/const.py +1 -1
  53. esphome/core/component.cpp +9 -8
  54. esphome/core/helpers.h +1 -1
  55. esphome/platformio_api.py +2 -0
  56. esphome/writer.py +23 -0
  57. {esphome-2025.7.0b2.dist-info → esphome-2025.7.0b4.dist-info}/METADATA +1 -1
  58. {esphome-2025.7.0b2.dist-info → esphome-2025.7.0b4.dist-info}/RECORD +62 -62
  59. {esphome-2025.7.0b2.dist-info → esphome-2025.7.0b4.dist-info}/WHEEL +0 -0
  60. {esphome-2025.7.0b2.dist-info → esphome-2025.7.0b4.dist-info}/entry_points.txt +0 -0
  61. {esphome-2025.7.0b2.dist-info → esphome-2025.7.0b4.dist-info}/licenses/LICENSE +0 -0
  62. {esphome-2025.7.0b2.dist-info → esphome-2025.7.0b4.dist-info}/top_level.txt +0 -0
@@ -2,7 +2,7 @@ import logging
2
2
 
3
3
  from esphome import automation
4
4
  import esphome.codegen as cg
5
- from esphome.components.const import CONF_REQUEST_HEADERS
5
+ from esphome.components.const import CONF_BYTE_ORDER, CONF_REQUEST_HEADERS
6
6
  from esphome.components.http_request import CONF_HTTP_REQUEST_ID, HttpRequestComponent
7
7
  from esphome.components.image import (
8
8
  CONF_INVERT_ALPHA,
@@ -11,6 +11,7 @@ from esphome.components.image import (
11
11
  Image_,
12
12
  get_image_type_enum,
13
13
  get_transparency_enum,
14
+ validate_settings,
14
15
  )
15
16
  import esphome.config_validation as cv
16
17
  from esphome.const import (
@@ -161,6 +162,7 @@ CONFIG_SCHEMA = cv.Schema(
161
162
  rp2040_arduino=cv.Version(0, 0, 0),
162
163
  host=cv.Version(0, 0, 0),
163
164
  ),
165
+ validate_settings,
164
166
  )
165
167
  )
166
168
 
@@ -213,6 +215,7 @@ async def to_code(config):
213
215
  get_image_type_enum(config[CONF_TYPE]),
214
216
  transparent,
215
217
  config[CONF_BUFFER_SIZE],
218
+ config.get(CONF_BYTE_ORDER) != "LITTLE_ENDIAN",
216
219
  )
217
220
  await cg.register_component(var, config)
218
221
  await cg.register_parented(var, config[CONF_HTTP_REQUEST_ID])
@@ -35,14 +35,15 @@ inline bool is_color_on(const Color &color) {
35
35
  }
36
36
 
37
37
  OnlineImage::OnlineImage(const std::string &url, int width, int height, ImageFormat format, ImageType type,
38
- image::Transparency transparency, uint32_t download_buffer_size)
38
+ image::Transparency transparency, uint32_t download_buffer_size, bool is_big_endian)
39
39
  : Image(nullptr, 0, 0, type, transparency),
40
40
  buffer_(nullptr),
41
41
  download_buffer_(download_buffer_size),
42
42
  download_buffer_initial_size_(download_buffer_size),
43
43
  format_(format),
44
44
  fixed_width_(width),
45
- fixed_height_(height) {
45
+ fixed_height_(height),
46
+ is_big_endian_(is_big_endian) {
46
47
  this->set_url(url);
47
48
  }
48
49
 
@@ -296,7 +297,7 @@ void OnlineImage::draw_pixel_(int x, int y, Color color) {
296
297
  break;
297
298
  }
298
299
  case ImageType::IMAGE_TYPE_GRAYSCALE: {
299
- uint8_t gray = static_cast<uint8_t>(0.2125 * color.r + 0.7154 * color.g + 0.0721 * color.b);
300
+ auto gray = static_cast<uint8_t>(0.2125 * color.r + 0.7154 * color.g + 0.0721 * color.b);
300
301
  if (this->transparency_ == image::TRANSPARENCY_CHROMA_KEY) {
301
302
  if (gray == 1) {
302
303
  gray = 0;
@@ -314,8 +315,13 @@ void OnlineImage::draw_pixel_(int x, int y, Color color) {
314
315
  case ImageType::IMAGE_TYPE_RGB565: {
315
316
  this->map_chroma_key(color);
316
317
  uint16_t col565 = display::ColorUtil::color_to_565(color);
317
- this->buffer_[pos + 0] = static_cast<uint8_t>((col565 >> 8) & 0xFF);
318
- this->buffer_[pos + 1] = static_cast<uint8_t>(col565 & 0xFF);
318
+ if (this->is_big_endian_) {
319
+ this->buffer_[pos + 0] = static_cast<uint8_t>((col565 >> 8) & 0xFF);
320
+ this->buffer_[pos + 1] = static_cast<uint8_t>(col565 & 0xFF);
321
+ } else {
322
+ this->buffer_[pos + 0] = static_cast<uint8_t>(col565 & 0xFF);
323
+ this->buffer_[pos + 1] = static_cast<uint8_t>((col565 >> 8) & 0xFF);
324
+ }
319
325
  if (this->transparency_ == image::TRANSPARENCY_ALPHA_CHANNEL) {
320
326
  this->buffer_[pos + 2] = color.w;
321
327
  }
@@ -50,7 +50,7 @@ class OnlineImage : public PollingComponent,
50
50
  * @param buffer_size Size of the buffer used to download the image.
51
51
  */
52
52
  OnlineImage(const std::string &url, int width, int height, ImageFormat format, image::ImageType type,
53
- image::Transparency transparency, uint32_t buffer_size);
53
+ image::Transparency transparency, uint32_t buffer_size, bool is_big_endian);
54
54
 
55
55
  void draw(int x, int y, display::Display *display, Color color_on, Color color_off) override;
56
56
 
@@ -164,6 +164,11 @@ class OnlineImage : public PollingComponent,
164
164
  const int fixed_width_;
165
165
  /** height requested on configuration, or 0 if non specified. */
166
166
  const int fixed_height_;
167
+ /**
168
+ * Whether the image is stored in big-endian format.
169
+ * This is used to determine how to store 16 bit colors in the buffer.
170
+ */
171
+ bool is_big_endian_;
167
172
  /**
168
173
  * Actual width of the current image. If fixed_width_ is specified,
169
174
  * this will be equal to it; otherwise it will be set once the decoding
@@ -10,7 +10,7 @@ void opentherm::OpenthermOutput::write_state(float state) {
10
10
  ESP_LOGD(TAG, "Received state: %.2f. Min value: %.2f, max value: %.2f", state, min_value_, max_value_);
11
11
  this->state = state < 0.003 && this->zero_means_zero_
12
12
  ? 0.0
13
- : clamp(lerp(state, min_value_, max_value_), min_value_, max_value_);
13
+ : clamp(std::lerp(min_value_, max_value_, state), min_value_, max_value_);
14
14
  this->has_state_ = true;
15
15
  ESP_LOGD(TAG, "Output %s set to %.2f", this->id_, this->state);
16
16
  }
@@ -88,9 +88,9 @@ void Servo::internal_write(float value) {
88
88
  value = clamp(value, -1.0f, 1.0f);
89
89
  float level;
90
90
  if (value < 0.0) {
91
- level = lerp(-value, this->idle_level_, this->min_level_);
91
+ level = std::lerp(this->idle_level_, this->min_level_, -value);
92
92
  } else {
93
- level = lerp(value, this->idle_level_, this->max_level_);
93
+ level = std::lerp(this->idle_level_, this->max_level_, value);
94
94
  }
95
95
  this->output_->set_level(level);
96
96
  this->current_value_ = value;
@@ -151,8 +151,11 @@ def _substitute_item(substitutions, item, path, jinja, ignore_missing):
151
151
  if sub is not None:
152
152
  item[k] = sub
153
153
  for old, new in replace_keys:
154
- item[new] = merge_config(item.get(old), item.get(new))
155
- del item[old]
154
+ if str(new) == str(old):
155
+ item[new] = item[old]
156
+ else:
157
+ item[new] = merge_config(item.get(old), item.get(new))
158
+ del item[old]
156
159
  elif isinstance(item, str):
157
160
  sub = _expand_substitutions(substitutions, item, path, jinja, ignore_missing)
158
161
  if isinstance(sub, JinjaStr) or sub != item:
@@ -792,7 +792,7 @@ std::string WebServer::light_json(light::LightState *obj, JsonDetail start_confi
792
792
 
793
793
  light::LightJSONSchema::dump_json(*obj, root);
794
794
  if (start_config == DETAIL_ALL) {
795
- JsonArray opt = root.createNestedArray("effects");
795
+ JsonArray opt = root["effects"].to<JsonArray>();
796
796
  opt.add("None");
797
797
  for (auto const &option : obj->get_effects()) {
798
798
  opt.add(option->get_name());
@@ -1238,7 +1238,7 @@ std::string WebServer::select_json(select::Select *obj, const std::string &value
1238
1238
  return json::build_json([this, obj, value, start_config](JsonObject root) {
1239
1239
  set_json_icon_state_value(root, obj, "select-" + obj->get_object_id(), value, value, start_config);
1240
1240
  if (start_config == DETAIL_ALL) {
1241
- JsonArray opt = root.createNestedArray("option");
1241
+ JsonArray opt = root["option"].to<JsonArray>();
1242
1242
  for (auto &option : obj->traits.get_options()) {
1243
1243
  opt.add(option);
1244
1244
  }
@@ -1322,6 +1322,7 @@ std::string WebServer::climate_all_json_generator(WebServer *web_server, void *s
1322
1322
  return web_server->climate_json((climate::Climate *) (source), DETAIL_ALL);
1323
1323
  }
1324
1324
  std::string WebServer::climate_json(climate::Climate *obj, JsonDetail start_config) {
1325
+ // NOLINTBEGIN(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
1325
1326
  return json::build_json([this, obj, start_config](JsonObject root) {
1326
1327
  set_json_id(root, obj, "climate-" + obj->get_object_id(), start_config);
1327
1328
  const auto traits = obj->get_traits();
@@ -1330,32 +1331,32 @@ std::string WebServer::climate_json(climate::Climate *obj, JsonDetail start_conf
1330
1331
  char buf[16];
1331
1332
 
1332
1333
  if (start_config == DETAIL_ALL) {
1333
- JsonArray opt = root.createNestedArray("modes");
1334
+ JsonArray opt = root["modes"].to<JsonArray>();
1334
1335
  for (climate::ClimateMode m : traits.get_supported_modes())
1335
1336
  opt.add(PSTR_LOCAL(climate::climate_mode_to_string(m)));
1336
1337
  if (!traits.get_supported_custom_fan_modes().empty()) {
1337
- JsonArray opt = root.createNestedArray("fan_modes");
1338
+ JsonArray opt = root["fan_modes"].to<JsonArray>();
1338
1339
  for (climate::ClimateFanMode m : traits.get_supported_fan_modes())
1339
1340
  opt.add(PSTR_LOCAL(climate::climate_fan_mode_to_string(m)));
1340
1341
  }
1341
1342
 
1342
1343
  if (!traits.get_supported_custom_fan_modes().empty()) {
1343
- JsonArray opt = root.createNestedArray("custom_fan_modes");
1344
+ JsonArray opt = root["custom_fan_modes"].to<JsonArray>();
1344
1345
  for (auto const &custom_fan_mode : traits.get_supported_custom_fan_modes())
1345
1346
  opt.add(custom_fan_mode);
1346
1347
  }
1347
1348
  if (traits.get_supports_swing_modes()) {
1348
- JsonArray opt = root.createNestedArray("swing_modes");
1349
+ JsonArray opt = root["swing_modes"].to<JsonArray>();
1349
1350
  for (auto swing_mode : traits.get_supported_swing_modes())
1350
1351
  opt.add(PSTR_LOCAL(climate::climate_swing_mode_to_string(swing_mode)));
1351
1352
  }
1352
1353
  if (traits.get_supports_presets() && obj->preset.has_value()) {
1353
- JsonArray opt = root.createNestedArray("presets");
1354
+ JsonArray opt = root["presets"].to<JsonArray>();
1354
1355
  for (climate::ClimatePreset m : traits.get_supported_presets())
1355
1356
  opt.add(PSTR_LOCAL(climate::climate_preset_to_string(m)));
1356
1357
  }
1357
1358
  if (!traits.get_supported_custom_presets().empty() && obj->custom_preset.has_value()) {
1358
- JsonArray opt = root.createNestedArray("custom_presets");
1359
+ JsonArray opt = root["custom_presets"].to<JsonArray>();
1359
1360
  for (auto const &custom_preset : traits.get_supported_custom_presets())
1360
1361
  opt.add(custom_preset);
1361
1362
  }
@@ -1407,6 +1408,7 @@ std::string WebServer::climate_json(climate::Climate *obj, JsonDetail start_conf
1407
1408
  root["state"] = root["target_temperature"];
1408
1409
  }
1409
1410
  });
1411
+ // NOLINTEND(clang-analyzer-cplusplus.NewDeleteLeaks)
1410
1412
  }
1411
1413
  #endif
1412
1414
 
@@ -1635,7 +1637,7 @@ std::string WebServer::event_json(event::Event *obj, const std::string &event_ty
1635
1637
  root["event_type"] = event_type;
1636
1638
  }
1637
1639
  if (start_config == DETAIL_ALL) {
1638
- JsonArray event_types = root.createNestedArray("event_types");
1640
+ JsonArray event_types = root["event_types"].to<JsonArray>();
1639
1641
  for (auto const &event_type : obj->get_event_types()) {
1640
1642
  event_types.add(event_type);
1641
1643
  }
@@ -1682,6 +1684,7 @@ std::string WebServer::update_all_json_generator(WebServer *web_server, void *so
1682
1684
  return web_server->update_json((update::UpdateEntity *) (source), DETAIL_STATE);
1683
1685
  }
1684
1686
  std::string WebServer::update_json(update::UpdateEntity *obj, JsonDetail start_config) {
1687
+ // NOLINTBEGIN(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
1685
1688
  return json::build_json([this, obj, start_config](JsonObject root) {
1686
1689
  set_json_id(root, obj, "update-" + obj->get_object_id(), start_config);
1687
1690
  root["value"] = obj->update_info.latest_version;
@@ -1707,6 +1710,7 @@ std::string WebServer::update_json(update::UpdateEntity *obj, JsonDetail start_c
1707
1710
  this->add_sorting_info_(root, obj);
1708
1711
  }
1709
1712
  });
1713
+ // NOLINTEND(clang-analyzer-cplusplus.NewDeleteLeaks)
1710
1714
  }
1711
1715
  #endif
1712
1716
 
@@ -40,4 +40,4 @@ async def to_code(config):
40
40
  if CORE.is_esp8266:
41
41
  cg.add_library("ESP8266WiFi", None)
42
42
  # https://github.com/ESP32Async/ESPAsyncWebServer/blob/main/library.json
43
- cg.add_library("ESP32Async/ESPAsyncWebServer", "3.7.8")
43
+ cg.add_library("ESP32Async/ESPAsyncWebServer", "3.7.10")
@@ -389,10 +389,12 @@ AsyncEventSourceResponse::AsyncEventSourceResponse(const AsyncWebServerRequest *
389
389
 
390
390
  #ifdef USE_WEBSERVER_SORTING
391
391
  for (auto &group : ws->sorting_groups_) {
392
+ // NOLINTBEGIN(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
392
393
  message = json::build_json([group](JsonObject root) {
393
394
  root["name"] = group.second.name;
394
395
  root["sorting_weight"] = group.second.weight;
395
396
  });
397
+ // NOLINTEND(clang-analyzer-cplusplus.NewDeleteLeaks)
396
398
 
397
399
  // a (very) large number of these should be able to be queued initially without defer
398
400
  // since the only thing in the send buffer at this point is the initial ping/config
esphome/const.py CHANGED
@@ -4,7 +4,7 @@ from enum import Enum
4
4
 
5
5
  from esphome.enum import StrEnum
6
6
 
7
- __version__ = "2025.7.0b2"
7
+ __version__ = "2025.7.0b4"
8
8
 
9
9
  ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
10
10
  VALID_SUBSTITUTIONS_CHARACTERS = (
@@ -138,7 +138,7 @@ void Component::call_dump_config() {
138
138
  }
139
139
  }
140
140
  }
141
- ESP_LOGE(TAG, " Component %s is marked FAILED: %s", this->get_component_source(), error_msg);
141
+ ESP_LOGE(TAG, " %s is marked FAILED: %s", this->get_component_source(), error_msg);
142
142
  }
143
143
  }
144
144
 
@@ -191,7 +191,7 @@ bool Component::should_warn_of_blocking(uint32_t blocking_time) {
191
191
  return false;
192
192
  }
193
193
  void Component::mark_failed() {
194
- ESP_LOGE(TAG, "Component %s was marked as failed", this->get_component_source());
194
+ ESP_LOGE(TAG, "%s was marked as failed", this->get_component_source());
195
195
  this->component_state_ &= ~COMPONENT_STATE_MASK;
196
196
  this->component_state_ |= COMPONENT_STATE_FAILED;
197
197
  this->status_set_error();
@@ -229,7 +229,7 @@ void IRAM_ATTR HOT Component::enable_loop_soon_any_context() {
229
229
  }
230
230
  void Component::reset_to_construction_state() {
231
231
  if ((this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_FAILED) {
232
- ESP_LOGI(TAG, "Component %s is being reset to construction state", this->get_component_source());
232
+ ESP_LOGI(TAG, "%s is being reset to construction state", this->get_component_source());
233
233
  this->component_state_ &= ~COMPONENT_STATE_MASK;
234
234
  this->component_state_ |= COMPONENT_STATE_CONSTRUCTION;
235
235
  // Clear error status when resetting
@@ -264,6 +264,7 @@ void Component::set_retry(uint32_t initial_wait_time, uint8_t max_attempts, std:
264
264
  bool Component::is_failed() const { return (this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_FAILED; }
265
265
  bool Component::is_ready() const {
266
266
  return (this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_LOOP ||
267
+ (this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_LOOP_DONE ||
267
268
  (this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_SETUP;
268
269
  }
269
270
  bool Component::can_proceed() { return true; }
@@ -275,14 +276,14 @@ void Component::status_set_warning(const char *message) {
275
276
  return;
276
277
  this->component_state_ |= STATUS_LED_WARNING;
277
278
  App.app_state_ |= STATUS_LED_WARNING;
278
- ESP_LOGW(TAG, "Component %s set Warning flag: %s", this->get_component_source(), message);
279
+ ESP_LOGW(TAG, "%s set Warning flag: %s", this->get_component_source(), message);
279
280
  }
280
281
  void Component::status_set_error(const char *message) {
281
282
  if ((this->component_state_ & STATUS_LED_ERROR) != 0)
282
283
  return;
283
284
  this->component_state_ |= STATUS_LED_ERROR;
284
285
  App.app_state_ |= STATUS_LED_ERROR;
285
- ESP_LOGE(TAG, "Component %s set Error flag: %s", this->get_component_source(), message);
286
+ ESP_LOGE(TAG, "%s set Error flag: %s", this->get_component_source(), message);
286
287
  if (strcmp(message, "unspecified") != 0) {
287
288
  // Lazy allocate the error messages vector if needed
288
289
  if (!component_error_messages) {
@@ -303,13 +304,13 @@ void Component::status_clear_warning() {
303
304
  if ((this->component_state_ & STATUS_LED_WARNING) == 0)
304
305
  return;
305
306
  this->component_state_ &= ~STATUS_LED_WARNING;
306
- ESP_LOGW(TAG, "Component %s cleared Warning flag", this->get_component_source());
307
+ ESP_LOGW(TAG, "%s cleared Warning flag", this->get_component_source());
307
308
  }
308
309
  void Component::status_clear_error() {
309
310
  if ((this->component_state_ & STATUS_LED_ERROR) == 0)
310
311
  return;
311
312
  this->component_state_ &= ~STATUS_LED_ERROR;
312
- ESP_LOGE(TAG, "Component %s cleared Error flag", this->get_component_source());
313
+ ESP_LOGE(TAG, "%s cleared Error flag", this->get_component_source());
313
314
  }
314
315
  void Component::status_momentary_warning(const std::string &name, uint32_t length) {
315
316
  this->status_set_warning();
@@ -403,7 +404,7 @@ uint32_t WarnIfComponentBlockingGuard::finish() {
403
404
  }
404
405
  if (should_warn) {
405
406
  const char *src = component_ == nullptr ? "<null>" : component_->get_component_source();
406
- ESP_LOGW(TAG, "Component %s took a long time for an operation (%" PRIu32 " ms)", src, blocking_time);
407
+ ESP_LOGW(TAG, "%s took a long time for an operation (%" PRIu32 " ms)", src, blocking_time);
407
408
  ESP_LOGW(TAG, "Components should block for at most 30 ms");
408
409
  }
409
410
 
esphome/core/helpers.h CHANGED
@@ -783,7 +783,7 @@ template<class T> class RAMAllocator {
783
783
  T *reallocate(T *p, size_t n) { return this->reallocate(p, n, sizeof(T)); }
784
784
 
785
785
  T *reallocate(T *p, size_t n, size_t manual_size) {
786
- size_t size = n * sizeof(T);
786
+ size_t size = n * manual_size;
787
787
  T *ptr = nullptr;
788
788
  #ifdef USE_ESP32
789
789
  if (this->flags_ & Flags::ALLOC_EXTERNAL) {
esphome/platformio_api.py CHANGED
@@ -78,6 +78,8 @@ def run_platformio_cli(*args, **kwargs) -> str | int:
78
78
  os.environ.setdefault(
79
79
  "PLATFORMIO_LIBDEPS_DIR", os.path.abspath(CORE.relative_piolibdeps_path())
80
80
  )
81
+ # Suppress Python syntax warnings from third-party scripts during compilation
82
+ os.environ.setdefault("PYTHONWARNINGS", "ignore::SyntaxWarning")
81
83
  cmd = ["platformio"] + list(args)
82
84
 
83
85
  if not CORE.verbose:
esphome/writer.py CHANGED
@@ -162,6 +162,9 @@ def get_ini_content():
162
162
  # Sort to avoid changing build unflags order
163
163
  CORE.add_platformio_option("build_unflags", sorted(CORE.build_unflags))
164
164
 
165
+ # Add extra script for C++ flags
166
+ CORE.add_platformio_option("extra_scripts", [f"pre:{CXX_FLAGS_FILE_NAME}"])
167
+
165
168
  content = "[platformio]\n"
166
169
  content += f"description = ESPHome {__version__}\n"
167
170
 
@@ -222,6 +225,9 @@ def write_platformio_project():
222
225
  write_gitignore()
223
226
  write_platformio_ini(content)
224
227
 
228
+ # Write extra script for C++ specific flags
229
+ write_cxx_flags_script()
230
+
225
231
 
226
232
  DEFINES_H_FORMAT = ESPHOME_H_FORMAT = """\
227
233
  #pragma once
@@ -394,3 +400,20 @@ def write_gitignore():
394
400
  if not os.path.isfile(path):
395
401
  with open(file=path, mode="w", encoding="utf-8") as f:
396
402
  f.write(GITIGNORE_CONTENT)
403
+
404
+
405
+ CXX_FLAGS_FILE_NAME = "cxx_flags.py"
406
+ CXX_FLAGS_FILE_CONTENTS = """# Auto-generated ESPHome script for C++ specific compiler flags
407
+ Import("env")
408
+
409
+ # Add C++ specific flags
410
+ """
411
+
412
+
413
+ def write_cxx_flags_script() -> None:
414
+ path = CORE.relative_build_path(CXX_FLAGS_FILE_NAME)
415
+ contents = CXX_FLAGS_FILE_CONTENTS
416
+ if not CORE.is_host:
417
+ contents += 'env.Append(CXXFLAGS=["-Wno-volatile"])'
418
+ contents += "\n"
419
+ write_file_if_changed(path, contents)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: esphome
3
- Version: 2025.7.0b2
3
+ Version: 2025.7.0b4
4
4
  Summary: ESPHome is a system to configure your microcontrollers by simple yet powerful configuration files and control them remotely through Home Automation systems.
5
5
  Author-email: The ESPHome Authors <esphome@openhomefoundation.org>
6
6
  License: MIT