ESPHome 2025.10.3
Loading...
Searching...
No Matches
mdns_component.cpp
Go to the documentation of this file.
2#ifdef USE_MDNS
4#include "esphome/core/log.h"
6#include "mdns_component.h"
7
8#ifdef USE_ESP8266
9#include <pgmspace.h>
10// Macro to define strings in PROGMEM on ESP8266, regular memory on other platforms
11#define MDNS_STATIC_CONST_CHAR(name, value) static const char name[] PROGMEM = value
12#else
13// On non-ESP8266 platforms, use regular const char*
14#define MDNS_STATIC_CONST_CHAR(name, value) static constexpr const char name[] = value
15#endif
16
17#ifdef USE_API
19#endif
20#ifdef USE_DASHBOARD_IMPORT
22#endif
23
24namespace esphome {
25namespace mdns {
26
27static const char *const TAG = "mdns";
28
29#ifndef USE_WEBSERVER_PORT
30#define USE_WEBSERVER_PORT 80 // NOLINT
31#endif
32
33// Define all constant strings using the macro
34MDNS_STATIC_CONST_CHAR(SERVICE_TCP, "_tcp");
35
36// Wrap build-time defines into flash storage
37MDNS_STATIC_CONST_CHAR(VALUE_VERSION, ESPHOME_VERSION);
38
40 this->hostname_ = App.get_name();
41
42 // IMPORTANT: The #ifdef blocks below must match COMPONENTS_WITH_MDNS_SERVICES
43 // in mdns/__init__.py. If you add a new service here, update both locations.
44
45#ifdef USE_API
46 MDNS_STATIC_CONST_CHAR(SERVICE_ESPHOMELIB, "_esphomelib");
47 MDNS_STATIC_CONST_CHAR(TXT_FRIENDLY_NAME, "friendly_name");
48 MDNS_STATIC_CONST_CHAR(TXT_VERSION, "version");
49 MDNS_STATIC_CONST_CHAR(TXT_MAC, "mac");
50 MDNS_STATIC_CONST_CHAR(TXT_PLATFORM, "platform");
51 MDNS_STATIC_CONST_CHAR(TXT_BOARD, "board");
52 MDNS_STATIC_CONST_CHAR(TXT_NETWORK, "network");
53 MDNS_STATIC_CONST_CHAR(VALUE_BOARD, ESPHOME_BOARD);
54
55 if (api::global_api_server != nullptr) {
56 auto &service = this->services_.emplace_next();
57 service.service_type = MDNS_STR(SERVICE_ESPHOMELIB);
58 service.proto = MDNS_STR(SERVICE_TCP);
59 service.port = api::global_api_server->get_port();
60
61 const std::string &friendly_name = App.get_friendly_name();
62 bool friendly_name_empty = friendly_name.empty();
63
64 // Calculate exact capacity for txt_records
65 size_t txt_count = 3; // version, mac, board (always present)
66 if (!friendly_name_empty) {
67 txt_count++; // friendly_name
68 }
69#if defined(USE_ESP8266) || defined(USE_ESP32) || defined(USE_RP2040) || defined(USE_LIBRETINY)
70 txt_count++; // platform
71#endif
72#if defined(USE_WIFI) || defined(USE_ETHERNET) || defined(USE_OPENTHREAD)
73 txt_count++; // network
74#endif
75#ifdef USE_API_NOISE
76 txt_count++; // api_encryption or api_encryption_supported
77#endif
78#ifdef ESPHOME_PROJECT_NAME
79 txt_count += 2; // project_name and project_version
80#endif
81#ifdef USE_DASHBOARD_IMPORT
82 txt_count++; // package_import_url
83#endif
84
85 auto &txt_records = service.txt_records;
86 txt_records.reserve(txt_count);
87
88 if (!friendly_name_empty) {
89 txt_records.push_back({MDNS_STR(TXT_FRIENDLY_NAME), MDNS_STR(friendly_name.c_str())});
90 }
91 txt_records.push_back({MDNS_STR(TXT_VERSION), MDNS_STR(VALUE_VERSION)});
92 txt_records.push_back({MDNS_STR(TXT_MAC), MDNS_STR(this->add_dynamic_txt_value(get_mac_address()))});
93
94#ifdef USE_ESP8266
95 MDNS_STATIC_CONST_CHAR(PLATFORM_ESP8266, "ESP8266");
96 txt_records.push_back({MDNS_STR(TXT_PLATFORM), MDNS_STR(PLATFORM_ESP8266)});
97#elif defined(USE_ESP32)
98 MDNS_STATIC_CONST_CHAR(PLATFORM_ESP32, "ESP32");
99 txt_records.push_back({MDNS_STR(TXT_PLATFORM), MDNS_STR(PLATFORM_ESP32)});
100#elif defined(USE_RP2040)
101 MDNS_STATIC_CONST_CHAR(PLATFORM_RP2040, "RP2040");
102 txt_records.push_back({MDNS_STR(TXT_PLATFORM), MDNS_STR(PLATFORM_RP2040)});
103#elif defined(USE_LIBRETINY)
104 txt_records.push_back({MDNS_STR(TXT_PLATFORM), MDNS_STR(lt_cpu_get_model_name())});
105#endif
106
107 txt_records.push_back({MDNS_STR(TXT_BOARD), MDNS_STR(VALUE_BOARD)});
108
109#if defined(USE_WIFI)
110 MDNS_STATIC_CONST_CHAR(NETWORK_WIFI, "wifi");
111 txt_records.push_back({MDNS_STR(TXT_NETWORK), MDNS_STR(NETWORK_WIFI)});
112#elif defined(USE_ETHERNET)
113 MDNS_STATIC_CONST_CHAR(NETWORK_ETHERNET, "ethernet");
114 txt_records.push_back({MDNS_STR(TXT_NETWORK), MDNS_STR(NETWORK_ETHERNET)});
115#elif defined(USE_OPENTHREAD)
116 MDNS_STATIC_CONST_CHAR(NETWORK_THREAD, "thread");
117 txt_records.push_back({MDNS_STR(TXT_NETWORK), MDNS_STR(NETWORK_THREAD)});
118#endif
119
120#ifdef USE_API_NOISE
121 MDNS_STATIC_CONST_CHAR(TXT_API_ENCRYPTION, "api_encryption");
122 MDNS_STATIC_CONST_CHAR(TXT_API_ENCRYPTION_SUPPORTED, "api_encryption_supported");
123 MDNS_STATIC_CONST_CHAR(NOISE_ENCRYPTION, "Noise_NNpsk0_25519_ChaChaPoly_SHA256");
124 bool has_psk = api::global_api_server->get_noise_ctx()->has_psk();
125 const char *encryption_key = has_psk ? TXT_API_ENCRYPTION : TXT_API_ENCRYPTION_SUPPORTED;
126 txt_records.push_back({MDNS_STR(encryption_key), MDNS_STR(NOISE_ENCRYPTION)});
127#endif
128
129#ifdef ESPHOME_PROJECT_NAME
130 MDNS_STATIC_CONST_CHAR(TXT_PROJECT_NAME, "project_name");
131 MDNS_STATIC_CONST_CHAR(TXT_PROJECT_VERSION, "project_version");
132 MDNS_STATIC_CONST_CHAR(VALUE_PROJECT_NAME, ESPHOME_PROJECT_NAME);
133 MDNS_STATIC_CONST_CHAR(VALUE_PROJECT_VERSION, ESPHOME_PROJECT_VERSION);
134 txt_records.push_back({MDNS_STR(TXT_PROJECT_NAME), MDNS_STR(VALUE_PROJECT_NAME)});
135 txt_records.push_back({MDNS_STR(TXT_PROJECT_VERSION), MDNS_STR(VALUE_PROJECT_VERSION)});
136#endif // ESPHOME_PROJECT_NAME
137
138#ifdef USE_DASHBOARD_IMPORT
139 MDNS_STATIC_CONST_CHAR(TXT_PACKAGE_IMPORT_URL, "package_import_url");
140 txt_records.push_back(
141 {MDNS_STR(TXT_PACKAGE_IMPORT_URL), MDNS_STR(dashboard_import::get_package_import_url().c_str())});
142#endif
143 }
144#endif // USE_API
145
146#ifdef USE_PROMETHEUS
147 MDNS_STATIC_CONST_CHAR(SERVICE_PROMETHEUS, "_prometheus-http");
148
149 auto &prom_service = this->services_.emplace_next();
150 prom_service.service_type = MDNS_STR(SERVICE_PROMETHEUS);
151 prom_service.proto = MDNS_STR(SERVICE_TCP);
152 prom_service.port = USE_WEBSERVER_PORT;
153#endif
154
155#ifdef USE_WEBSERVER
156 MDNS_STATIC_CONST_CHAR(SERVICE_HTTP, "_http");
157
158 auto &web_service = this->services_.emplace_next();
159 web_service.service_type = MDNS_STR(SERVICE_HTTP);
160 web_service.proto = MDNS_STR(SERVICE_TCP);
161 web_service.port = USE_WEBSERVER_PORT;
162#endif
163
164#if !defined(USE_API) && !defined(USE_PROMETHEUS) && !defined(USE_WEBSERVER) && !defined(USE_MDNS_EXTRA_SERVICES)
165 MDNS_STATIC_CONST_CHAR(SERVICE_HTTP, "_http");
166 MDNS_STATIC_CONST_CHAR(TXT_VERSION, "version");
167
168 // Publish "http" service if not using native API or any other services
169 // This is just to have *some* mDNS service so that .local resolution works
170 auto &fallback_service = this->services_.emplace_next();
171 fallback_service.service_type = MDNS_STR(SERVICE_HTTP);
172 fallback_service.proto = MDNS_STR(SERVICE_TCP);
173 fallback_service.port = USE_WEBSERVER_PORT;
174 fallback_service.txt_records.push_back({MDNS_STR(TXT_VERSION), MDNS_STR(VALUE_VERSION)});
175#endif
176}
177
179 ESP_LOGCONFIG(TAG,
180 "mDNS:\n"
181 " Hostname: %s",
182 this->hostname_.c_str());
183#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
184 ESP_LOGV(TAG, " Services:");
185 for (const auto &service : this->services_) {
186 ESP_LOGV(TAG, " - %s, %s, %d", MDNS_STR_ARG(service.service_type), MDNS_STR_ARG(service.proto),
187 const_cast<TemplatableValue<uint16_t> &>(service.port).value());
188 for (const auto &record : service.txt_records) {
189 ESP_LOGV(TAG, " TXT: %s = %s", MDNS_STR_ARG(record.key), MDNS_STR_ARG(record.value));
190 }
191 }
192#endif
193}
194
195} // namespace mdns
196} // namespace esphome
197#endif
const std::string & get_friendly_name() const
Get the friendly name of this Application set by pre_setup().
const std::string & get_name() const
Get the name of this Application set by pre_setup().
std::shared_ptr< APINoiseContext > get_noise_ctx()
Definition api_server.h:57
uint16_t get_port() const
const char * add_dynamic_txt_value(const std::string &value)
Add a dynamic TXT value and return pointer to it for use in MDNSTXTRecord.
StaticVector< MDNSService, MDNS_SERVICE_COUNT > services_
APIServer * global_api_server
const std::string & get_package_import_url()
MDNS_STATIC_CONST_CHAR(SERVICE_TCP, "_tcp")
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
std::string get_mac_address()
Get the device MAC address as a string, in lowercase hex notation.
Definition helpers.cpp:608
Application App
Global storage of Application pointer - only one Application can exist.