mirror of
https://github.com/esphome/esphome.git
synced 2025-10-30 06:33:51 +00:00
Merge remote-tracking branch 'upstream/dev' into integration
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