diff --git a/esphome/components/api/__init__.py b/esphome/components/api/__init__.py index 9cbab8164f..f48a7d93be 100644 --- a/esphome/components/api/__init__.py +++ b/esphome/components/api/__init__.py @@ -53,6 +53,7 @@ SERVICE_ARG_NATIVE_TYPES = { CONF_ENCRYPTION = "encryption" CONF_BATCH_DELAY = "batch_delay" CONF_CUSTOM_SERVICES = "custom_services" +CONF_HOMEASSISTANT_STATES = "homeassistant_states" def validate_encryption_key(value): @@ -118,6 +119,7 @@ CONFIG_SCHEMA = cv.All( cv.Range(max=cv.TimePeriod(milliseconds=65535)), ), cv.Optional(CONF_CUSTOM_SERVICES, default=False): cv.boolean, + cv.Optional(CONF_HOMEASSISTANT_STATES, default=False): cv.boolean, cv.Optional(CONF_ON_CLIENT_CONNECTED): automation.validate_automation( single=True ), @@ -146,6 +148,9 @@ async def to_code(config): if config.get(CONF_ACTIONS) or config[CONF_CUSTOM_SERVICES]: cg.add_define("USE_API_SERVICES") + if config[CONF_HOMEASSISTANT_STATES]: + cg.add_define("USE_API_HOMEASSISTANT_STATES") + if actions := config.get(CONF_ACTIONS, []): for conf in actions: template_args = [] diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index 93e84702e2..5956c8b0b9 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -781,11 +781,13 @@ message HomeassistantServiceResponse { message SubscribeHomeAssistantStatesRequest { option (id) = 38; option (source) = SOURCE_CLIENT; + option (ifdef) = "USE_API_HOMEASSISTANT_STATES"; } message SubscribeHomeAssistantStateResponse { option (id) = 39; option (source) = SOURCE_SERVER; + option (ifdef) = "USE_API_HOMEASSISTANT_STATES"; string entity_id = 1; string attribute = 2; bool once = 3; @@ -795,6 +797,7 @@ message HomeAssistantStateResponse { option (id) = 40; option (source) = SOURCE_CLIENT; option (no_delay) = true; + option (ifdef) = "USE_API_HOMEASSISTANT_STATES"; string entity_id = 1; string state = 2; diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 76713c54c8..0d3b99cd41 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -242,6 +242,7 @@ void APIConnection::loop() { } #endif +#ifdef USE_API_HOMEASSISTANT_STATES if (state_subs_at_ >= 0) { const auto &subs = this->parent_->get_state_subs(); if (state_subs_at_ < static_cast(subs.size())) { @@ -259,6 +260,7 @@ void APIConnection::loop() { state_subs_at_ = -1; } } +#endif } bool APIConnection::send_disconnect_response(const DisconnectRequest &msg) { @@ -1512,6 +1514,7 @@ bool APIConnection::send_device_info_response(const DeviceInfoRequest &msg) { return this->send_message(resp, DeviceInfoResponse::MESSAGE_TYPE); } +#ifdef USE_API_HOMEASSISTANT_STATES void APIConnection::on_home_assistant_state_response(const HomeAssistantStateResponse &msg) { for (auto &it : this->parent_->get_state_subs()) { if (it.entity_id == msg.entity_id && it.attribute.value() == msg.attribute) { @@ -1519,6 +1522,7 @@ void APIConnection::on_home_assistant_state_response(const HomeAssistantStateRes } } } +#endif #ifdef USE_API_SERVICES void APIConnection::execute_service(const ExecuteServiceRequest &msg) { bool found = false; @@ -1550,9 +1554,11 @@ bool APIConnection::send_noise_encryption_set_key_response(const NoiseEncryption return this->send_message(resp, NoiseEncryptionSetKeyResponse::MESSAGE_TYPE); } #endif +#ifdef USE_API_HOMEASSISTANT_STATES void APIConnection::subscribe_home_assistant_states(const SubscribeHomeAssistantStatesRequest &msg) { state_subs_at_ = 0; } +#endif bool APIConnection::try_to_clear_buffer(bool log_out_of_space) { if (this->flags_.remove) return false; @@ -1590,10 +1596,12 @@ bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint8_t message_type) { // Do not set last_traffic_ on send return true; } +#ifdef USE_API_PASSWORD void APIConnection::on_unauthenticated_access() { this->on_fatal_error(); ESP_LOGD(TAG, "%s access without authentication", this->get_client_combined_info().c_str()); } +#endif void APIConnection::on_no_setup_connection() { this->on_fatal_error(); ESP_LOGD(TAG, "%s access without full connection", this->get_client_combined_info().c_str()); diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index 6214d5ba82..4f4b44b0ad 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -188,7 +188,9 @@ class APIConnection : public APIServerConnection { // we initiated ping this->flags_.sent_ping = false; } +#ifdef USE_API_HOMEASSISTANT_STATES void on_home_assistant_state_response(const HomeAssistantStateResponse &msg) override; +#endif #ifdef USE_HOMEASSISTANT_TIME void on_get_time_response(const GetTimeResponse &value) override; #endif @@ -210,7 +212,9 @@ class APIConnection : public APIServerConnection { void subscribe_homeassistant_services(const SubscribeHomeassistantServicesRequest &msg) override { this->flags_.service_call_subscription = true; } +#ifdef USE_API_HOMEASSISTANT_STATES void subscribe_home_assistant_states(const SubscribeHomeAssistantStatesRequest &msg) override; +#endif bool send_get_time_response(const GetTimeRequest &msg) override; #ifdef USE_API_SERVICES void execute_service(const ExecuteServiceRequest &msg) override; @@ -228,7 +232,9 @@ class APIConnection : public APIServerConnection { } uint8_t get_log_subscription_level() const { return this->flags_.log_subscription; } void on_fatal_error() override; +#ifdef USE_API_PASSWORD void on_unauthenticated_access() override; +#endif void on_no_setup_connection() override; ProtoWriteBuffer create_buffer(uint32_t reserve_size) override { // FIXME: ensure no recursive writes can happen @@ -492,7 +498,9 @@ class APIConnection : public APIServerConnection { // Group 4: 4-byte types uint32_t last_traffic_; +#ifdef USE_API_HOMEASSISTANT_STATES int state_subs_at_ = -1; +#endif // Function pointer type for message encoding using MessageCreatorPtr = uint16_t (*)(EntityBase *, APIConnection *, uint32_t remaining_size, bool is_single); diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 6d2e17dc27..e2d1cfebd4 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -871,6 +871,7 @@ void HomeassistantServiceResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_repeated_message(total_size, 1, this->variables); ProtoSize::add_bool_field(total_size, 1, this->is_event); } +#ifdef USE_API_HOMEASSISTANT_STATES void SubscribeHomeAssistantStateResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_string(1, this->entity_id_ref_); buffer.encode_string(2, this->attribute_ref_); @@ -897,6 +898,7 @@ bool HomeAssistantStateResponse::decode_length(uint32_t field_id, ProtoLengthDel } return true; } +#endif bool GetTimeResponse::decode_32bit(uint32_t field_id, Proto32Bit value) { switch (field_id) { case 1: diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index 756c320ff4..e7f8237808 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -1092,6 +1092,7 @@ class HomeassistantServiceResponse : public ProtoMessage { protected: }; +#ifdef USE_API_HOMEASSISTANT_STATES class SubscribeHomeAssistantStatesRequest : public ProtoMessage { public: static constexpr uint8_t MESSAGE_TYPE = 38; @@ -1142,6 +1143,7 @@ class HomeAssistantStateResponse : public ProtoDecodableMessage { protected: bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; }; +#endif class GetTimeRequest : public ProtoMessage { public: static constexpr uint8_t MESSAGE_TYPE = 36; diff --git a/esphome/components/api/api_pb2_dump.cpp b/esphome/components/api/api_pb2_dump.cpp index 5db9b79cfa..d7f9f63f5f 100644 --- a/esphome/components/api/api_pb2_dump.cpp +++ b/esphome/components/api/api_pb2_dump.cpp @@ -1066,6 +1066,7 @@ void HomeassistantServiceResponse::dump_to(std::string &out) const { } dump_field(out, "is_event", this->is_event); } +#ifdef USE_API_HOMEASSISTANT_STATES void SubscribeHomeAssistantStatesRequest::dump_to(std::string &out) const { out.append("SubscribeHomeAssistantStatesRequest {}"); } @@ -1081,6 +1082,7 @@ void HomeAssistantStateResponse::dump_to(std::string &out) const { dump_field(out, "state", this->state); dump_field(out, "attribute", this->attribute); } +#endif void GetTimeRequest::dump_to(std::string &out) const { out.append("GetTimeRequest {}"); } void GetTimeResponse::dump_to(std::string &out) const { dump_field(out, "epoch_seconds", this->epoch_seconds); } #ifdef USE_API_SERVICES diff --git a/esphome/components/api/api_pb2_service.cpp b/esphome/components/api/api_pb2_service.cpp index 3d75cfe162..415e4ff91c 100644 --- a/esphome/components/api/api_pb2_service.cpp +++ b/esphome/components/api/api_pb2_service.cpp @@ -176,6 +176,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, this->on_get_time_response(msg); break; } +#ifdef USE_API_HOMEASSISTANT_STATES case SubscribeHomeAssistantStatesRequest::MESSAGE_TYPE: { SubscribeHomeAssistantStatesRequest msg; // Empty message: no decode needed @@ -185,6 +186,8 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, this->on_subscribe_home_assistant_states_request(msg); break; } +#endif +#ifdef USE_API_HOMEASSISTANT_STATES case HomeAssistantStateResponse::MESSAGE_TYPE: { HomeAssistantStateResponse msg; msg.decode(msg_data, msg_size); @@ -194,6 +197,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, this->on_home_assistant_state_response(msg); break; } +#endif #ifdef USE_API_SERVICES case ExecuteServiceRequest::MESSAGE_TYPE: { ExecuteServiceRequest msg; @@ -641,11 +645,13 @@ void APIServerConnection::on_subscribe_homeassistant_services_request( this->subscribe_homeassistant_services(msg); } } +#ifdef USE_API_HOMEASSISTANT_STATES void APIServerConnection::on_subscribe_home_assistant_states_request(const SubscribeHomeAssistantStatesRequest &msg) { if (this->check_authenticated_()) { this->subscribe_home_assistant_states(msg); } } +#endif void APIServerConnection::on_get_time_request(const GetTimeRequest &msg) { if (this->check_connection_setup_() && !this->send_get_time_response(msg)) { this->on_fatal_error(); diff --git a/esphome/components/api/api_pb2_service.h b/esphome/components/api/api_pb2_service.h index 38008197fa..19ed85aa0b 100644 --- a/esphome/components/api/api_pb2_service.h +++ b/esphome/components/api/api_pb2_service.h @@ -62,9 +62,13 @@ class APIServerConnectionBase : public ProtoService { virtual void on_subscribe_homeassistant_services_request(const SubscribeHomeassistantServicesRequest &value){}; +#ifdef USE_API_HOMEASSISTANT_STATES virtual void on_subscribe_home_assistant_states_request(const SubscribeHomeAssistantStatesRequest &value){}; +#endif +#ifdef USE_API_HOMEASSISTANT_STATES virtual void on_home_assistant_state_response(const HomeAssistantStateResponse &value){}; +#endif virtual void on_get_time_request(const GetTimeRequest &value){}; virtual void on_get_time_response(const GetTimeResponse &value){}; @@ -215,7 +219,9 @@ class APIServerConnection : public APIServerConnectionBase { virtual void subscribe_states(const SubscribeStatesRequest &msg) = 0; virtual void subscribe_logs(const SubscribeLogsRequest &msg) = 0; virtual void subscribe_homeassistant_services(const SubscribeHomeassistantServicesRequest &msg) = 0; +#ifdef USE_API_HOMEASSISTANT_STATES virtual void subscribe_home_assistant_states(const SubscribeHomeAssistantStatesRequest &msg) = 0; +#endif virtual bool send_get_time_response(const GetTimeRequest &msg) = 0; #ifdef USE_API_SERVICES virtual void execute_service(const ExecuteServiceRequest &msg) = 0; @@ -333,7 +339,9 @@ class APIServerConnection : public APIServerConnectionBase { void on_subscribe_states_request(const SubscribeStatesRequest &msg) override; void on_subscribe_logs_request(const SubscribeLogsRequest &msg) override; void on_subscribe_homeassistant_services_request(const SubscribeHomeassistantServicesRequest &msg) override; +#ifdef USE_API_HOMEASSISTANT_STATES void on_subscribe_home_assistant_states_request(const SubscribeHomeAssistantStatesRequest &msg) override; +#endif void on_get_time_request(const GetTimeRequest &msg) override; #ifdef USE_API_SERVICES void on_execute_service_request(const ExecuteServiceRequest &msg) override; diff --git a/esphome/components/api/api_server.cpp b/esphome/components/api/api_server.cpp index 6d1729e611..0454315760 100644 --- a/esphome/components/api/api_server.cpp +++ b/esphome/components/api/api_server.cpp @@ -375,6 +375,7 @@ void APIServer::send_homeassistant_service_call(const HomeassistantServiceRespon } } +#ifdef USE_API_HOMEASSISTANT_STATES void APIServer::subscribe_home_assistant_state(std::string entity_id, optional attribute, std::function f) { this->state_subs_.push_back(HomeAssistantStateSubscription{ @@ -398,6 +399,7 @@ void APIServer::get_home_assistant_state(std::string entity_id, optional &APIServer::get_state_subs() const { return this->state_subs_; } +#endif uint16_t APIServer::get_port() const { return this->port_; } diff --git a/esphome/components/api/api_server.h b/esphome/components/api/api_server.h index 54663a013f..22e9573d7e 100644 --- a/esphome/components/api/api_server.h +++ b/esphome/components/api/api_server.h @@ -126,6 +126,7 @@ class APIServer : public Component, public Controller { bool is_connected() const; +#ifdef USE_API_HOMEASSISTANT_STATES struct HomeAssistantStateSubscription { std::string entity_id; optional attribute; @@ -138,6 +139,7 @@ class APIServer : public Component, public Controller { void get_home_assistant_state(std::string entity_id, optional attribute, std::function f); const std::vector &get_state_subs() const; +#endif #ifdef USE_API_SERVICES const std::vector &get_user_services() const { return this->user_services_; } #endif @@ -171,7 +173,9 @@ class APIServer : public Component, public Controller { std::string password_; #endif std::vector shared_write_buffer_; // Shared proto write buffer for all connections +#ifdef USE_API_HOMEASSISTANT_STATES std::vector state_subs_; +#endif #ifdef USE_API_SERVICES std::vector user_services_; #endif diff --git a/esphome/components/api/custom_api_device.h b/esphome/components/api/custom_api_device.h index 73c7804ff3..e9e39a0772 100644 --- a/esphome/components/api/custom_api_device.h +++ b/esphome/components/api/custom_api_device.h @@ -83,6 +83,7 @@ class CustomAPIDevice { } #endif +#ifdef USE_API_HOMEASSISTANT_STATES /** Subscribe to the state (or attribute state) of an entity from Home Assistant. * * Usage: @@ -134,6 +135,7 @@ class CustomAPIDevice { auto f = std::bind(callback, (T *) this, entity_id, std::placeholders::_1); global_api_server->subscribe_home_assistant_state(entity_id, optional(attribute), f); } +#endif /** Call a Home Assistant service from ESPHome. * diff --git a/esphome/components/api/proto.h b/esphome/components/api/proto.h index 44f9716516..771eaa98d1 100644 --- a/esphome/components/api/proto.h +++ b/esphome/components/api/proto.h @@ -860,7 +860,9 @@ class ProtoService { virtual bool is_authenticated() = 0; virtual bool is_connection_setup() = 0; virtual void on_fatal_error() = 0; +#ifdef USE_API_PASSWORD virtual void on_unauthenticated_access() = 0; +#endif virtual void on_no_setup_connection() = 0; /** * Create a buffer with a reserved size. @@ -898,6 +900,7 @@ class ProtoService { } bool check_authenticated_() { +#ifdef USE_API_PASSWORD if (!this->check_connection_setup_()) { return false; } @@ -906,6 +909,9 @@ class ProtoService { return false; } return true; +#else + return this->check_connection_setup_(); +#endif } }; diff --git a/esphome/components/display/__init__.py b/esphome/components/display/__init__.py index 12c63231e7..81f2536e96 100644 --- a/esphome/components/display/__init__.py +++ b/esphome/components/display/__init__.py @@ -51,8 +51,7 @@ DISPLAY_ROTATIONS = { def validate_rotation(value): value = cv.string(value) - if value.endswith("°"): - value = value[:-1] + value = value.removesuffix("°") return cv.enum(DISPLAY_ROTATIONS, int=True)(value) diff --git a/esphome/components/homeassistant/__init__.py b/esphome/components/homeassistant/__init__.py index 223d6c18c3..7b23775b47 100644 --- a/esphome/components/homeassistant/__init__.py +++ b/esphome/components/homeassistant/__init__.py @@ -38,3 +38,4 @@ def setup_home_assistant_entity(var, config): cg.add(var.set_entity_id(config[CONF_ENTITY_ID])) if CONF_ATTRIBUTE in config: cg.add(var.set_attribute(config[CONF_ATTRIBUTE])) + cg.add_define("USE_API_HOMEASSISTANT_STATES") diff --git a/esphome/components/i2c/i2c_bus_esp_idf.cpp b/esphome/components/i2c/i2c_bus_esp_idf.cpp index c473a58b5e..cf31ba1c0d 100644 --- a/esphome/components/i2c/i2c_bus_esp_idf.cpp +++ b/esphome/components/i2c/i2c_bus_esp_idf.cpp @@ -151,13 +151,13 @@ void IDFI2CBus::dump_config() { break; } if (this->scan_) { - ESP_LOGI(TAG, "Results from bus scan:"); + ESP_LOGCONFIG(TAG, "Results from bus scan:"); if (scan_results_.empty()) { - ESP_LOGI(TAG, "Found no devices"); + ESP_LOGCONFIG(TAG, "Found no devices"); } else { for (const auto &s : scan_results_) { if (s.second) { - ESP_LOGI(TAG, "Found device at address 0x%02X", s.first); + ESP_LOGCONFIG(TAG, "Found device at address 0x%02X", s.first); } else { ESP_LOGE(TAG, "Unknown error at address 0x%02X", s.first); } diff --git a/esphome/components/logger/__init__.py b/esphome/components/logger/__init__.py index d718a7a612..d8c95d75f2 100644 --- a/esphome/components/logger/__init__.py +++ b/esphome/components/logger/__init__.py @@ -409,7 +409,7 @@ def validate_printf(value): [cCdiouxXeEfgGaAnpsSZ] # type ) """ # noqa - matches = re.findall(cfmt, value[CONF_FORMAT], flags=re.X) + matches = re.findall(cfmt, value[CONF_FORMAT], flags=re.VERBOSE) if len(matches) != len(value[CONF_ARGS]): raise cv.Invalid( f"Found {len(matches)} printf-patterns ({', '.join(matches)}), but {len(value[CONF_ARGS])} args were given!" diff --git a/esphome/components/lvgl/helpers.py b/esphome/components/lvgl/helpers.py index e04a0105d5..8d5b6354bb 100644 --- a/esphome/components/lvgl/helpers.py +++ b/esphome/components/lvgl/helpers.py @@ -33,7 +33,7 @@ def validate_printf(value): [cCdiouxXeEfgGaAnpsSZ] # type ) """ # noqa - matches = re.findall(cfmt, value[CONF_FORMAT], flags=re.X) + matches = re.findall(cfmt, value[CONF_FORMAT], flags=re.VERBOSE) if len(matches) != len(value[CONF_ARGS]): raise cv.Invalid( f"Found {len(matches)} printf-patterns ({', '.join(matches)}), but {len(value[CONF_ARGS])} args were given!" diff --git a/esphome/components/speaker/media_player/__init__.py b/esphome/components/speaker/media_player/__init__.py index 16dcc855c3..1c2e7dc0e1 100644 --- a/esphome/components/speaker/media_player/__init__.py +++ b/esphome/components/speaker/media_player/__init__.py @@ -155,8 +155,7 @@ def _read_audio_file_and_type(file_config): import puremagic file_type: str = puremagic.from_string(data) - if file_type.startswith("."): - file_type = file_type[1:] + file_type = file_type.removeprefix(".") media_file_type = audio.AUDIO_FILE_TYPE_ENUM["NONE"] if file_type in ("wav"): diff --git a/esphome/components/stepper/__init__.py b/esphome/components/stepper/__init__.py index 66fe88c6c4..c234388e7e 100644 --- a/esphome/components/stepper/__init__.py +++ b/esphome/components/stepper/__init__.py @@ -27,8 +27,7 @@ SetDecelerationAction = stepper_ns.class_("SetDecelerationAction", automation.Ac def validate_acceleration(value): value = cv.string(value) for suffix in ("steps/s^2", "steps/s*s", "steps/s/s", "steps/ss", "steps/(s*s)"): - if value.endswith(suffix): - value = value[: -len(suffix)] + value = value.removesuffix(suffix) if value == "inf": return 1e6 @@ -48,8 +47,7 @@ def validate_acceleration(value): def validate_speed(value): value = cv.string(value) for suffix in ("steps/s", "steps/s"): - if value.endswith(suffix): - value = value[: -len(suffix)] + value = value.removesuffix(suffix) if value == "inf": return 1e6 diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 348f288863..611e283e6d 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -109,6 +109,7 @@ #define USE_API #define USE_API_CLIENT_CONNECTED_TRIGGER #define USE_API_CLIENT_DISCONNECTED_TRIGGER +#define USE_API_HOMEASSISTANT_STATES #define USE_API_NOISE #define USE_API_PLAINTEXT #define USE_API_SERVICES diff --git a/esphome/cpp_generator.py b/esphome/cpp_generator.py index 72aadcb139..34e4eec1ee 100644 --- a/esphome/cpp_generator.py +++ b/esphome/cpp_generator.py @@ -771,8 +771,7 @@ class MockObj(Expression): if attr.startswith("P") and self.op not in ["::", ""]: attr = attr[1:] next_op = "->" - if attr.startswith("_"): - attr = attr[1:] + attr = attr.removeprefix("_") return MockObj(f"{self.base}{self.op}{attr}", next_op) def __call__(self, *args: SafeExpType) -> "MockObj": diff --git a/esphome/writer.py b/esphome/writer.py index 2c2e00b513..b5c834722a 100644 --- a/esphome/writer.py +++ b/esphome/writer.py @@ -76,7 +76,7 @@ def get_include_text(): def replace_file_content(text, pattern, repl): - content_new, count = re.subn(pattern, repl, text, flags=re.M) + content_new, count = re.subn(pattern, repl, text, flags=re.MULTILINE) return content_new, count diff --git a/pyproject.toml b/pyproject.toml index 742cd6e83d..200f51a873 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -113,6 +113,7 @@ exclude = ['generated'] select = [ "E", # pycodestyle "F", # pyflakes/autoflake + "FURB", # refurb "I", # isort "PERF", # performance "PL", # pylint diff --git a/script/generate-esp32-boards.py b/script/generate-esp32-boards.py index 83d0f0c3e0..3f444ed455 100755 --- a/script/generate-esp32-boards.py +++ b/script/generate-esp32-boards.py @@ -64,8 +64,10 @@ def main(): for line in lines: if line.startswith("BOARDS = {"): f.write("BOARDS = {\n") - for board, info in sorted(boards.items()): - f.write(TEMPLATE % (board, info["name"], info["variant"])) + f.writelines( + TEMPLATE % (board, info["name"], info["variant"]) + for board, info in sorted(boards.items()) + ) f.write("}\n") break