mirror of
https://github.com/esphome/esphome.git
synced 2025-10-12 23:03:46 +01:00
Merge remote-tracking branch 'upstream/dev' into common_bus_grouping
This commit is contained in:
@@ -5,7 +5,7 @@ namespace dashboard_import {
|
|||||||
|
|
||||||
static std::string g_package_import_url; // NOLINT
|
static std::string g_package_import_url; // NOLINT
|
||||||
|
|
||||||
std::string get_package_import_url() { return g_package_import_url; }
|
const std::string &get_package_import_url() { return g_package_import_url; }
|
||||||
void set_package_import_url(std::string url) { g_package_import_url = std::move(url); }
|
void set_package_import_url(std::string url) { g_package_import_url = std::move(url); }
|
||||||
|
|
||||||
} // namespace dashboard_import
|
} // namespace dashboard_import
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace dashboard_import {
|
namespace dashboard_import {
|
||||||
|
|
||||||
std::string get_package_import_url();
|
const std::string &get_package_import_url();
|
||||||
void set_package_import_url(std::string url);
|
void set_package_import_url(std::string url);
|
||||||
|
|
||||||
} // namespace dashboard_import
|
} // namespace dashboard_import
|
||||||
|
@@ -329,7 +329,8 @@ ARDUINO_FRAMEWORK_VERSION_LOOKUP = {
|
|||||||
"dev": cv.Version(3, 3, 1),
|
"dev": cv.Version(3, 3, 1),
|
||||||
}
|
}
|
||||||
ARDUINO_PLATFORM_VERSION_LOOKUP = {
|
ARDUINO_PLATFORM_VERSION_LOOKUP = {
|
||||||
cv.Version(3, 3, 1): cv.Version(55, 3, 31),
|
cv.Version(3, 3, 2): cv.Version(55, 3, 31, "1"),
|
||||||
|
cv.Version(3, 3, 1): cv.Version(55, 3, 31, "1"),
|
||||||
cv.Version(3, 3, 0): cv.Version(55, 3, 30, "2"),
|
cv.Version(3, 3, 0): cv.Version(55, 3, 30, "2"),
|
||||||
cv.Version(3, 2, 1): cv.Version(54, 3, 21, "2"),
|
cv.Version(3, 2, 1): cv.Version(54, 3, 21, "2"),
|
||||||
cv.Version(3, 2, 0): cv.Version(54, 3, 20),
|
cv.Version(3, 2, 0): cv.Version(54, 3, 20),
|
||||||
@@ -347,8 +348,8 @@ ESP_IDF_FRAMEWORK_VERSION_LOOKUP = {
|
|||||||
"dev": cv.Version(5, 5, 1),
|
"dev": cv.Version(5, 5, 1),
|
||||||
}
|
}
|
||||||
ESP_IDF_PLATFORM_VERSION_LOOKUP = {
|
ESP_IDF_PLATFORM_VERSION_LOOKUP = {
|
||||||
cv.Version(5, 5, 1): cv.Version(55, 3, 31),
|
cv.Version(5, 5, 1): cv.Version(55, 3, 31, "1"),
|
||||||
cv.Version(5, 5, 0): cv.Version(55, 3, 31),
|
cv.Version(5, 5, 0): cv.Version(55, 3, 31, "1"),
|
||||||
cv.Version(5, 4, 2): cv.Version(54, 3, 21, "2"),
|
cv.Version(5, 4, 2): cv.Version(54, 3, 21, "2"),
|
||||||
cv.Version(5, 4, 1): cv.Version(54, 3, 21, "2"),
|
cv.Version(5, 4, 1): cv.Version(54, 3, 21, "2"),
|
||||||
cv.Version(5, 4, 0): cv.Version(54, 3, 21, "2"),
|
cv.Version(5, 4, 0): cv.Version(54, 3, 21, "2"),
|
||||||
@@ -363,8 +364,8 @@ ESP_IDF_PLATFORM_VERSION_LOOKUP = {
|
|||||||
# - https://github.com/pioarduino/platform-espressif32/releases
|
# - https://github.com/pioarduino/platform-espressif32/releases
|
||||||
PLATFORM_VERSION_LOOKUP = {
|
PLATFORM_VERSION_LOOKUP = {
|
||||||
"recommended": cv.Version(54, 3, 21, "2"),
|
"recommended": cv.Version(54, 3, 21, "2"),
|
||||||
"latest": cv.Version(55, 3, 31),
|
"latest": cv.Version(55, 3, 31, "1"),
|
||||||
"dev": "https://github.com/pioarduino/platform-espressif32.git#develop",
|
"dev": cv.Version(55, 3, 31, "1"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -656,6 +657,7 @@ def _show_framework_migration_message(name: str, variant: str) -> None:
|
|||||||
+ "Why change? ESP-IDF offers:\n"
|
+ "Why change? ESP-IDF offers:\n"
|
||||||
+ color(AnsiFore.GREEN, " ✨ Up to 40% smaller binaries\n")
|
+ color(AnsiFore.GREEN, " ✨ Up to 40% smaller binaries\n")
|
||||||
+ color(AnsiFore.GREEN, " 🚀 Better performance and optimization\n")
|
+ color(AnsiFore.GREEN, " 🚀 Better performance and optimization\n")
|
||||||
|
+ color(AnsiFore.GREEN, " ⚡ 2-3x faster compile times\n")
|
||||||
+ color(AnsiFore.GREEN, " 📦 Custom-built firmware for your exact needs\n")
|
+ color(AnsiFore.GREEN, " 📦 Custom-built firmware for your exact needs\n")
|
||||||
+ color(
|
+ color(
|
||||||
AnsiFore.GREEN,
|
AnsiFore.GREEN,
|
||||||
@@ -663,7 +665,6 @@ def _show_framework_migration_message(name: str, variant: str) -> None:
|
|||||||
)
|
)
|
||||||
+ "\n"
|
+ "\n"
|
||||||
+ "Trade-offs:\n"
|
+ "Trade-offs:\n"
|
||||||
+ color(AnsiFore.YELLOW, " ⏱️ Compile times are ~25% longer\n")
|
|
||||||
+ color(AnsiFore.YELLOW, " 🔄 Some components need migration\n")
|
+ color(AnsiFore.YELLOW, " 🔄 Some components need migration\n")
|
||||||
+ "\n"
|
+ "\n"
|
||||||
+ "What should I do?\n"
|
+ "What should I do?\n"
|
||||||
|
@@ -58,14 +58,6 @@ CONFIG_SCHEMA = cv.All(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def mdns_txt_record(key: str, value: str):
|
|
||||||
return cg.StructInitializer(
|
|
||||||
MDNSTXTRecord,
|
|
||||||
("key", cg.RawExpression(f"MDNS_STR({cg.safe_exp(key)})")),
|
|
||||||
("value", value),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def mdns_service(
|
def mdns_service(
|
||||||
service: str, proto: str, port: int, txt_records: list[dict[str, str]]
|
service: str, proto: str, port: int, txt_records: list[dict[str, str]]
|
||||||
):
|
):
|
||||||
@@ -107,23 +99,53 @@ async def to_code(config):
|
|||||||
# Ensure at least 1 service (fallback service)
|
# Ensure at least 1 service (fallback service)
|
||||||
cg.add_define("MDNS_SERVICE_COUNT", max(1, service_count))
|
cg.add_define("MDNS_SERVICE_COUNT", max(1, service_count))
|
||||||
|
|
||||||
|
# Calculate compile-time dynamic TXT value count
|
||||||
|
# Dynamic values are those that cannot be stored in flash at compile time
|
||||||
|
dynamic_txt_count = 0
|
||||||
|
if "api" in CORE.config:
|
||||||
|
# Always: get_mac_address()
|
||||||
|
dynamic_txt_count += 1
|
||||||
|
# User-provided templatable TXT values (only lambdas, not static strings)
|
||||||
|
dynamic_txt_count += sum(
|
||||||
|
1
|
||||||
|
for service in config[CONF_SERVICES]
|
||||||
|
for txt_value in service[CONF_TXT].values()
|
||||||
|
if cg.is_template(txt_value)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Ensure at least 1 to avoid zero-size array
|
||||||
|
cg.add_define("MDNS_DYNAMIC_TXT_COUNT", max(1, dynamic_txt_count))
|
||||||
|
|
||||||
var = cg.new_Pvariable(config[CONF_ID])
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
await cg.register_component(var, config)
|
await cg.register_component(var, config)
|
||||||
|
|
||||||
for service in config[CONF_SERVICES]:
|
for service in config[CONF_SERVICES]:
|
||||||
txt = [
|
# Build the txt records list for the service
|
||||||
cg.StructInitializer(
|
txt_records = []
|
||||||
MDNSTXTRecord,
|
for txt_key, txt_value in service[CONF_TXT].items():
|
||||||
("key", cg.RawExpression(f"MDNS_STR({cg.safe_exp(txt_key)})")),
|
if cg.is_template(txt_value):
|
||||||
("value", await cg.templatable(txt_value, [], cg.std_string)),
|
# It's a lambda - evaluate and store using helper
|
||||||
|
templated_value = await cg.templatable(txt_value, [], cg.std_string)
|
||||||
|
safe_key = cg.safe_exp(txt_key)
|
||||||
|
dynamic_call = f"{var}->add_dynamic_txt_value(({templated_value})())"
|
||||||
|
txt_records.append(
|
||||||
|
cg.RawExpression(
|
||||||
|
f"{{MDNS_STR({safe_key}), MDNS_STR({dynamic_call})}}"
|
||||||
)
|
)
|
||||||
for txt_key, txt_value in service[CONF_TXT].items()
|
)
|
||||||
]
|
else:
|
||||||
|
# It's a static string - use directly in flash, no need to store in vector
|
||||||
|
txt_records.append(
|
||||||
|
cg.RawExpression(
|
||||||
|
f"{{MDNS_STR({cg.safe_exp(txt_key)}), MDNS_STR({cg.safe_exp(txt_value)})}}"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
exp = mdns_service(
|
exp = mdns_service(
|
||||||
service[CONF_SERVICE],
|
service[CONF_SERVICE],
|
||||||
service[CONF_PROTOCOL],
|
service[CONF_PROTOCOL],
|
||||||
await cg.templatable(service[CONF_PORT], [], cg.uint16),
|
await cg.templatable(service[CONF_PORT], [], cg.uint16),
|
||||||
txt,
|
txt_records,
|
||||||
)
|
)
|
||||||
|
|
||||||
cg.add(var.add_extra_service(exp))
|
cg.add(var.add_extra_service(exp))
|
||||||
|
@@ -9,21 +9,9 @@
|
|||||||
#include <pgmspace.h>
|
#include <pgmspace.h>
|
||||||
// Macro to define strings in PROGMEM on ESP8266, regular memory on other platforms
|
// Macro to define strings in PROGMEM on ESP8266, regular memory on other platforms
|
||||||
#define MDNS_STATIC_CONST_CHAR(name, value) static const char name[] PROGMEM = value
|
#define MDNS_STATIC_CONST_CHAR(name, value) static const char name[] PROGMEM = value
|
||||||
// Helper to convert PROGMEM string to std::string for TemplatableValue
|
|
||||||
// Only define this function if we have services that will use it
|
|
||||||
#if defined(USE_API) || defined(USE_PROMETHEUS) || defined(USE_WEBSERVER) || defined(USE_MDNS_EXTRA_SERVICES)
|
|
||||||
static std::string mdns_str_value(PGM_P str) {
|
|
||||||
char buf[64];
|
|
||||||
strncpy_P(buf, str, sizeof(buf) - 1);
|
|
||||||
buf[sizeof(buf) - 1] = '\0';
|
|
||||||
return std::string(buf);
|
|
||||||
}
|
|
||||||
#define MDNS_STR_VALUE(name) mdns_str_value(name)
|
|
||||||
#endif
|
|
||||||
#else
|
#else
|
||||||
// On non-ESP8266 platforms, use regular const char*
|
// On non-ESP8266 platforms, use regular const char*
|
||||||
#define MDNS_STATIC_CONST_CHAR(name, value) static constexpr const char name[] = value
|
#define MDNS_STATIC_CONST_CHAR(name, value) static constexpr const char name[] = value
|
||||||
#define MDNS_STR_VALUE(name) std::string(name)
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_API
|
#ifdef USE_API
|
||||||
@@ -43,30 +31,10 @@ static const char *const TAG = "mdns";
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Define all constant strings using the macro
|
// Define all constant strings using the macro
|
||||||
MDNS_STATIC_CONST_CHAR(SERVICE_ESPHOMELIB, "_esphomelib");
|
|
||||||
MDNS_STATIC_CONST_CHAR(SERVICE_TCP, "_tcp");
|
MDNS_STATIC_CONST_CHAR(SERVICE_TCP, "_tcp");
|
||||||
MDNS_STATIC_CONST_CHAR(SERVICE_PROMETHEUS, "_prometheus-http");
|
|
||||||
MDNS_STATIC_CONST_CHAR(SERVICE_HTTP, "_http");
|
|
||||||
|
|
||||||
MDNS_STATIC_CONST_CHAR(TXT_FRIENDLY_NAME, "friendly_name");
|
// Wrap build-time defines into flash storage
|
||||||
MDNS_STATIC_CONST_CHAR(TXT_VERSION, "version");
|
MDNS_STATIC_CONST_CHAR(VALUE_VERSION, ESPHOME_VERSION);
|
||||||
MDNS_STATIC_CONST_CHAR(TXT_MAC, "mac");
|
|
||||||
MDNS_STATIC_CONST_CHAR(TXT_PLATFORM, "platform");
|
|
||||||
MDNS_STATIC_CONST_CHAR(TXT_BOARD, "board");
|
|
||||||
MDNS_STATIC_CONST_CHAR(TXT_NETWORK, "network");
|
|
||||||
MDNS_STATIC_CONST_CHAR(TXT_API_ENCRYPTION, "api_encryption");
|
|
||||||
MDNS_STATIC_CONST_CHAR(TXT_API_ENCRYPTION_SUPPORTED, "api_encryption_supported");
|
|
||||||
MDNS_STATIC_CONST_CHAR(TXT_PROJECT_NAME, "project_name");
|
|
||||||
MDNS_STATIC_CONST_CHAR(TXT_PROJECT_VERSION, "project_version");
|
|
||||||
MDNS_STATIC_CONST_CHAR(TXT_PACKAGE_IMPORT_URL, "package_import_url");
|
|
||||||
|
|
||||||
MDNS_STATIC_CONST_CHAR(PLATFORM_ESP8266, "ESP8266");
|
|
||||||
MDNS_STATIC_CONST_CHAR(PLATFORM_ESP32, "ESP32");
|
|
||||||
MDNS_STATIC_CONST_CHAR(PLATFORM_RP2040, "RP2040");
|
|
||||||
|
|
||||||
MDNS_STATIC_CONST_CHAR(NETWORK_WIFI, "wifi");
|
|
||||||
MDNS_STATIC_CONST_CHAR(NETWORK_ETHERNET, "ethernet");
|
|
||||||
MDNS_STATIC_CONST_CHAR(NETWORK_THREAD, "thread");
|
|
||||||
|
|
||||||
void MDNSComponent::compile_records_() {
|
void MDNSComponent::compile_records_() {
|
||||||
this->hostname_ = App.get_name();
|
this->hostname_ = App.get_name();
|
||||||
@@ -75,6 +43,15 @@ void MDNSComponent::compile_records_() {
|
|||||||
// in mdns/__init__.py. If you add a new service here, update both locations.
|
// in mdns/__init__.py. If you add a new service here, update both locations.
|
||||||
|
|
||||||
#ifdef USE_API
|
#ifdef USE_API
|
||||||
|
MDNS_STATIC_CONST_CHAR(SERVICE_ESPHOMELIB, "_esphomelib");
|
||||||
|
MDNS_STATIC_CONST_CHAR(TXT_FRIENDLY_NAME, "friendly_name");
|
||||||
|
MDNS_STATIC_CONST_CHAR(TXT_VERSION, "version");
|
||||||
|
MDNS_STATIC_CONST_CHAR(TXT_MAC, "mac");
|
||||||
|
MDNS_STATIC_CONST_CHAR(TXT_PLATFORM, "platform");
|
||||||
|
MDNS_STATIC_CONST_CHAR(TXT_BOARD, "board");
|
||||||
|
MDNS_STATIC_CONST_CHAR(TXT_NETWORK, "network");
|
||||||
|
MDNS_STATIC_CONST_CHAR(VALUE_BOARD, ESPHOME_BOARD);
|
||||||
|
|
||||||
if (api::global_api_server != nullptr) {
|
if (api::global_api_server != nullptr) {
|
||||||
auto &service = this->services_.emplace_next();
|
auto &service = this->services_.emplace_next();
|
||||||
service.service_type = MDNS_STR(SERVICE_ESPHOMELIB);
|
service.service_type = MDNS_STR(SERVICE_ESPHOMELIB);
|
||||||
@@ -109,52 +86,66 @@ void MDNSComponent::compile_records_() {
|
|||||||
txt_records.reserve(txt_count);
|
txt_records.reserve(txt_count);
|
||||||
|
|
||||||
if (!friendly_name_empty) {
|
if (!friendly_name_empty) {
|
||||||
txt_records.push_back({MDNS_STR(TXT_FRIENDLY_NAME), friendly_name});
|
txt_records.push_back({MDNS_STR(TXT_FRIENDLY_NAME), MDNS_STR(friendly_name.c_str())});
|
||||||
}
|
}
|
||||||
txt_records.push_back({MDNS_STR(TXT_VERSION), ESPHOME_VERSION});
|
txt_records.push_back({MDNS_STR(TXT_VERSION), MDNS_STR(VALUE_VERSION)});
|
||||||
txt_records.push_back({MDNS_STR(TXT_MAC), get_mac_address()});
|
txt_records.push_back({MDNS_STR(TXT_MAC), MDNS_STR(this->add_dynamic_txt_value(get_mac_address()))});
|
||||||
|
|
||||||
#ifdef USE_ESP8266
|
#ifdef USE_ESP8266
|
||||||
txt_records.push_back({MDNS_STR(TXT_PLATFORM), MDNS_STR_VALUE(PLATFORM_ESP8266)});
|
MDNS_STATIC_CONST_CHAR(PLATFORM_ESP8266, "ESP8266");
|
||||||
|
txt_records.push_back({MDNS_STR(TXT_PLATFORM), MDNS_STR(PLATFORM_ESP8266)});
|
||||||
#elif defined(USE_ESP32)
|
#elif defined(USE_ESP32)
|
||||||
txt_records.push_back({MDNS_STR(TXT_PLATFORM), MDNS_STR_VALUE(PLATFORM_ESP32)});
|
MDNS_STATIC_CONST_CHAR(PLATFORM_ESP32, "ESP32");
|
||||||
|
txt_records.push_back({MDNS_STR(TXT_PLATFORM), MDNS_STR(PLATFORM_ESP32)});
|
||||||
#elif defined(USE_RP2040)
|
#elif defined(USE_RP2040)
|
||||||
txt_records.push_back({MDNS_STR(TXT_PLATFORM), MDNS_STR_VALUE(PLATFORM_RP2040)});
|
MDNS_STATIC_CONST_CHAR(PLATFORM_RP2040, "RP2040");
|
||||||
|
txt_records.push_back({MDNS_STR(TXT_PLATFORM), MDNS_STR(PLATFORM_RP2040)});
|
||||||
#elif defined(USE_LIBRETINY)
|
#elif defined(USE_LIBRETINY)
|
||||||
txt_records.push_back({MDNS_STR(TXT_PLATFORM), lt_cpu_get_model_name()});
|
txt_records.push_back({MDNS_STR(TXT_PLATFORM), MDNS_STR(lt_cpu_get_model_name())});
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
txt_records.push_back({MDNS_STR(TXT_BOARD), ESPHOME_BOARD});
|
txt_records.push_back({MDNS_STR(TXT_BOARD), MDNS_STR(VALUE_BOARD)});
|
||||||
|
|
||||||
#if defined(USE_WIFI)
|
#if defined(USE_WIFI)
|
||||||
txt_records.push_back({MDNS_STR(TXT_NETWORK), MDNS_STR_VALUE(NETWORK_WIFI)});
|
MDNS_STATIC_CONST_CHAR(NETWORK_WIFI, "wifi");
|
||||||
|
txt_records.push_back({MDNS_STR(TXT_NETWORK), MDNS_STR(NETWORK_WIFI)});
|
||||||
#elif defined(USE_ETHERNET)
|
#elif defined(USE_ETHERNET)
|
||||||
txt_records.push_back({MDNS_STR(TXT_NETWORK), MDNS_STR_VALUE(NETWORK_ETHERNET)});
|
MDNS_STATIC_CONST_CHAR(NETWORK_ETHERNET, "ethernet");
|
||||||
|
txt_records.push_back({MDNS_STR(TXT_NETWORK), MDNS_STR(NETWORK_ETHERNET)});
|
||||||
#elif defined(USE_OPENTHREAD)
|
#elif defined(USE_OPENTHREAD)
|
||||||
txt_records.push_back({MDNS_STR(TXT_NETWORK), MDNS_STR_VALUE(NETWORK_THREAD)});
|
MDNS_STATIC_CONST_CHAR(NETWORK_THREAD, "thread");
|
||||||
|
txt_records.push_back({MDNS_STR(TXT_NETWORK), MDNS_STR(NETWORK_THREAD)});
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_API_NOISE
|
#ifdef USE_API_NOISE
|
||||||
|
MDNS_STATIC_CONST_CHAR(TXT_API_ENCRYPTION, "api_encryption");
|
||||||
|
MDNS_STATIC_CONST_CHAR(TXT_API_ENCRYPTION_SUPPORTED, "api_encryption_supported");
|
||||||
MDNS_STATIC_CONST_CHAR(NOISE_ENCRYPTION, "Noise_NNpsk0_25519_ChaChaPoly_SHA256");
|
MDNS_STATIC_CONST_CHAR(NOISE_ENCRYPTION, "Noise_NNpsk0_25519_ChaChaPoly_SHA256");
|
||||||
if (api::global_api_server->get_noise_ctx()->has_psk()) {
|
bool has_psk = api::global_api_server->get_noise_ctx()->has_psk();
|
||||||
txt_records.push_back({MDNS_STR(TXT_API_ENCRYPTION), MDNS_STR_VALUE(NOISE_ENCRYPTION)});
|
const char *encryption_key = has_psk ? TXT_API_ENCRYPTION : TXT_API_ENCRYPTION_SUPPORTED;
|
||||||
} else {
|
txt_records.push_back({MDNS_STR(encryption_key), MDNS_STR(NOISE_ENCRYPTION)});
|
||||||
txt_records.push_back({MDNS_STR(TXT_API_ENCRYPTION_SUPPORTED), MDNS_STR_VALUE(NOISE_ENCRYPTION)});
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ESPHOME_PROJECT_NAME
|
#ifdef ESPHOME_PROJECT_NAME
|
||||||
txt_records.push_back({MDNS_STR(TXT_PROJECT_NAME), ESPHOME_PROJECT_NAME});
|
MDNS_STATIC_CONST_CHAR(TXT_PROJECT_NAME, "project_name");
|
||||||
txt_records.push_back({MDNS_STR(TXT_PROJECT_VERSION), ESPHOME_PROJECT_VERSION});
|
MDNS_STATIC_CONST_CHAR(TXT_PROJECT_VERSION, "project_version");
|
||||||
|
MDNS_STATIC_CONST_CHAR(VALUE_PROJECT_NAME, ESPHOME_PROJECT_NAME);
|
||||||
|
MDNS_STATIC_CONST_CHAR(VALUE_PROJECT_VERSION, ESPHOME_PROJECT_VERSION);
|
||||||
|
txt_records.push_back({MDNS_STR(TXT_PROJECT_NAME), MDNS_STR(VALUE_PROJECT_NAME)});
|
||||||
|
txt_records.push_back({MDNS_STR(TXT_PROJECT_VERSION), MDNS_STR(VALUE_PROJECT_VERSION)});
|
||||||
#endif // ESPHOME_PROJECT_NAME
|
#endif // ESPHOME_PROJECT_NAME
|
||||||
|
|
||||||
#ifdef USE_DASHBOARD_IMPORT
|
#ifdef USE_DASHBOARD_IMPORT
|
||||||
txt_records.push_back({MDNS_STR(TXT_PACKAGE_IMPORT_URL), dashboard_import::get_package_import_url()});
|
MDNS_STATIC_CONST_CHAR(TXT_PACKAGE_IMPORT_URL, "package_import_url");
|
||||||
|
txt_records.push_back(
|
||||||
|
{MDNS_STR(TXT_PACKAGE_IMPORT_URL), MDNS_STR(dashboard_import::get_package_import_url().c_str())});
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif // USE_API
|
#endif // USE_API
|
||||||
|
|
||||||
#ifdef USE_PROMETHEUS
|
#ifdef USE_PROMETHEUS
|
||||||
|
MDNS_STATIC_CONST_CHAR(SERVICE_PROMETHEUS, "_prometheus-http");
|
||||||
|
|
||||||
auto &prom_service = this->services_.emplace_next();
|
auto &prom_service = this->services_.emplace_next();
|
||||||
prom_service.service_type = MDNS_STR(SERVICE_PROMETHEUS);
|
prom_service.service_type = MDNS_STR(SERVICE_PROMETHEUS);
|
||||||
prom_service.proto = MDNS_STR(SERVICE_TCP);
|
prom_service.proto = MDNS_STR(SERVICE_TCP);
|
||||||
@@ -162,6 +153,8 @@ void MDNSComponent::compile_records_() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_WEBSERVER
|
#ifdef USE_WEBSERVER
|
||||||
|
MDNS_STATIC_CONST_CHAR(SERVICE_HTTP, "_http");
|
||||||
|
|
||||||
auto &web_service = this->services_.emplace_next();
|
auto &web_service = this->services_.emplace_next();
|
||||||
web_service.service_type = MDNS_STR(SERVICE_HTTP);
|
web_service.service_type = MDNS_STR(SERVICE_HTTP);
|
||||||
web_service.proto = MDNS_STR(SERVICE_TCP);
|
web_service.proto = MDNS_STR(SERVICE_TCP);
|
||||||
@@ -169,13 +162,16 @@ void MDNSComponent::compile_records_() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(USE_API) && !defined(USE_PROMETHEUS) && !defined(USE_WEBSERVER) && !defined(USE_MDNS_EXTRA_SERVICES)
|
#if !defined(USE_API) && !defined(USE_PROMETHEUS) && !defined(USE_WEBSERVER) && !defined(USE_MDNS_EXTRA_SERVICES)
|
||||||
|
MDNS_STATIC_CONST_CHAR(SERVICE_HTTP, "_http");
|
||||||
|
MDNS_STATIC_CONST_CHAR(TXT_VERSION, "version");
|
||||||
|
|
||||||
// Publish "http" service if not using native API or any other services
|
// Publish "http" service if not using native API or any other services
|
||||||
// This is just to have *some* mDNS service so that .local resolution works
|
// This is just to have *some* mDNS service so that .local resolution works
|
||||||
auto &fallback_service = this->services_.emplace_next();
|
auto &fallback_service = this->services_.emplace_next();
|
||||||
fallback_service.service_type = MDNS_STR(SERVICE_HTTP);
|
fallback_service.service_type = MDNS_STR(SERVICE_HTTP);
|
||||||
fallback_service.proto = MDNS_STR(SERVICE_TCP);
|
fallback_service.proto = MDNS_STR(SERVICE_TCP);
|
||||||
fallback_service.port = USE_WEBSERVER_PORT;
|
fallback_service.port = USE_WEBSERVER_PORT;
|
||||||
fallback_service.txt_records.push_back({MDNS_STR(TXT_VERSION), ESPHOME_VERSION});
|
fallback_service.txt_records.push_back({MDNS_STR(TXT_VERSION), MDNS_STR(VALUE_VERSION)});
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,8 +186,7 @@ void MDNSComponent::dump_config() {
|
|||||||
ESP_LOGV(TAG, " - %s, %s, %d", MDNS_STR_ARG(service.service_type), MDNS_STR_ARG(service.proto),
|
ESP_LOGV(TAG, " - %s, %s, %d", MDNS_STR_ARG(service.service_type), MDNS_STR_ARG(service.proto),
|
||||||
const_cast<TemplatableValue<uint16_t> &>(service.port).value());
|
const_cast<TemplatableValue<uint16_t> &>(service.port).value());
|
||||||
for (const auto &record : service.txt_records) {
|
for (const auto &record : service.txt_records) {
|
||||||
ESP_LOGV(TAG, " TXT: %s = %s", MDNS_STR_ARG(record.key),
|
ESP_LOGV(TAG, " TXT: %s = %s", MDNS_STR_ARG(record.key), MDNS_STR_ARG(record.value));
|
||||||
const_cast<TemplatableValue<std::string> &>(record.value).value().c_str());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -27,7 +27,7 @@ struct MDNSString;
|
|||||||
|
|
||||||
struct MDNSTXTRecord {
|
struct MDNSTXTRecord {
|
||||||
const MDNSString *key;
|
const MDNSString *key;
|
||||||
TemplatableValue<std::string> value;
|
const MDNSString *value;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MDNSService {
|
struct MDNSService {
|
||||||
@@ -59,6 +59,17 @@ class MDNSComponent : public Component {
|
|||||||
|
|
||||||
void on_shutdown() override;
|
void on_shutdown() override;
|
||||||
|
|
||||||
|
/// Add a dynamic TXT value and return pointer to it for use in MDNSTXTRecord
|
||||||
|
const char *add_dynamic_txt_value(const std::string &value) {
|
||||||
|
this->dynamic_txt_values_.push_back(value);
|
||||||
|
return this->dynamic_txt_values_[this->dynamic_txt_values_.size() - 1].c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Storage for runtime-generated TXT values (MAC address, user lambdas)
|
||||||
|
/// Pre-sized at compile time via MDNS_DYNAMIC_TXT_COUNT to avoid heap allocations.
|
||||||
|
/// Static/compile-time values (version, board, etc.) are stored directly in flash and don't use this.
|
||||||
|
StaticVector<std::string, MDNS_DYNAMIC_TXT_COUNT> dynamic_txt_values_;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
StaticVector<MDNSService, MDNS_SERVICE_COUNT> services_{};
|
StaticVector<MDNSService, MDNS_SERVICE_COUNT> services_{};
|
||||||
std::string hostname_;
|
std::string hostname_;
|
||||||
|
@@ -2,7 +2,6 @@
|
|||||||
#if defined(USE_ESP32) && defined(USE_MDNS)
|
#if defined(USE_ESP32) && defined(USE_MDNS)
|
||||||
|
|
||||||
#include <mdns.h>
|
#include <mdns.h>
|
||||||
#include <cstring>
|
|
||||||
#include "esphome/core/hal.h"
|
#include "esphome/core/hal.h"
|
||||||
#include "esphome/core/log.h"
|
#include "esphome/core/log.h"
|
||||||
#include "mdns_component.h"
|
#include "mdns_component.h"
|
||||||
@@ -29,21 +28,16 @@ void MDNSComponent::setup() {
|
|||||||
std::vector<mdns_txt_item_t> txt_records;
|
std::vector<mdns_txt_item_t> txt_records;
|
||||||
for (const auto &record : service.txt_records) {
|
for (const auto &record : service.txt_records) {
|
||||||
mdns_txt_item_t it{};
|
mdns_txt_item_t it{};
|
||||||
// key is a compile-time string literal in flash, no need to strdup
|
// key and value are either compile-time string literals in flash or pointers to dynamic_txt_values_
|
||||||
|
// Both remain valid for the lifetime of this function, and ESP-IDF makes internal copies
|
||||||
it.key = MDNS_STR_ARG(record.key);
|
it.key = MDNS_STR_ARG(record.key);
|
||||||
// value is a temporary from TemplatableValue, must strdup to keep it alive
|
it.value = MDNS_STR_ARG(record.value);
|
||||||
it.value = strdup(const_cast<TemplatableValue<std::string> &>(record.value).value().c_str());
|
|
||||||
txt_records.push_back(it);
|
txt_records.push_back(it);
|
||||||
}
|
}
|
||||||
uint16_t port = const_cast<TemplatableValue<uint16_t> &>(service.port).value();
|
uint16_t port = const_cast<TemplatableValue<uint16_t> &>(service.port).value();
|
||||||
err = mdns_service_add(nullptr, MDNS_STR_ARG(service.service_type), MDNS_STR_ARG(service.proto), port,
|
err = mdns_service_add(nullptr, MDNS_STR_ARG(service.service_type), MDNS_STR_ARG(service.proto), port,
|
||||||
txt_records.data(), txt_records.size());
|
txt_records.data(), txt_records.size());
|
||||||
|
|
||||||
// free records
|
|
||||||
for (const auto &it : txt_records) {
|
|
||||||
free((void *) it.value); // NOLINT(cppcoreguidelines-no-malloc)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGW(TAG, "Failed to register service %s: %s", MDNS_STR_ARG(service.service_type), esp_err_to_name(err));
|
ESP_LOGW(TAG, "Failed to register service %s: %s", MDNS_STR_ARG(service.service_type), esp_err_to_name(err));
|
||||||
}
|
}
|
||||||
|
@@ -33,7 +33,7 @@ void MDNSComponent::setup() {
|
|||||||
MDNS.addService(FPSTR(service_type), FPSTR(proto), port);
|
MDNS.addService(FPSTR(service_type), FPSTR(proto), port);
|
||||||
for (const auto &record : service.txt_records) {
|
for (const auto &record : service.txt_records) {
|
||||||
MDNS.addServiceTxt(FPSTR(service_type), FPSTR(proto), FPSTR(MDNS_STR_ARG(record.key)),
|
MDNS.addServiceTxt(FPSTR(service_type), FPSTR(proto), FPSTR(MDNS_STR_ARG(record.key)),
|
||||||
const_cast<TemplatableValue<std::string> &>(record.value).value().c_str());
|
FPSTR(MDNS_STR_ARG(record.value)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -32,8 +32,7 @@ void MDNSComponent::setup() {
|
|||||||
uint16_t port_ = const_cast<TemplatableValue<uint16_t> &>(service.port).value();
|
uint16_t port_ = const_cast<TemplatableValue<uint16_t> &>(service.port).value();
|
||||||
MDNS.addService(service_type, proto, port_);
|
MDNS.addService(service_type, proto, port_);
|
||||||
for (const auto &record : service.txt_records) {
|
for (const auto &record : service.txt_records) {
|
||||||
MDNS.addServiceTxt(service_type, proto, MDNS_STR_ARG(record.key),
|
MDNS.addServiceTxt(service_type, proto, MDNS_STR_ARG(record.key), MDNS_STR_ARG(record.value));
|
||||||
const_cast<TemplatableValue<std::string> &>(record.value).value().c_str());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -32,8 +32,7 @@ void MDNSComponent::setup() {
|
|||||||
uint16_t port = const_cast<TemplatableValue<uint16_t> &>(service.port).value();
|
uint16_t port = const_cast<TemplatableValue<uint16_t> &>(service.port).value();
|
||||||
MDNS.addService(service_type, proto, port);
|
MDNS.addService(service_type, proto, port);
|
||||||
for (const auto &record : service.txt_records) {
|
for (const auto &record : service.txt_records) {
|
||||||
MDNS.addServiceTxt(service_type, proto, MDNS_STR_ARG(record.key),
|
MDNS.addServiceTxt(service_type, proto, MDNS_STR_ARG(record.key), MDNS_STR_ARG(record.value));
|
||||||
const_cast<TemplatableValue<std::string> &>(record.value).value().c_str());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -180,10 +180,12 @@ void OpenThreadSrpComponent::setup() {
|
|||||||
entry->mService.mNumTxtEntries = service.txt_records.size();
|
entry->mService.mNumTxtEntries = service.txt_records.size();
|
||||||
for (size_t i = 0; i < service.txt_records.size(); i++) {
|
for (size_t i = 0; i < service.txt_records.size(); i++) {
|
||||||
const auto &txt = service.txt_records[i];
|
const auto &txt = service.txt_records[i];
|
||||||
auto value = const_cast<TemplatableValue<std::string> &>(txt.value).value();
|
// Value is either a compile-time string literal in flash or a pointer to dynamic_txt_values_
|
||||||
|
// OpenThread SRP client expects the data to persist, so we strdup it
|
||||||
|
const char *value_str = MDNS_STR_ARG(txt.value);
|
||||||
txt_entries[i].mKey = MDNS_STR_ARG(txt.key);
|
txt_entries[i].mKey = MDNS_STR_ARG(txt.key);
|
||||||
txt_entries[i].mValue = reinterpret_cast<const uint8_t *>(strdup(value.c_str()));
|
txt_entries[i].mValue = reinterpret_cast<const uint8_t *>(strdup(value_str));
|
||||||
txt_entries[i].mValueLength = value.size();
|
txt_entries[i].mValueLength = strlen(value_str);
|
||||||
}
|
}
|
||||||
entry->mService.mTxtEntries = txt_entries;
|
entry->mService.mTxtEntries = txt_entries;
|
||||||
entry->mService.mNumTxtEntries = service.txt_records.size();
|
entry->mService.mNumTxtEntries = service.txt_records.size();
|
||||||
|
@@ -84,6 +84,7 @@
|
|||||||
#define USE_LVGL_TOUCHSCREEN
|
#define USE_LVGL_TOUCHSCREEN
|
||||||
#define USE_MDNS
|
#define USE_MDNS
|
||||||
#define MDNS_SERVICE_COUNT 3
|
#define MDNS_SERVICE_COUNT 3
|
||||||
|
#define MDNS_DYNAMIC_TXT_COUNT 3
|
||||||
#define USE_MEDIA_PLAYER
|
#define USE_MEDIA_PLAYER
|
||||||
#define USE_NEXTION_TFT_UPLOAD
|
#define USE_NEXTION_TFT_UPLOAD
|
||||||
#define USE_NUMBER
|
#define USE_NUMBER
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
pylint==3.3.9
|
pylint==3.3.9
|
||||||
flake8==7.3.0 # also change in .pre-commit-config.yaml when updating
|
flake8==7.3.0 # also change in .pre-commit-config.yaml when updating
|
||||||
ruff==0.14.0 # also change in .pre-commit-config.yaml when updating
|
ruff==0.14.0 # also change in .pre-commit-config.yaml when updating
|
||||||
pyupgrade==3.20.0 # also change in .pre-commit-config.yaml when updating
|
pyupgrade==3.21.0 # also change in .pre-commit-config.yaml when updating
|
||||||
pre-commit
|
pre-commit
|
||||||
|
|
||||||
# Unit tests
|
# Unit tests
|
||||||
|
@@ -25,6 +25,9 @@ mdns:
|
|||||||
- service: _http
|
- service: _http
|
||||||
protocol: _tcp
|
protocol: _tcp
|
||||||
port: 80
|
port: 80
|
||||||
|
txt:
|
||||||
|
version: "1.0"
|
||||||
|
path: "/"
|
||||||
|
|
||||||
# OTA should run at priority 54 (after mdns)
|
# OTA should run at priority 54 (after mdns)
|
||||||
ota:
|
ota:
|
||||||
|
@@ -1 +0,0 @@
|
|||||||
<<: !include common-enabled.yaml
|
|
@@ -1 +0,0 @@
|
|||||||
<<: !include common-enabled.yaml
|
|
Reference in New Issue
Block a user