mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-29 22:24:26 +00:00 
			
		
		
		
	Merge branch 'integration' into memory_api
This commit is contained in:
		| @@ -112,7 +112,7 @@ async def to_code(config): | ||||
|  | ||||
|     cg.add_define("USE_IMPROV") | ||||
|  | ||||
|     await improv_base.setup_improv_core(var, config) | ||||
|     await improv_base.setup_improv_core(var, config, "esp32_improv") | ||||
|  | ||||
|     cg.add(var.set_identify_duration(config[CONF_IDENTIFY_DURATION])) | ||||
|     cg.add(var.set_authorized_duration(config[CONF_AUTHORIZED_DURATION])) | ||||
|   | ||||
| @@ -389,11 +389,13 @@ void ESP32ImprovComponent::check_wifi_connection_() { | ||||
|     std::string url_strings[3]; | ||||
|     size_t url_count = 0; | ||||
|  | ||||
| #ifdef USE_ESP32_IMPROV_NEXT_URL | ||||
|     // Add next_url if configured (should be first per Improv BLE spec) | ||||
|     std::string next_url = this->get_formatted_next_url_(); | ||||
|     if (!next_url.empty()) { | ||||
|       url_strings[url_count++] = std::move(next_url); | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|     // Add default URLs for backward compatibility | ||||
|     url_strings[url_count++] = ESPHOME_MY_LINK; | ||||
|   | ||||
| @@ -3,6 +3,8 @@ import re | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import __version__ | ||||
| from esphome.cpp_generator import MockObj | ||||
| from esphome.types import ConfigType | ||||
|  | ||||
| CODEOWNERS = ["@esphome/core"] | ||||
|  | ||||
| @@ -35,7 +37,9 @@ def _process_next_url(url: str): | ||||
|     return url | ||||
|  | ||||
|  | ||||
| async def setup_improv_core(var, config): | ||||
|     if CONF_NEXT_URL in config: | ||||
|         cg.add(var.set_next_url(_process_next_url(config[CONF_NEXT_URL]))) | ||||
| async def setup_improv_core(var: MockObj, config: ConfigType, component: str): | ||||
|     if next_url := config.get(CONF_NEXT_URL): | ||||
|         cg.add(var.set_next_url(_process_next_url(next_url))) | ||||
|         cg.add_define(f"USE_{component.upper()}_NEXT_URL") | ||||
|  | ||||
|     cg.add_library("improv/Improv", "1.2.4") | ||||
|   | ||||
| @@ -2,10 +2,12 @@ | ||||
|  | ||||
| #include "esphome/components/network/util.h" | ||||
| #include "esphome/core/application.h" | ||||
| #include "esphome/core/defines.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace improv_base { | ||||
|  | ||||
| #if defined(USE_ESP32_IMPROV_NEXT_URL) || defined(USE_IMPROV_SERIAL_NEXT_URL) | ||||
| static constexpr const char DEVICE_NAME_PLACEHOLDER[] = "{{device_name}}"; | ||||
| static constexpr size_t DEVICE_NAME_PLACEHOLDER_LEN = sizeof(DEVICE_NAME_PLACEHOLDER) - 1; | ||||
| static constexpr const char IP_ADDRESS_PLACEHOLDER[] = "{{ip_address}}"; | ||||
| @@ -43,6 +45,7 @@ std::string ImprovBase::get_formatted_next_url_() { | ||||
|  | ||||
|   return formatted_url; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| }  // namespace improv_base | ||||
| }  // namespace esphome | ||||
|   | ||||
| @@ -1,17 +1,22 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <string> | ||||
| #include "esphome/core/defines.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace improv_base { | ||||
|  | ||||
| class ImprovBase { | ||||
|  public: | ||||
| #if defined(USE_ESP32_IMPROV_NEXT_URL) || defined(USE_IMPROV_SERIAL_NEXT_URL) | ||||
|   void set_next_url(const std::string &next_url) { this->next_url_ = next_url; } | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
| #if defined(USE_ESP32_IMPROV_NEXT_URL) || defined(USE_IMPROV_SERIAL_NEXT_URL) | ||||
|   std::string get_formatted_next_url_(); | ||||
|   std::string next_url_; | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| }  // namespace improv_base | ||||
|   | ||||
| @@ -43,4 +43,4 @@ FINAL_VALIDATE_SCHEMA = validate_logger | ||||
| async def to_code(config): | ||||
|     var = cg.new_Pvariable(config[CONF_ID]) | ||||
|     await cg.register_component(var, config) | ||||
|     await improv_base.setup_improv_core(var, config) | ||||
|     await improv_base.setup_improv_core(var, config, "improv_serial") | ||||
|   | ||||
| @@ -146,9 +146,11 @@ void ImprovSerialComponent::loop() { | ||||
|  | ||||
| std::vector<uint8_t> ImprovSerialComponent::build_rpc_settings_response_(improv::Command command) { | ||||
|   std::vector<std::string> urls; | ||||
| #ifdef USE_IMPROV_SERIAL_NEXT_URL | ||||
|   if (!this->next_url_.empty()) { | ||||
|     urls.push_back(this->get_formatted_next_url_()); | ||||
|   } | ||||
| #endif | ||||
| #ifdef USE_WEBSERVER | ||||
|   for (auto &ip : wifi::global_wifi_component->wifi_sta_ip_addresses()) { | ||||
|     if (ip.is_ip4()) { | ||||
|   | ||||
| @@ -62,7 +62,8 @@ optional<std::string> AppendFilter::new_value(std::string value) { return value | ||||
| optional<std::string> PrependFilter::new_value(std::string value) { return this->prefix_ + value; } | ||||
|  | ||||
| // Substitute | ||||
| SubstituteFilter::SubstituteFilter(std::initializer_list<Substitution> substitutions) : substitutions_(substitutions) {} | ||||
| SubstituteFilter::SubstituteFilter(const std::initializer_list<Substitution> &substitutions) | ||||
|     : substitutions_(substitutions) {} | ||||
|  | ||||
| optional<std::string> SubstituteFilter::new_value(std::string value) { | ||||
|   std::size_t pos; | ||||
| @@ -74,7 +75,7 @@ optional<std::string> SubstituteFilter::new_value(std::string value) { | ||||
| } | ||||
|  | ||||
| // Map | ||||
| MapFilter::MapFilter(std::initializer_list<Substitution> mappings) : mappings_(mappings) {} | ||||
| MapFilter::MapFilter(const std::initializer_list<Substitution> &mappings) : mappings_(mappings) {} | ||||
|  | ||||
| optional<std::string> MapFilter::new_value(std::string value) { | ||||
|   for (const auto &mapping : this->mappings_) { | ||||
|   | ||||
| @@ -102,7 +102,7 @@ struct Substitution { | ||||
| /// A simple filter that replaces a substring with another substring | ||||
| class SubstituteFilter : public Filter { | ||||
|  public: | ||||
|   explicit SubstituteFilter(std::initializer_list<Substitution> substitutions); | ||||
|   explicit SubstituteFilter(const std::initializer_list<Substitution> &substitutions); | ||||
|   optional<std::string> new_value(std::string value) override; | ||||
|  | ||||
|  protected: | ||||
| @@ -135,7 +135,7 @@ class SubstituteFilter : public Filter { | ||||
|  */ | ||||
| class MapFilter : public Filter { | ||||
|  public: | ||||
|   explicit MapFilter(std::initializer_list<Substitution> mappings); | ||||
|   explicit MapFilter(const std::initializer_list<Substitution> &mappings); | ||||
|   optional<std::string> new_value(std::string value) override; | ||||
|  | ||||
|  protected: | ||||
|   | ||||
| @@ -471,6 +471,7 @@ CONF_IMPORT_REACTIVE_ENERGY = "import_reactive_energy" | ||||
| CONF_INC_PIN = "inc_pin" | ||||
| CONF_INCLUDE_INTERNAL = "include_internal" | ||||
| CONF_INCLUDES = "includes" | ||||
| CONF_INCLUDES_C = "includes_c" | ||||
| CONF_INDEX = "index" | ||||
| CONF_INDOOR = "indoor" | ||||
| CONF_INFRARED = "infrared" | ||||
|   | ||||
| @@ -21,6 +21,7 @@ from esphome.const import ( | ||||
|     CONF_FRIENDLY_NAME, | ||||
|     CONF_ID, | ||||
|     CONF_INCLUDES, | ||||
|     CONF_INCLUDES_C, | ||||
|     CONF_LIBRARIES, | ||||
|     CONF_MIN_VERSION, | ||||
|     CONF_NAME, | ||||
| @@ -227,6 +228,7 @@ CONFIG_SCHEMA = cv.All( | ||||
|                 } | ||||
|             ), | ||||
|             cv.Optional(CONF_INCLUDES, default=[]): cv.ensure_list(valid_include), | ||||
|             cv.Optional(CONF_INCLUDES_C, default=[]): cv.ensure_list(valid_include), | ||||
|             cv.Optional(CONF_LIBRARIES, default=[]): cv.ensure_list(cv.string_strict), | ||||
|             cv.Optional(CONF_NAME_ADD_MAC_SUFFIX, default=False): cv.boolean, | ||||
|             cv.Optional(CONF_DEBUG_SCHEDULER, default=False): cv.boolean, | ||||
| @@ -302,6 +304,17 @@ def _list_target_platforms(): | ||||
|     return target_platforms | ||||
|  | ||||
|  | ||||
| def _sort_includes_by_type(includes: list[str]) -> tuple[list[str], list[str]]: | ||||
|     system_includes = [] | ||||
|     other_includes = [] | ||||
|     for include in includes: | ||||
|         if include.startswith("<") and include.endswith(">"): | ||||
|             system_includes.append(include) | ||||
|         else: | ||||
|             other_includes.append(include) | ||||
|     return system_includes, other_includes | ||||
|  | ||||
|  | ||||
| def preload_core_config(config, result) -> str: | ||||
|     with cv.prepend_path(CONF_ESPHOME): | ||||
|         conf = PRELOAD_CONFIG_SCHEMA(config[CONF_ESPHOME]) | ||||
| @@ -339,7 +352,7 @@ def preload_core_config(config, result) -> str: | ||||
|     return target_platforms[0] | ||||
|  | ||||
|  | ||||
| def include_file(path: Path, basename: Path): | ||||
| def include_file(path: Path, basename: Path, is_c_header: bool = False): | ||||
|     parts = basename.parts | ||||
|     dst = CORE.relative_src_path(*parts) | ||||
|     copy_file_if_changed(path, dst) | ||||
| @@ -347,7 +360,14 @@ def include_file(path: Path, basename: Path): | ||||
|     ext = path.suffix | ||||
|     if ext in [".h", ".hpp", ".tcc"]: | ||||
|         # Header, add include statement | ||||
|         cg.add_global(cg.RawStatement(f'#include "{basename}"')) | ||||
|         if is_c_header: | ||||
|             # Wrap in extern "C" block for C headers | ||||
|             cg.add_global( | ||||
|                 cg.RawStatement(f'extern "C" {{\n  #include "{basename}"\n}}') | ||||
|             ) | ||||
|         else: | ||||
|             # Regular include | ||||
|             cg.add_global(cg.RawStatement(f'#include "{basename}"')) | ||||
|  | ||||
|  | ||||
| ARDUINO_GLUE_CODE = """\ | ||||
| @@ -377,7 +397,7 @@ async def add_arduino_global_workaround(): | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(CoroPriority.FINAL) | ||||
| async def add_includes(includes: list[str]) -> None: | ||||
| async def add_includes(includes: list[str], is_c_header: bool = False) -> None: | ||||
|     # Add includes at the very end, so that the included files can access global variables | ||||
|     for include in includes: | ||||
|         path = CORE.relative_config_path(include) | ||||
| @@ -385,11 +405,11 @@ async def add_includes(includes: list[str]) -> None: | ||||
|             # Directory, copy tree | ||||
|             for p in walk_files(path): | ||||
|                 basename = p.relative_to(path.parent) | ||||
|                 include_file(p, basename) | ||||
|                 include_file(p, basename, is_c_header) | ||||
|         else: | ||||
|             # Copy file | ||||
|             basename = Path(path.name) | ||||
|             include_file(path, basename) | ||||
|             include_file(path, basename, is_c_header) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(CoroPriority.FINAL) | ||||
| @@ -494,19 +514,25 @@ async def to_code(config: ConfigType) -> None: | ||||
|         CORE.add_job(add_arduino_global_workaround) | ||||
|  | ||||
|     if config[CONF_INCLUDES]: | ||||
|         # Get the <...> includes | ||||
|         system_includes = [] | ||||
|         other_includes = [] | ||||
|         for include in config[CONF_INCLUDES]: | ||||
|             if include.startswith("<") and include.endswith(">"): | ||||
|                 system_includes.append(include) | ||||
|             else: | ||||
|                 other_includes.append(include) | ||||
|         system_includes, other_includes = _sort_includes_by_type(config[CONF_INCLUDES]) | ||||
|         # <...> includes should be at the start | ||||
|         for include in system_includes: | ||||
|             cg.add_global(cg.RawStatement(f"#include {include}"), prepend=True) | ||||
|         # Other includes should be at the end | ||||
|         CORE.add_job(add_includes, other_includes) | ||||
|         CORE.add_job(add_includes, other_includes, False) | ||||
|  | ||||
|     if config[CONF_INCLUDES_C]: | ||||
|         system_includes, other_includes = _sort_includes_by_type( | ||||
|             config[CONF_INCLUDES_C] | ||||
|         ) | ||||
|         # <...> includes should be at the start | ||||
|         for include in system_includes: | ||||
|             cg.add_global( | ||||
|                 cg.RawStatement(f'extern "C" {{\n  #include {include}\n}}'), | ||||
|                 prepend=True, | ||||
|             ) | ||||
|         # Other includes should be at the end | ||||
|         CORE.add_job(add_includes, other_includes, True) | ||||
|  | ||||
|     if project_conf := config.get(CONF_PROJECT): | ||||
|         cg.add_define("ESPHOME_PROJECT_NAME", project_conf[CONF_NAME]) | ||||
|   | ||||
| @@ -44,6 +44,7 @@ | ||||
| #define USE_GRAPHICAL_DISPLAY_MENU | ||||
| #define USE_HOMEASSISTANT_TIME | ||||
| #define USE_HTTP_REQUEST_OTA_WATCHDOG_TIMEOUT 8000  // NOLINT | ||||
| #define USE_IMPROV_SERIAL_NEXT_URL | ||||
| #define USE_JSON | ||||
| #define USE_LIGHT | ||||
| #define USE_LOCK | ||||
| @@ -186,6 +187,7 @@ | ||||
| #define USE_ESP32_CAMERA_JPEG_ENCODER | ||||
| #define USE_I2C | ||||
| #define USE_IMPROV | ||||
| #define USE_ESP32_IMPROV_NEXT_URL | ||||
| #define USE_MICROPHONE | ||||
| #define USE_PSRAM | ||||
| #define USE_SOCKET_IMPL_BSD_SOCKETS | ||||
|   | ||||
		Reference in New Issue
	
	Block a user