From 24b75b7ed64ee9e239e27511c91e33a66519e9a2 Mon Sep 17 00:00:00 2001 From: wysiwyng <4764286+wysiwyng@users.noreply.github.com> Date: Wed, 16 Mar 2022 20:33:05 +0100 Subject: [PATCH 1/5] Fix WDT reset during dallas search algorithm (#3293) --- esphome/components/dallas/esp_one_wire.cpp | 4 ---- esphome/components/dallas/esp_one_wire.h | 1 - 2 files changed, 5 deletions(-) diff --git a/esphome/components/dallas/esp_one_wire.cpp b/esphome/components/dallas/esp_one_wire.cpp index 885846e5e5..5bd0f42855 100644 --- a/esphome/components/dallas/esp_one_wire.cpp +++ b/esphome/components/dallas/esp_one_wire.cpp @@ -142,7 +142,6 @@ void IRAM_ATTR ESPOneWire::select(uint64_t address) { void IRAM_ATTR ESPOneWire::reset_search() { this->last_discrepancy_ = 0; this->last_device_flag_ = false; - this->last_family_discrepancy_ = 0; this->rom_number_ = 0; } uint64_t IRAM_ATTR ESPOneWire::search() { @@ -195,9 +194,6 @@ uint64_t IRAM_ATTR ESPOneWire::search() { if (!branch) { last_zero = id_bit_number; - if (last_zero < 9) { - this->last_discrepancy_ = last_zero; - } } } diff --git a/esphome/components/dallas/esp_one_wire.h b/esphome/components/dallas/esp_one_wire.h index ef6f079f02..7544a6fe98 100644 --- a/esphome/components/dallas/esp_one_wire.h +++ b/esphome/components/dallas/esp_one_wire.h @@ -60,7 +60,6 @@ class ESPOneWire { ISRInternalGPIOPin pin_; uint8_t last_discrepancy_{0}; - uint8_t last_family_discrepancy_{0}; bool last_device_flag_{false}; uint64_t rom_number_{0}; }; From 0729ed538e6b13b5ad5d4f6d3051e79012430cf5 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 23 Mar 2022 09:45:05 +1300 Subject: [PATCH 2/5] Webserver utilize Component Iterator to not overload eventstream (#3310) --- esphome/components/api/api_connection.cpp | 2 +- esphome/components/api/api_server.h | 1 - esphome/components/api/list_entities.cpp | 3 +- esphome/components/api/list_entities.h | 6 +- esphome/components/api/proto.cpp | 1 - esphome/components/api/subscribe_state.cpp | 3 +- esphome/components/api/subscribe_state.h | 6 +- .../components/web_server/list_entities.cpp | 97 +++++++++++++++++++ esphome/components/web_server/list_entities.h | 60 ++++++++++++ esphome/components/web_server/web_server.cpp | 86 +--------------- esphome/components/web_server/web_server.h | 7 +- .../util.cpp => core/component_iterator.cpp} | 56 ++++++----- .../api/util.h => core/component_iterator.h} | 23 +++-- 13 files changed, 217 insertions(+), 134 deletions(-) create mode 100644 esphome/components/web_server/list_entities.cpp create mode 100644 esphome/components/web_server/list_entities.h rename esphome/{components/api/util.cpp => core/component_iterator.cpp} (80%) rename esphome/{components/api/util.h => core/component_iterator.h} (91%) diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index b998ef5929..81f2465b74 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -23,7 +23,7 @@ static const char *const TAG = "api.connection"; static const int ESP32_CAMERA_STOP_STREAM = 5000; APIConnection::APIConnection(std::unique_ptr sock, APIServer *parent) - : parent_(parent), initial_state_iterator_(parent, this), list_entities_iterator_(parent, this) { + : parent_(parent), initial_state_iterator_(this), list_entities_iterator_(this) { this->proto_write_buffer_.reserve(64); #if defined(USE_API_PLAINTEXT) diff --git a/esphome/components/api/api_server.h b/esphome/components/api/api_server.h index 3214da5b3d..fdc46922ad 100644 --- a/esphome/components/api/api_server.h +++ b/esphome/components/api/api_server.h @@ -7,7 +7,6 @@ #include "esphome/components/socket/socket.h" #include "api_pb2.h" #include "api_pb2_service.h" -#include "util.h" #include "list_entities.h" #include "subscribe_state.h" #include "user_services.h" diff --git a/esphome/components/api/list_entities.cpp b/esphome/components/api/list_entities.cpp index fb0dfa3d05..9f55fda617 100644 --- a/esphome/components/api/list_entities.cpp +++ b/esphome/components/api/list_entities.cpp @@ -40,8 +40,7 @@ bool ListEntitiesIterator::on_lock(lock::Lock *a_lock) { return this->client_->s #endif bool ListEntitiesIterator::on_end() { return this->client_->send_list_info_done(); } -ListEntitiesIterator::ListEntitiesIterator(APIServer *server, APIConnection *client) - : ComponentIterator(server), client_(client) {} +ListEntitiesIterator::ListEntitiesIterator(APIConnection *client) : client_(client) {} bool ListEntitiesIterator::on_service(UserServiceDescriptor *service) { auto resp = service->encode_list_service_response(); return this->client_->send_list_entities_services_response(resp); diff --git a/esphome/components/api/list_entities.h b/esphome/components/api/list_entities.h index bfceb39ebf..51c343eb03 100644 --- a/esphome/components/api/list_entities.h +++ b/esphome/components/api/list_entities.h @@ -1,8 +1,8 @@ #pragma once #include "esphome/core/component.h" +#include "esphome/core/component_iterator.h" #include "esphome/core/defines.h" -#include "util.h" namespace esphome { namespace api { @@ -11,7 +11,7 @@ class APIConnection; class ListEntitiesIterator : public ComponentIterator { public: - ListEntitiesIterator(APIServer *server, APIConnection *client); + ListEntitiesIterator(APIConnection *client); #ifdef USE_BINARY_SENSOR bool on_binary_sensor(binary_sensor::BinarySensor *binary_sensor) override; #endif @@ -60,5 +60,3 @@ class ListEntitiesIterator : public ComponentIterator { } // namespace api } // namespace esphome - -#include "api_server.h" diff --git a/esphome/components/api/proto.cpp b/esphome/components/api/proto.cpp index 0ba277d90a..ca7a4c0887 100644 --- a/esphome/components/api/proto.cpp +++ b/esphome/components/api/proto.cpp @@ -1,5 +1,4 @@ #include "proto.h" -#include "util.h" #include "esphome/core/log.h" namespace esphome { diff --git a/esphome/components/api/subscribe_state.cpp b/esphome/components/api/subscribe_state.cpp index 10416ecc5c..ba277502c8 100644 --- a/esphome/components/api/subscribe_state.cpp +++ b/esphome/components/api/subscribe_state.cpp @@ -50,8 +50,7 @@ bool InitialStateIterator::on_select(select::Select *select) { #ifdef USE_LOCK bool InitialStateIterator::on_lock(lock::Lock *a_lock) { return this->client_->send_lock_state(a_lock, a_lock->state); } #endif -InitialStateIterator::InitialStateIterator(APIServer *server, APIConnection *client) - : ComponentIterator(server), client_(client) {} +InitialStateIterator::InitialStateIterator(APIConnection *client) : client_(client) {} } // namespace api } // namespace esphome diff --git a/esphome/components/api/subscribe_state.h b/esphome/components/api/subscribe_state.h index caea013f84..515e1a2d07 100644 --- a/esphome/components/api/subscribe_state.h +++ b/esphome/components/api/subscribe_state.h @@ -1,9 +1,9 @@ #pragma once #include "esphome/core/component.h" +#include "esphome/core/component_iterator.h" #include "esphome/core/controller.h" #include "esphome/core/defines.h" -#include "util.h" namespace esphome { namespace api { @@ -12,7 +12,7 @@ class APIConnection; class InitialStateIterator : public ComponentIterator { public: - InitialStateIterator(APIServer *server, APIConnection *client); + InitialStateIterator(APIConnection *client); #ifdef USE_BINARY_SENSOR bool on_binary_sensor(binary_sensor::BinarySensor *binary_sensor) override; #endif @@ -55,5 +55,3 @@ class InitialStateIterator : public ComponentIterator { } // namespace api } // namespace esphome - -#include "api_server.h" diff --git a/esphome/components/web_server/list_entities.cpp b/esphome/components/web_server/list_entities.cpp new file mode 100644 index 0000000000..6f833a5c83 --- /dev/null +++ b/esphome/components/web_server/list_entities.cpp @@ -0,0 +1,97 @@ +#ifdef USE_ARDUINO + +#include "list_entities.h" +#include "esphome/core/application.h" +#include "esphome/core/log.h" +#include "esphome/core/util.h" + +#include "web_server.h" + +namespace esphome { +namespace web_server { + +ListEntitiesIterator::ListEntitiesIterator(WebServer *web_server) : web_server_(web_server) {} + +#ifdef USE_BINARY_SENSOR +bool ListEntitiesIterator::on_binary_sensor(binary_sensor::BinarySensor *binary_sensor) { + this->web_server_->events_.send( + this->web_server_->binary_sensor_json(binary_sensor, binary_sensor->state, DETAIL_ALL).c_str(), "state"); + return true; +} +#endif +#ifdef USE_COVER +bool ListEntitiesIterator::on_cover(cover::Cover *cover) { + this->web_server_->events_.send(this->web_server_->cover_json(cover, DETAIL_ALL).c_str(), "state"); + return true; +} +#endif +#ifdef USE_FAN +bool ListEntitiesIterator::on_fan(fan::Fan *fan) { + this->web_server_->events_.send(this->web_server_->fan_json(fan, DETAIL_ALL).c_str(), "state"); + return true; +} +#endif +#ifdef USE_LIGHT +bool ListEntitiesIterator::on_light(light::LightState *light) { + this->web_server_->events_.send(this->web_server_->light_json(light, DETAIL_ALL).c_str(), "state"); + return true; +} +#endif +#ifdef USE_SENSOR +bool ListEntitiesIterator::on_sensor(sensor::Sensor *sensor) { + this->web_server_->events_.send(this->web_server_->sensor_json(sensor, sensor->state, DETAIL_ALL).c_str(), "state"); + return true; +} +#endif +#ifdef USE_SWITCH +bool ListEntitiesIterator::on_switch(switch_::Switch *a_switch) { + this->web_server_->events_.send(this->web_server_->switch_json(a_switch, a_switch->state, DETAIL_ALL).c_str(), + "state"); + return true; +} +#endif +#ifdef USE_BUTTON +bool ListEntitiesIterator::on_button(button::Button *button) { + this->web_server_->events_.send(this->web_server_->button_json(button, DETAIL_ALL).c_str(), "state"); + return true; +} +#endif +#ifdef USE_TEXT_SENSOR +bool ListEntitiesIterator::on_text_sensor(text_sensor::TextSensor *text_sensor) { + this->web_server_->events_.send( + this->web_server_->text_sensor_json(text_sensor, text_sensor->state, DETAIL_ALL).c_str(), "state"); + return true; +} +#endif +#ifdef USE_LOCK +bool ListEntitiesIterator::on_lock(lock::Lock *a_lock) { + this->web_server_->events_.send(this->web_server_->lock_json(a_lock, a_lock->state, DETAIL_ALL).c_str(), "state"); + return true; +} +#endif + +#ifdef USE_CLIMATE +bool ListEntitiesIterator::on_climate(climate::Climate *climate) { + this->web_server_->events_.send(this->web_server_->climate_json(climate, DETAIL_ALL).c_str(), "state"); + return true; +} +#endif + +#ifdef USE_NUMBER +bool ListEntitiesIterator::on_number(number::Number *number) { + this->web_server_->events_.send(this->web_server_->number_json(number, number->state, DETAIL_ALL).c_str(), "state"); + return true; +} +#endif + +#ifdef USE_SELECT +bool ListEntitiesIterator::on_select(select::Select *select) { + this->web_server_->events_.send(this->web_server_->select_json(select, select->state, DETAIL_ALL).c_str(), "state"); + return true; +} +#endif + +} // namespace web_server +} // namespace esphome + +#endif // USE_ARDUINO diff --git a/esphome/components/web_server/list_entities.h b/esphome/components/web_server/list_entities.h new file mode 100644 index 0000000000..85868caff8 --- /dev/null +++ b/esphome/components/web_server/list_entities.h @@ -0,0 +1,60 @@ +#pragma once + +#ifdef USE_ARDUINO + +#include "esphome/core/component.h" +#include "esphome/core/component_iterator.h" +#include "esphome/core/defines.h" +namespace esphome { +namespace web_server { + +class WebServer; + +class ListEntitiesIterator : public ComponentIterator { + public: + ListEntitiesIterator(WebServer *web_server); +#ifdef USE_BINARY_SENSOR + bool on_binary_sensor(binary_sensor::BinarySensor *binary_sensor) override; +#endif +#ifdef USE_COVER + bool on_cover(cover::Cover *cover) override; +#endif +#ifdef USE_FAN + bool on_fan(fan::Fan *fan) override; +#endif +#ifdef USE_LIGHT + bool on_light(light::LightState *light) override; +#endif +#ifdef USE_SENSOR + bool on_sensor(sensor::Sensor *sensor) override; +#endif +#ifdef USE_SWITCH + bool on_switch(switch_::Switch *a_switch) override; +#endif +#ifdef USE_BUTTON + bool on_button(button::Button *button) override; +#endif +#ifdef USE_TEXT_SENSOR + bool on_text_sensor(text_sensor::TextSensor *text_sensor) override; +#endif +#ifdef USE_CLIMATE + bool on_climate(climate::Climate *climate) override; +#endif +#ifdef USE_NUMBER + bool on_number(number::Number *number) override; +#endif +#ifdef USE_SELECT + bool on_select(select::Select *select) override; +#endif +#ifdef USE_LOCK + bool on_lock(lock::Lock *a_lock) override; +#endif + + protected: + WebServer *web_server_; +}; + +} // namespace web_server +} // namespace esphome + +#endif // USE_ARDUINO diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index 278aeab937..0dfd608661 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -1,6 +1,7 @@ #ifdef USE_ARDUINO #include "web_server.h" + #include "esphome/core/log.h" #include "esphome/core/application.h" #include "esphome/core/entity_base.h" @@ -17,7 +18,7 @@ #endif #ifdef USE_LOGGER -#include +#include "esphome/components/logger/logger.h" #endif #ifdef USE_FAN @@ -106,87 +107,7 @@ void WebServer::setup() { }).c_str(), "ping", millis(), 30000); -#ifdef USE_SENSOR - for (auto *obj : App.get_sensors()) { - if (this->include_internal_ || !obj->is_internal()) - client->send(this->sensor_json(obj, obj->state, DETAIL_ALL).c_str(), "state"); - } -#endif - -#ifdef USE_SWITCH - for (auto *obj : App.get_switches()) { - if (this->include_internal_ || !obj->is_internal()) - client->send(this->switch_json(obj, obj->state, DETAIL_ALL).c_str(), "state"); - } -#endif - -#ifdef USE_BUTTON - for (auto *obj : App.get_buttons()) - client->send(this->button_json(obj, DETAIL_ALL).c_str(), "state"); -#endif - -#ifdef USE_BINARY_SENSOR - for (auto *obj : App.get_binary_sensors()) { - if (this->include_internal_ || !obj->is_internal()) - client->send(this->binary_sensor_json(obj, obj->state, DETAIL_ALL).c_str(), "state"); - } -#endif - -#ifdef USE_FAN - for (auto *obj : App.get_fans()) { - if (this->include_internal_ || !obj->is_internal()) - client->send(this->fan_json(obj, DETAIL_ALL).c_str(), "state"); - } -#endif - -#ifdef USE_LIGHT - for (auto *obj : App.get_lights()) { - if (this->include_internal_ || !obj->is_internal()) - client->send(this->light_json(obj, DETAIL_ALL).c_str(), "state"); - } -#endif - -#ifdef USE_TEXT_SENSOR - for (auto *obj : App.get_text_sensors()) { - if (this->include_internal_ || !obj->is_internal()) - client->send(this->text_sensor_json(obj, obj->state, DETAIL_ALL).c_str(), "state"); - } -#endif - -#ifdef USE_COVER - for (auto *obj : App.get_covers()) { - if (this->include_internal_ || !obj->is_internal()) - client->send(this->cover_json(obj, DETAIL_ALL).c_str(), "state"); - } -#endif - -#ifdef USE_NUMBER - for (auto *obj : App.get_numbers()) { - if (this->include_internal_ || !obj->is_internal()) - client->send(this->number_json(obj, obj->state, DETAIL_ALL).c_str(), "state"); - } -#endif - -#ifdef USE_SELECT - for (auto *obj : App.get_selects()) { - if (this->include_internal_ || !obj->is_internal()) - client->send(this->select_json(obj, obj->state, DETAIL_ALL).c_str(), "state"); - } -#endif - -#ifdef USE_CLIMATE - for (auto *obj : App.get_climates()) { - if (this->include_internal_ || !obj->is_internal()) - client->send(this->climate_json(obj, DETAIL_ALL).c_str(), "state"); - } -#endif - -#ifdef USE_LOCK - for (auto *obj : App.get_locks()) { - if (this->include_internal_ || !obj->is_internal()) - client->send(this->lock_json(obj, obj->state, DETAIL_ALL).c_str(), "state"); - } -#endif + this->entities_iterator_.begin(this->include_internal_); }); #ifdef USE_LOGGER @@ -203,6 +124,7 @@ void WebServer::setup() { this->set_interval(10000, [this]() { this->events_.send("", "ping", millis(), 30000); }); } +void WebServer::loop() { this->entities_iterator_.advance(); } void WebServer::dump_config() { ESP_LOGCONFIG(TAG, "Web Server:"); ESP_LOGCONFIG(TAG, " Address: %s:%u", network::get_use_address().c_str(), this->base_->get_port()); diff --git a/esphome/components/web_server/web_server.h b/esphome/components/web_server/web_server.h index 2717997f60..73813ecfa1 100644 --- a/esphome/components/web_server/web_server.h +++ b/esphome/components/web_server/web_server.h @@ -2,6 +2,8 @@ #ifdef USE_ARDUINO +#include "list_entities.h" + #include "esphome/components/web_server_base/web_server_base.h" #include "esphome/core/component.h" #include "esphome/core/controller.h" @@ -32,7 +34,7 @@ enum JsonDetail { DETAIL_ALL, DETAIL_STATE }; */ class WebServer : public Controller, public Component, public AsyncWebHandler { public: - WebServer(web_server_base::WebServerBase *base) : base_(base) {} + WebServer(web_server_base::WebServerBase *base) : base_(base), entities_iterator_(ListEntitiesIterator(this)) {} /** Set the URL to the CSS that's sent to each client. Defaults to * https://esphome.io/_static/webserver-v1.min.css @@ -76,6 +78,7 @@ class WebServer : public Controller, public Component, public AsyncWebHandler { // (In most use cases you won't need these) /// Setup the internal web server and register handlers. void setup() override; + void loop() override; void dump_config() override; @@ -217,8 +220,10 @@ class WebServer : public Controller, public Component, public AsyncWebHandler { bool isRequestHandlerTrivial() override; protected: + friend ListEntitiesIterator; web_server_base::WebServerBase *base_; AsyncEventSource events_{"/events"}; + ListEntitiesIterator entities_iterator_; const char *css_url_{nullptr}; const char *css_include_{nullptr}; const char *js_url_{nullptr}; diff --git a/esphome/components/api/util.cpp b/esphome/core/component_iterator.cpp similarity index 80% rename from esphome/components/api/util.cpp rename to esphome/core/component_iterator.cpp index fd55f89f9b..4781607a2d 100644 --- a/esphome/components/api/util.cpp +++ b/esphome/core/component_iterator.cpp @@ -1,16 +1,18 @@ -#include "util.h" -#include "api_server.h" -#include "user_services.h" -#include "esphome/core/log.h" +#include "component_iterator.h" + #include "esphome/core/application.h" -namespace esphome { -namespace api { +#ifdef USE_API +#include "esphome/components/api/api_server.h" +#include "esphome/components/api/user_services.h" +#endif -ComponentIterator::ComponentIterator(APIServer *server) : server_(server) {} -void ComponentIterator::begin() { +namespace esphome { + +void ComponentIterator::begin(bool include_internal) { this->state_ = IteratorState::BEGIN; this->at_ = 0; + this->include_internal_ = include_internal; } void ComponentIterator::advance() { bool advance_platform = false; @@ -32,7 +34,7 @@ void ComponentIterator::advance() { advance_platform = true; } else { auto *binary_sensor = App.get_binary_sensors()[this->at_]; - if (binary_sensor->is_internal()) { + if (binary_sensor->is_internal() && !this->include_internal_) { success = true; break; } else { @@ -47,7 +49,7 @@ void ComponentIterator::advance() { advance_platform = true; } else { auto *cover = App.get_covers()[this->at_]; - if (cover->is_internal()) { + if (cover->is_internal() && !this->include_internal_) { success = true; break; } else { @@ -62,7 +64,7 @@ void ComponentIterator::advance() { advance_platform = true; } else { auto *fan = App.get_fans()[this->at_]; - if (fan->is_internal()) { + if (fan->is_internal() && !this->include_internal_) { success = true; break; } else { @@ -77,7 +79,7 @@ void ComponentIterator::advance() { advance_platform = true; } else { auto *light = App.get_lights()[this->at_]; - if (light->is_internal()) { + if (light->is_internal() && !this->include_internal_) { success = true; break; } else { @@ -92,7 +94,7 @@ void ComponentIterator::advance() { advance_platform = true; } else { auto *sensor = App.get_sensors()[this->at_]; - if (sensor->is_internal()) { + if (sensor->is_internal() && !this->include_internal_) { success = true; break; } else { @@ -107,7 +109,7 @@ void ComponentIterator::advance() { advance_platform = true; } else { auto *a_switch = App.get_switches()[this->at_]; - if (a_switch->is_internal()) { + if (a_switch->is_internal() && !this->include_internal_) { success = true; break; } else { @@ -122,7 +124,7 @@ void ComponentIterator::advance() { advance_platform = true; } else { auto *button = App.get_buttons()[this->at_]; - if (button->is_internal()) { + if (button->is_internal() && !this->include_internal_) { success = true; break; } else { @@ -137,7 +139,7 @@ void ComponentIterator::advance() { advance_platform = true; } else { auto *text_sensor = App.get_text_sensors()[this->at_]; - if (text_sensor->is_internal()) { + if (text_sensor->is_internal() && !this->include_internal_) { success = true; break; } else { @@ -146,20 +148,22 @@ void ComponentIterator::advance() { } break; #endif +#ifdef USE_API case IteratorState ::SERVICE: - if (this->at_ >= this->server_->get_user_services().size()) { + if (this->at_ >= api::global_api_server->get_user_services().size()) { advance_platform = true; } else { - auto *service = this->server_->get_user_services()[this->at_]; + auto *service = api::global_api_server->get_user_services()[this->at_]; success = this->on_service(service); } break; +#endif #ifdef USE_ESP32_CAMERA case IteratorState::CAMERA: if (esp32_camera::global_esp32_camera == nullptr) { advance_platform = true; } else { - if (esp32_camera::global_esp32_camera->is_internal()) { + if (esp32_camera::global_esp32_camera->is_internal() && !this->include_internal_) { advance_platform = success = true; break; } else { @@ -174,7 +178,7 @@ void ComponentIterator::advance() { advance_platform = true; } else { auto *climate = App.get_climates()[this->at_]; - if (climate->is_internal()) { + if (climate->is_internal() && !this->include_internal_) { success = true; break; } else { @@ -189,7 +193,7 @@ void ComponentIterator::advance() { advance_platform = true; } else { auto *number = App.get_numbers()[this->at_]; - if (number->is_internal()) { + if (number->is_internal() && !this->include_internal_) { success = true; break; } else { @@ -204,7 +208,7 @@ void ComponentIterator::advance() { advance_platform = true; } else { auto *select = App.get_selects()[this->at_]; - if (select->is_internal()) { + if (select->is_internal() && !this->include_internal_) { success = true; break; } else { @@ -219,7 +223,7 @@ void ComponentIterator::advance() { advance_platform = true; } else { auto *a_lock = App.get_locks()[this->at_]; - if (a_lock->is_internal()) { + if (a_lock->is_internal() && !this->include_internal_) { success = true; break; } else { @@ -244,10 +248,10 @@ void ComponentIterator::advance() { } bool ComponentIterator::on_end() { return true; } bool ComponentIterator::on_begin() { return true; } -bool ComponentIterator::on_service(UserServiceDescriptor *service) { return true; } +#ifdef USE_API +bool ComponentIterator::on_service(api::UserServiceDescriptor *service) { return true; } +#endif #ifdef USE_ESP32_CAMERA bool ComponentIterator::on_camera(esp32_camera::ESP32Camera *camera) { return true; } #endif - -} // namespace api } // namespace esphome diff --git a/esphome/components/api/util.h b/esphome/core/component_iterator.h similarity index 91% rename from esphome/components/api/util.h rename to esphome/core/component_iterator.h index 9204b0829e..bd95fe95e1 100644 --- a/esphome/components/api/util.h +++ b/esphome/core/component_iterator.h @@ -1,23 +1,24 @@ #pragma once -#include "esphome/core/helpers.h" #include "esphome/core/component.h" #include "esphome/core/controller.h" +#include "esphome/core/helpers.h" + #ifdef USE_ESP32_CAMERA #include "esphome/components/esp32_camera/esp32_camera.h" #endif namespace esphome { -namespace api { -class APIServer; +#ifdef USE_API +namespace api { class UserServiceDescriptor; +} // namespace api +#endif class ComponentIterator { public: - ComponentIterator(APIServer *server); - - void begin(); + void begin(bool include_internal = false); void advance(); virtual bool on_begin(); #ifdef USE_BINARY_SENSOR @@ -44,7 +45,9 @@ class ComponentIterator { #ifdef USE_TEXT_SENSOR virtual bool on_text_sensor(text_sensor::TextSensor *text_sensor) = 0; #endif - virtual bool on_service(UserServiceDescriptor *service); +#ifdef USE_API + virtual bool on_service(api::UserServiceDescriptor *service); +#endif #ifdef USE_ESP32_CAMERA virtual bool on_camera(esp32_camera::ESP32Camera *camera); #endif @@ -90,7 +93,9 @@ class ComponentIterator { #ifdef USE_TEXT_SENSOR TEXT_SENSOR, #endif +#ifdef USE_API SERVICE, +#endif #ifdef USE_ESP32_CAMERA CAMERA, #endif @@ -109,9 +114,7 @@ class ComponentIterator { MAX, } state_{IteratorState::NONE}; size_t at_{0}; - - APIServer *server_; + bool include_internal_{false}; }; -} // namespace api } // namespace esphome From 4e4a512107f714bac29fab43a2fd6ddb7dcea308 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 23 Mar 2022 09:46:25 +1300 Subject: [PATCH 3/5] Reserve less memory for json (#3289) --- esphome/components/json/json_util.cpp | 60 +++++++++++++++++++-------- 1 file changed, 43 insertions(+), 17 deletions(-) diff --git a/esphome/components/json/json_util.cpp b/esphome/components/json/json_util.cpp index 9acba76597..2070b312e8 100644 --- a/esphome/components/json/json_util.cpp +++ b/esphome/components/json/json_util.cpp @@ -16,16 +16,24 @@ static const char *const TAG = "json"; static std::vector global_json_build_buffer; // NOLINT std::string build_json(const json_build_t &f) { - // Here we are allocating as much heap memory as available minus 2kb to be safe + // Here we are allocating up to 5kb of memory, + // with the heap size minus 2kb to be safe if less than 5kb // as we can not have a true dynamic sized document. // The excess memory is freed below with `shrinkToFit()` #ifdef USE_ESP8266 - const size_t free_heap = ESP.getMaxFreeBlockSize() - 2048; // NOLINT(readability-static-accessed-through-instance) + const size_t free_heap = ESP.getMaxFreeBlockSize(); // NOLINT(readability-static-accessed-through-instance) #elif defined(USE_ESP32) - const size_t free_heap = heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL) - 2048; + const size_t free_heap = heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL); #endif - DynamicJsonDocument json_document(free_heap); + const size_t request_size = std::min(free_heap - 2048, (size_t) 5120); + + DynamicJsonDocument json_document(request_size); + if (json_document.memoryPool().buffer() == nullptr) { + ESP_LOGE(TAG, "Could not allocate memory for JSON document! Requested %u bytes, largest free heap block: %u bytes", + request_size, free_heap); + return "{}"; + } JsonObject root = json_document.to(); f(root); json_document.shrinkToFit(); @@ -36,27 +44,45 @@ std::string build_json(const json_build_t &f) { } void parse_json(const std::string &data, const json_parse_t &f) { - // Here we are allocating as much heap memory as available minus 2kb to be safe + // Here we are allocating 1.5 times the data size, + // with the heap size minus 2kb to be safe if less than that // as we can not have a true dynamic sized document. // The excess memory is freed below with `shrinkToFit()` #ifdef USE_ESP8266 - const size_t free_heap = ESP.getMaxFreeBlockSize() - 2048; // NOLINT(readability-static-accessed-through-instance) + const size_t free_heap = ESP.getMaxFreeBlockSize(); // NOLINT(readability-static-accessed-through-instance) #elif defined(USE_ESP32) - const size_t free_heap = heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL) - 2048; + const size_t free_heap = heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL); #endif + bool pass = false; + do { + const size_t request_size = std::min(free_heap - 2048, (size_t)(data.size() * 1.5)); - DynamicJsonDocument json_document(free_heap); - DeserializationError err = deserializeJson(json_document, data); - json_document.shrinkToFit(); + DynamicJsonDocument json_document(request_size); + if (json_document.memoryPool().buffer() == nullptr) { + ESP_LOGE(TAG, "Could not allocate memory for JSON document! Requested %u bytes, free heap: %u", request_size, + free_heap); + return; + } + DeserializationError err = deserializeJson(json_document, data); + json_document.shrinkToFit(); - JsonObject root = json_document.as(); + JsonObject root = json_document.as(); - if (err) { - ESP_LOGW(TAG, "Parsing JSON failed."); - return; - } - - f(root); + if (err == DeserializationError::Ok) { + pass = true; + f(root); + } else if (err == DeserializationError::NoMemory) { + if (request_size * 2 >= free_heap) { + ESP_LOGE(TAG, "Can not allocate more memory for deserialization. Consider making source string smaller"); + return; + } + ESP_LOGW(TAG, "Increasing memory allocation."); + continue; + } else { + ESP_LOGE(TAG, "JSON parse error: %s", err.c_str()); + return; + } + } while (!pass); } } // namespace json From 9a9d5964eeda7fda76900ec50109f4465f092871 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 23 Mar 2022 11:12:22 +1300 Subject: [PATCH 4/5] Add small delay before setting up app in safe mode (#3323) --- esphome/components/ota/ota_component.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/components/ota/ota_component.cpp b/esphome/components/ota/ota_component.cpp index 37da3bdc44..3138c495da 100644 --- a/esphome/components/ota/ota_component.cpp +++ b/esphome/components/ota/ota_component.cpp @@ -473,6 +473,8 @@ bool OTAComponent::should_enter_safe_mode(uint8_t num_attempts, uint32_t enable_ App.reboot(); }); + // Delay here to allow power to stabilise before Wi-Fi/Ethernet is initialised. + delay(100); // NOLINT App.setup(); ESP_LOGI(TAG, "Waiting for OTA attempt."); From 24029cc918ea6f9bfbdcfb2f0f4a932dd5c460c8 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 23 Mar 2022 12:26:02 +1300 Subject: [PATCH 5/5] Bump version to 2022.3.1 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index e9e3809b2c..8bf303db09 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2022.3.0" +__version__ = "2022.3.1" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"