esphome 2025.7.0b3__py3-none-any.whl → 2025.7.0b5__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/as3935_spi/as3935_spi.h +0 -2
- esphome/components/async_tcp/__init__.py +1 -1
- esphome/components/fan/fan.cpp +4 -0
- esphome/components/http_request/update/http_request_update.cpp +7 -7
- esphome/components/json/__init__.py +1 -1
- esphome/components/json/json_util.cpp +56 -63
- esphome/components/light/light_json_schema.cpp +17 -16
- esphome/components/mqtt/mqtt_alarm_control_panel.cpp +2 -1
- esphome/components/mqtt/mqtt_binary_sensor.cpp +1 -0
- esphome/components/mqtt/mqtt_button.cpp +4 -1
- esphome/components/mqtt/mqtt_client.cpp +2 -0
- esphome/components/mqtt/mqtt_climate.cpp +6 -4
- esphome/components/mqtt/mqtt_component.cpp +3 -1
- esphome/components/mqtt/mqtt_cover.cpp +1 -0
- esphome/components/mqtt/mqtt_date.cpp +4 -3
- esphome/components/mqtt/mqtt_datetime.cpp +7 -6
- esphome/components/mqtt/mqtt_event.cpp +6 -3
- esphome/components/mqtt/mqtt_fan.cpp +1 -0
- esphome/components/mqtt/mqtt_light.cpp +8 -4
- esphome/components/mqtt/mqtt_lock.cpp +3 -1
- esphome/components/mqtt/mqtt_number.cpp +1 -0
- esphome/components/mqtt/mqtt_select.cpp +2 -1
- esphome/components/mqtt/mqtt_sensor.cpp +3 -1
- esphome/components/mqtt/mqtt_switch.cpp +3 -1
- esphome/components/mqtt/mqtt_text.cpp +1 -0
- esphome/components/mqtt/mqtt_text_sensor.cpp +3 -1
- esphome/components/mqtt/mqtt_time.cpp +4 -3
- esphome/components/mqtt/mqtt_update.cpp +1 -0
- esphome/components/mqtt/mqtt_valve.cpp +3 -1
- esphome/components/ms8607/ms8607.cpp +1 -1
- esphome/components/online_image/__init__.py +4 -1
- esphome/components/online_image/online_image.cpp +11 -5
- esphome/components/online_image/online_image.h +6 -1
- esphome/components/opentherm/output/output.cpp +1 -1
- esphome/components/servo/servo.cpp +2 -2
- esphome/components/web_server/web_server.cpp +13 -9
- esphome/components/web_server_base/__init__.py +1 -1
- esphome/components/web_server_idf/web_server_idf.cpp +2 -0
- esphome/const.py +1 -1
- esphome/core/application.cpp +6 -0
- esphome/core/component.cpp +1 -0
- esphome/platformio_api.py +2 -0
- esphome/writer.py +23 -0
- {esphome-2025.7.0b3.dist-info → esphome-2025.7.0b5.dist-info}/METADATA +1 -1
- {esphome-2025.7.0b3.dist-info → esphome-2025.7.0b5.dist-info}/RECORD +49 -49
- {esphome-2025.7.0b3.dist-info → esphome-2025.7.0b5.dist-info}/WHEEL +0 -0
- {esphome-2025.7.0b3.dist-info → esphome-2025.7.0b5.dist-info}/entry_points.txt +0 -0
- {esphome-2025.7.0b3.dist-info → esphome-2025.7.0b5.dist-info}/licenses/LICENSE +0 -0
- {esphome-2025.7.0b3.dist-info → esphome-2025.7.0b5.dist-info}/top_level.txt +0 -0
|
@@ -44,8 +44,10 @@ void MQTTSensorComponent::set_expire_after(uint32_t expire_after) { this->expire
|
|
|
44
44
|
void MQTTSensorComponent::disable_expire_after() { this->expire_after_ = 0; }
|
|
45
45
|
|
|
46
46
|
void MQTTSensorComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) {
|
|
47
|
-
|
|
47
|
+
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
|
|
48
|
+
if (!this->sensor_->get_device_class().empty()) {
|
|
48
49
|
root[MQTT_DEVICE_CLASS] = this->sensor_->get_device_class();
|
|
50
|
+
}
|
|
49
51
|
|
|
50
52
|
if (!this->sensor_->get_unit_of_measurement().empty())
|
|
51
53
|
root[MQTT_UNIT_OF_MEASUREMENT] = this->sensor_->get_unit_of_measurement();
|
|
@@ -45,8 +45,10 @@ void MQTTSwitchComponent::dump_config() {
|
|
|
45
45
|
std::string MQTTSwitchComponent::component_type() const { return "switch"; }
|
|
46
46
|
const EntityBase *MQTTSwitchComponent::get_entity() const { return this->switch_; }
|
|
47
47
|
void MQTTSwitchComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) {
|
|
48
|
-
|
|
48
|
+
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
|
|
49
|
+
if (this->switch_->assumed_state()) {
|
|
49
50
|
root[MQTT_OPTIMISTIC] = true;
|
|
51
|
+
}
|
|
50
52
|
}
|
|
51
53
|
bool MQTTSwitchComponent::send_initial_state() { return this->publish_state(this->switch_->state); }
|
|
52
54
|
|
|
@@ -34,6 +34,7 @@ std::string MQTTTextComponent::component_type() const { return "text"; }
|
|
|
34
34
|
const EntityBase *MQTTTextComponent::get_entity() const { return this->text_; }
|
|
35
35
|
|
|
36
36
|
void MQTTTextComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) {
|
|
37
|
+
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
|
|
37
38
|
switch (this->text_->traits.get_mode()) {
|
|
38
39
|
case TEXT_MODE_TEXT:
|
|
39
40
|
root[MQTT_MODE] = "text";
|
|
@@ -15,8 +15,10 @@ using namespace esphome::text_sensor;
|
|
|
15
15
|
|
|
16
16
|
MQTTTextSensor::MQTTTextSensor(TextSensor *sensor) : sensor_(sensor) {}
|
|
17
17
|
void MQTTTextSensor::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) {
|
|
18
|
-
|
|
18
|
+
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
|
|
19
|
+
if (!this->sensor_->get_device_class().empty()) {
|
|
19
20
|
root[MQTT_DEVICE_CLASS] = this->sensor_->get_device_class();
|
|
21
|
+
}
|
|
20
22
|
config.command_topic = false;
|
|
21
23
|
}
|
|
22
24
|
void MQTTTextSensor::setup() {
|
|
@@ -20,13 +20,13 @@ MQTTTimeComponent::MQTTTimeComponent(TimeEntity *time) : time_(time) {}
|
|
|
20
20
|
void MQTTTimeComponent::setup() {
|
|
21
21
|
this->subscribe_json(this->get_command_topic_(), [this](const std::string &topic, JsonObject root) {
|
|
22
22
|
auto call = this->time_->make_call();
|
|
23
|
-
if (root
|
|
23
|
+
if (root["hour"].is<uint8_t>()) {
|
|
24
24
|
call.set_hour(root["hour"]);
|
|
25
25
|
}
|
|
26
|
-
if (root
|
|
26
|
+
if (root["minute"].is<uint8_t>()) {
|
|
27
27
|
call.set_minute(root["minute"]);
|
|
28
28
|
}
|
|
29
|
-
if (root
|
|
29
|
+
if (root["second"].is<uint8_t>()) {
|
|
30
30
|
call.set_second(root["second"]);
|
|
31
31
|
}
|
|
32
32
|
call.perform();
|
|
@@ -55,6 +55,7 @@ bool MQTTTimeComponent::send_initial_state() {
|
|
|
55
55
|
}
|
|
56
56
|
bool MQTTTimeComponent::publish_state(uint8_t hour, uint8_t minute, uint8_t second) {
|
|
57
57
|
return this->publish_json(this->get_state_topic_(), [hour, minute, second](JsonObject root) {
|
|
58
|
+
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
|
|
58
59
|
root["hour"] = hour;
|
|
59
60
|
root["minute"] = minute;
|
|
60
61
|
root["second"] = second;
|
|
@@ -41,6 +41,7 @@ bool MQTTUpdateComponent::publish_state() {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
void MQTTUpdateComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) {
|
|
44
|
+
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
|
|
44
45
|
root["schema"] = "json";
|
|
45
46
|
root[MQTT_PAYLOAD_INSTALL] = "INSTALL";
|
|
46
47
|
}
|
|
@@ -49,8 +49,10 @@ void MQTTValveComponent::dump_config() {
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
void MQTTValveComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) {
|
|
52
|
-
|
|
52
|
+
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
|
|
53
|
+
if (!this->valve_->get_device_class().empty()) {
|
|
53
54
|
root[MQTT_DEVICE_CLASS] = this->valve_->get_device_class();
|
|
55
|
+
}
|
|
54
56
|
|
|
55
57
|
auto traits = this->valve_->get_traits();
|
|
56
58
|
if (traits.get_is_assumed_state()) {
|
|
@@ -356,7 +356,7 @@ void MS8607Component::read_humidity_(float temperature_float) {
|
|
|
356
356
|
|
|
357
357
|
// map 16 bit humidity value into range [-6%, 118%]
|
|
358
358
|
float const humidity_partial = double(humidity) / (1 << 16);
|
|
359
|
-
float const humidity_percentage = lerp(
|
|
359
|
+
float const humidity_percentage = std::lerp(-6.0, 118.0, humidity_partial);
|
|
360
360
|
float const compensated_humidity_percentage =
|
|
361
361
|
humidity_percentage + (20 - temperature_float) * MS8607_H_TEMP_COEFFICIENT;
|
|
362
362
|
ESP_LOGD(TAG, "Compensated for temperature, humidity=%.2f%%", compensated_humidity_percentage);
|
|
@@ -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
|
-
|
|
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->
|
|
318
|
-
|
|
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(
|
|
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(
|
|
91
|
+
level = std::lerp(this->idle_level_, this->min_level_, -value);
|
|
92
92
|
} else {
|
|
93
|
-
level = lerp(
|
|
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;
|
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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
esphome/core/application.cpp
CHANGED
|
@@ -309,6 +309,12 @@ void Application::disable_component_loop_(Component *component) {
|
|
|
309
309
|
if (this->in_loop_ && i == this->current_loop_index_) {
|
|
310
310
|
// Decrement so we'll process the swapped component next
|
|
311
311
|
this->current_loop_index_--;
|
|
312
|
+
// Update the loop start time to current time so the swapped component
|
|
313
|
+
// gets correct timing instead of inheriting stale timing.
|
|
314
|
+
// This prevents integer underflow in timing calculations by ensuring
|
|
315
|
+
// the swapped component starts with a fresh timing reference, avoiding
|
|
316
|
+
// errors caused by stale or wrapped timing values.
|
|
317
|
+
this->loop_component_start_time_ = millis();
|
|
312
318
|
}
|
|
313
319
|
}
|
|
314
320
|
return;
|
esphome/core/component.cpp
CHANGED
|
@@ -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; }
|
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.
|
|
3
|
+
Version: 2025.7.0b5
|
|
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
|