ESPHome 2026.1.4
Loading...
Searching...
No Matches
mqtt_client.cpp
Go to the documentation of this file.
1#include "mqtt_client.h"
2
3#ifdef USE_MQTT
4
5#include <utility>
9#include "esphome/core/log.h"
11#ifdef USE_LOGGER
13#endif
14#include "lwip/dns.h"
15#include "lwip/err.h"
16#include "mqtt_component.h"
17
18#ifdef USE_API
20#endif
21#ifdef USE_DASHBOARD_IMPORT
23#endif
24
25namespace esphome::mqtt {
26
27static const char *const TAG = "mqtt";
28
30 global_mqtt_client = this;
31 char mac_addr[MAC_ADDRESS_BUFFER_SIZE];
33 this->credentials_.client_id = make_name_with_suffix(App.get_name(), '-', mac_addr, MAC_ADDRESS_BUFFER_SIZE - 1);
34}
35
36// Connection
39 [this](const char *topic, const char *payload, size_t len, size_t index, size_t total) {
40 if (index == 0)
41 this->payload_buffer_.reserve(total);
42
43 // append new payload, may contain incomplete MQTT message
44 this->payload_buffer_.append(payload, len);
45
46 // MQTT fully received
47 if (len + index == total) {
48 this->on_message(topic, this->payload_buffer_);
49 this->payload_buffer_.clear();
50 }
51 });
53 if (this->state_ == MQTT_CLIENT_DISABLED)
54 return;
56 this->disconnect_reason_ = reason;
57 });
58#ifdef USE_LOGGER
59 if (this->is_log_message_enabled() && logger::global_logger != nullptr) {
61 }
62#endif
63
64 if (this->is_discovery_ip_enabled()) {
65 this->subscribe(
66 "esphome/discover", [this](const std::string &topic, const std::string &payload) { this->send_device_info_(); },
67 2);
68
69 std::string topic = "esphome/ping/";
70 topic.append(App.get_name());
71 this->subscribe(
72 topic, [this](const std::string &topic, const std::string &payload) { this->send_device_info_(); }, 2);
73 }
74
75 if (this->enable_on_boot_) {
76 this->enable();
77 }
78}
79
81 if (!this->is_connected() or !this->is_discovery_ip_enabled()) {
82 return;
83 }
84 std::string topic = "esphome/discover/";
85 topic.append(App.get_name());
86
87 // NOLINTBEGIN(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
88 this->publish_json(
89 topic,
90 [](JsonObject root) {
91 uint8_t index = 0;
92 for (auto &ip : network::get_ip_addresses()) {
93 if (ip.is_set()) {
94 root["ip" + (index == 0 ? "" : esphome::to_string(index))] = ip.str();
95 index++;
96 }
97 }
98 root[ESPHOME_F("name")] = App.get_name();
99 if (!App.get_friendly_name().empty()) {
100 root[ESPHOME_F("friendly_name")] = App.get_friendly_name();
101 }
102#ifdef USE_API
103 root[ESPHOME_F("port")] = api::global_api_server->get_port();
104#endif
105 root[ESPHOME_F("version")] = ESPHOME_VERSION;
106 char mac_buf[MAC_ADDRESS_BUFFER_SIZE];
108 root[ESPHOME_F("mac")] = mac_buf;
109
110#ifdef USE_ESP8266
111 root[ESPHOME_F("platform")] = ESPHOME_F("ESP8266");
112#endif
113#ifdef USE_ESP32
114 root[ESPHOME_F("platform")] = ESPHOME_F("ESP32");
115#endif
116#ifdef USE_LIBRETINY
117 root[ESPHOME_F("platform")] = lt_cpu_get_model_name();
118#endif
119
120 root[ESPHOME_F("board")] = ESPHOME_BOARD;
121#if defined(USE_WIFI)
122 root[ESPHOME_F("network")] = ESPHOME_F("wifi");
123#elif defined(USE_ETHERNET)
124 root[ESPHOME_F("network")] = ESPHOME_F("ethernet");
125#endif
126
127#ifdef ESPHOME_PROJECT_NAME
128 root[ESPHOME_F("project_name")] = ESPHOME_PROJECT_NAME;
129 root[ESPHOME_F("project_version")] = ESPHOME_PROJECT_VERSION;
130#endif // ESPHOME_PROJECT_NAME
131
132#ifdef USE_DASHBOARD_IMPORT
133 root[ESPHOME_F("package_import_url")] = dashboard_import::get_package_import_url();
134#endif
135
136#ifdef USE_API_NOISE
137 root[api::global_api_server->get_noise_ctx().has_psk() ? ESPHOME_F("api_encryption")
138 : ESPHOME_F("api_encryption_supported")] =
139 ESPHOME_F("Noise_NNpsk0_25519_ChaChaPoly_SHA256");
140#endif
141 },
142 2, this->discovery_info_.retain);
143 // NOLINTEND(clang-analyzer-cplusplus.NewDeleteLeaks)
144}
145
146#ifdef USE_LOGGER
147void MQTTClientComponent::on_log(uint8_t level, const char *tag, const char *message, size_t message_len) {
148 (void) tag;
149 if (level <= this->log_level_ && this->is_connected()) {
150 this->publish({.topic = this->log_message_.topic,
151 .payload = std::string(message, message_len),
152 .qos = this->log_message_.qos,
153 .retain = this->log_message_.retain});
154 }
155}
156#endif
157
159 char ip_buf[network::IP_ADDRESS_BUFFER_SIZE];
160 // clang-format off
161 ESP_LOGCONFIG(TAG,
162 "MQTT:\n"
163 " Server Address: %s:%u (%s)\n"
164 " Username: " LOG_SECRET("'%s'") "\n"
165 " Client ID: " LOG_SECRET("'%s'") "\n"
166 " Clean Session: %s",
167 this->credentials_.address.c_str(), this->credentials_.port, this->ip_.str_to(ip_buf),
168 this->credentials_.username.c_str(), this->credentials_.client_id.c_str(),
169 YESNO(this->credentials_.clean_session));
170 // clang-format on
171 if (this->is_discovery_ip_enabled()) {
172 ESP_LOGCONFIG(TAG, " Discovery IP enabled");
173 }
174 if (!this->discovery_info_.prefix.empty()) {
175 ESP_LOGCONFIG(TAG,
176 " Discovery prefix: '%s'\n"
177 " Discovery retain: %s",
178 this->discovery_info_.prefix.c_str(), YESNO(this->discovery_info_.retain));
179 }
180 ESP_LOGCONFIG(TAG, " Topic Prefix: '%s'", this->topic_prefix_.c_str());
181 if (!this->log_message_.topic.empty()) {
182 ESP_LOGCONFIG(TAG, " Log Topic: '%s'", this->log_message_.topic.c_str());
183 }
184 if (!this->availability_.topic.empty()) {
185 ESP_LOGCONFIG(TAG, " Availability: '%s'", this->availability_.topic.c_str());
186 }
187}
189 return network::is_disabled() || this->state_ == MQTT_CLIENT_DISABLED || this->is_connected() ||
191}
192
194 for (auto &subscription : this->subscriptions_) {
195 subscription.subscribed = false;
196 subscription.resubscribe_timeout = 0;
197 }
198
199 this->status_set_warning();
200 this->dns_resolve_error_ = false;
201 this->dns_resolved_ = false;
202 ip_addr_t addr;
203 err_t err;
204 {
205 LwIPLock lock;
206#if USE_NETWORK_IPV6
207 err = dns_gethostbyname_addrtype(this->credentials_.address.c_str(), &addr, MQTTClientComponent::dns_found_callback,
208 this, LWIP_DNS_ADDRTYPE_IPV6_IPV4);
209#else
210 err = dns_gethostbyname_addrtype(this->credentials_.address.c_str(), &addr, MQTTClientComponent::dns_found_callback,
211 this, LWIP_DNS_ADDRTYPE_IPV4);
212#endif /* USE_NETWORK_IPV6 */
213 }
214 switch (err) {
215 case ERR_OK: {
216 // Got IP immediately
217 this->dns_resolved_ = true;
218 this->ip_ = network::IPAddress(&addr);
219 this->start_connect_();
220 return;
221 }
222 case ERR_INPROGRESS: {
223 // wait for callback
224 ESP_LOGD(TAG, "Resolving broker IP address");
225 break;
226 }
227 default:
228 case ERR_ARG: {
229 // error
230 ESP_LOGW(TAG, "Error resolving broker IP address: %d", err);
231 break;
232 }
233 }
234
236 this->connect_begin_ = millis();
237}
239 if (!this->dns_resolved_ && millis() - this->connect_begin_ > 20000) {
240 this->dns_resolve_error_ = true;
241 }
242
243 if (this->dns_resolve_error_) {
244 ESP_LOGW(TAG, "Couldn't resolve IP address for '%s'", this->credentials_.address.c_str());
248 return;
249 }
250
251 if (!this->dns_resolved_) {
252 return;
253 }
254
255 char ip_buf[network::IP_ADDRESS_BUFFER_SIZE];
256 ESP_LOGD(TAG, "Resolved broker IP address to %s", this->ip_.str_to(ip_buf));
257 this->start_connect_();
258}
259#if defined(USE_ESP8266) && LWIP_VERSION_MAJOR == 1
260void MQTTClientComponent::dns_found_callback(const char *name, ip_addr_t *ipaddr, void *callback_arg) {
261#else
262void MQTTClientComponent::dns_found_callback(const char *name, const ip_addr_t *ipaddr, void *callback_arg) {
263#endif
264 auto *a_this = (MQTTClientComponent *) callback_arg;
265 if (ipaddr == nullptr) {
266 a_this->dns_resolve_error_ = true;
267 } else {
268 a_this->ip_ = network::IPAddress(ipaddr);
269 a_this->dns_resolved_ = true;
270 }
271}
272
275 return;
276
277 ESP_LOGI(TAG, "Connecting");
278 // Force disconnect first
280
283 const char *username = nullptr;
284 if (!this->credentials_.username.empty())
285 username = this->credentials_.username.c_str();
286 const char *password = nullptr;
287 if (!this->credentials_.password.empty())
288 password = this->credentials_.password.c_str();
289
290 this->mqtt_backend_.set_credentials(username, password);
291
292 this->mqtt_backend_.set_server(this->credentials_.address.c_str(), this->credentials_.port);
293 if (!this->last_will_.topic.empty()) {
294 this->mqtt_backend_.set_will(this->last_will_.topic.c_str(), this->last_will_.qos, this->last_will_.retain,
295 this->last_will_.payload.c_str());
296 }
297
298 this->mqtt_backend_.connect();
300 this->connect_begin_ = millis();
301}
303 return this->state_ == MQTT_CLIENT_CONNECTED && this->mqtt_backend_.connected();
304}
305
307 if (!this->mqtt_backend_.connected()) {
308 if (millis() - this->connect_begin_ > 60000) {
310 this->start_dnslookup_();
311 }
312 return;
313 }
314
316 this->sent_birth_message_ = false;
317 this->status_clear_warning();
318 ESP_LOGI(TAG, "Connected");
319 // MQTT Client needs some time to be fully set up.
320 delay(100); // NOLINT
321
323 this->send_device_info_();
324
325 for (MQTTComponent *component : this->children_)
326 component->schedule_resend_state();
327}
328
330 // Call the backend loop first
332
333 if (this->disconnect_reason_.has_value()) {
334 const LogString *reason_s;
335 switch (*this->disconnect_reason_) {
337 reason_s = LOG_STR("TCP disconnected");
338 break;
340 reason_s = LOG_STR("Unacceptable Protocol Version");
341 break;
343 reason_s = LOG_STR("Identifier Rejected");
344 break;
346 reason_s = LOG_STR("Server Unavailable");
347 break;
349 reason_s = LOG_STR("Malformed Credentials");
350 break;
352 reason_s = LOG_STR("Not Authorized");
353 break;
355 reason_s = LOG_STR("Not Enough Space");
356 break;
358 reason_s = LOG_STR("TLS Bad Fingerprint");
359 break;
360 default:
361 reason_s = LOG_STR("Unknown");
362 break;
363 }
364 if (!network::is_connected()) {
365 reason_s = LOG_STR("WiFi disconnected");
366 }
367 ESP_LOGW(TAG, "Disconnected: %s", LOG_STR_ARG(reason_s));
369 }
370
372
373 switch (this->state_) {
375 return; // Return to avoid a reboot when disabled
377 if (now - this->connect_begin_ > 5000) {
378 this->start_dnslookup_();
379 }
380 break;
382 this->check_dnslookup_();
383 break;
385 this->check_connected();
386 break;
388 if (!this->mqtt_backend_.connected()) {
390 ESP_LOGW(TAG, "Lost client connection");
391 this->start_dnslookup_();
392 } else {
393 if (!this->birth_message_.topic.empty() && !this->sent_birth_message_) {
394 this->sent_birth_message_ = this->publish(this->birth_message_);
395 }
396
397 this->last_connected_ = now;
399 }
400 break;
401 }
402
403 if (millis() - this->last_connected_ > this->reboot_timeout_ && this->reboot_timeout_ != 0) {
404 ESP_LOGE(TAG, "Can't connect; restarting");
405 App.reboot();
406 }
407}
409
410// Subscribe
411bool MQTTClientComponent::subscribe_(const char *topic, uint8_t qos) {
412 if (!this->is_connected())
413 return false;
414
415 bool ret = this->mqtt_backend_.subscribe(topic, qos);
416 yield();
417
418 if (ret) {
419 ESP_LOGV(TAG, "subscribe(topic='%s')", topic);
420 } else {
421 delay(5);
422 ESP_LOGV(TAG, "Subscribe failed for topic='%s'. Will retry", topic);
423 this->status_momentary_warning("subscribe", 1000);
424 }
425 return ret != 0;
426}
427void MQTTClientComponent::resubscribe_subscription_(MQTTSubscription *sub) {
428 if (sub->subscribed)
429 return;
430
431 const uint32_t now = millis();
432 bool do_resub = sub->resubscribe_timeout == 0 || now - sub->resubscribe_timeout > 1000;
433
434 if (do_resub) {
435 sub->subscribed = this->subscribe_(sub->topic.c_str(), sub->qos);
436 sub->resubscribe_timeout = now;
437 }
438}
440 for (auto &subscription : this->subscriptions_) {
441 this->resubscribe_subscription_(&subscription);
442 }
443}
444
445void MQTTClientComponent::subscribe(const std::string &topic, mqtt_callback_t callback, uint8_t qos) {
446 MQTTSubscription subscription{
447 .topic = topic,
448 .qos = qos,
449 .callback = std::move(callback),
450 .subscribed = false,
451 .resubscribe_timeout = 0,
452 };
453 this->resubscribe_subscription_(&subscription);
454 this->subscriptions_.push_back(subscription);
455}
456
457void MQTTClientComponent::subscribe_json(const std::string &topic, const mqtt_json_callback_t &callback, uint8_t qos) {
458 auto f = [callback](const std::string &topic, const std::string &payload) {
459 json::parse_json(payload, [topic, callback](JsonObject root) -> bool {
460 callback(topic, root);
461 return true;
462 });
463 };
464 MQTTSubscription subscription{
465 .topic = topic,
466 .qos = qos,
467 .callback = f,
468 .subscribed = false,
469 .resubscribe_timeout = 0,
470 };
471 this->resubscribe_subscription_(&subscription);
472 this->subscriptions_.push_back(subscription);
473}
474
475void MQTTClientComponent::unsubscribe(const std::string &topic) {
476 bool ret = this->mqtt_backend_.unsubscribe(topic.c_str());
477 yield();
478 if (ret) {
479 ESP_LOGV(TAG, "unsubscribe(topic='%s')", topic.c_str());
480 } else {
481 delay(5);
482 ESP_LOGV(TAG, "Unsubscribe failed for topic='%s'.", topic.c_str());
483 this->status_momentary_warning("unsubscribe", 1000);
484 }
485
486 auto it = subscriptions_.begin();
487 while (it != subscriptions_.end()) {
488 if (it->topic == topic) {
489 it = subscriptions_.erase(it);
490 } else {
491 ++it;
492 }
493 }
494}
495
496// Publish
497bool MQTTClientComponent::publish(const std::string &topic, const std::string &payload, uint8_t qos, bool retain) {
498 return this->publish(topic, payload.data(), payload.size(), qos, retain);
499}
500
501bool MQTTClientComponent::publish(const std::string &topic, const char *payload, size_t payload_length, uint8_t qos,
502 bool retain) {
503 return publish({.topic = topic, .payload = std::string(payload, payload_length), .qos = qos, .retain = retain});
504}
505
506bool MQTTClientComponent::publish(const MQTTMessage &message) {
507 if (!this->is_connected()) {
508 // critical components will re-transmit their messages
509 return false;
510 }
511 bool logging_topic = this->log_message_.topic == message.topic;
512 bool ret = this->mqtt_backend_.publish(message);
513 delay(0);
514 if (!ret && !logging_topic && this->is_connected()) {
515 delay(0);
516 ret = this->mqtt_backend_.publish(message);
517 delay(0);
518 }
519
520 if (!logging_topic) {
521 if (ret) {
522 ESP_LOGV(TAG, "Publish(topic='%s' payload='%s' retain=%d qos=%d)", message.topic.c_str(), message.payload.c_str(),
523 message.retain, message.qos);
524 } else {
525 ESP_LOGV(TAG, "Publish failed for topic='%s' (len=%u). Will retry", message.topic.c_str(),
526 message.payload.length());
527 this->status_momentary_warning("publish", 1000);
528 }
529 }
530 return ret != 0;
531}
532bool MQTTClientComponent::publish_json(const std::string &topic, const json::json_build_t &f, uint8_t qos,
533 bool retain) {
534 std::string message = json::build_json(f);
535 return this->publish(topic, message, qos, retain);
536}
537
539 if (this->state_ != MQTT_CLIENT_DISABLED)
540 return;
541 ESP_LOGD(TAG, "Enabling");
543 this->last_connected_ = millis();
544 this->start_dnslookup_();
545}
546
548 if (this->state_ == MQTT_CLIENT_DISABLED)
549 return;
550 ESP_LOGD(TAG, "Disabling");
552 this->on_shutdown();
553}
554
566static bool topic_match(const char *message, const char *subscription, bool is_normal, bool past_separator) {
567 // Reached end of both strings at the same time, this means we have a successful match
568 if (*message == '\0' && *subscription == '\0')
569 return true;
570
571 // Either the message or the subscribe are at the end. This means they don't match.
572 if (*message == '\0' || *subscription == '\0')
573 return false;
574
575 bool do_wildcards = is_normal || past_separator;
576
577 if (*subscription == '+' && do_wildcards) {
578 // single level wildcard
579 // consume + from subscription
580 subscription++;
581 // consume everything from message until '/' found or end of string
582 while (*message != '\0' && *message != '/') {
583 message++;
584 }
585 // after this, both pointers will point to a '/' or to the end of the string
586
587 return topic_match(message, subscription, is_normal, true);
588 }
589
590 if (*subscription == '#' && do_wildcards) {
591 // multilevel wildcard - MQTT mandates that this must be at end of subscribe topic
592 return true;
593 }
594
595 // this handles '/' and normal characters at the same time.
596 if (*message != *subscription)
597 return false;
598
599 past_separator = past_separator || *subscription == '/';
600
601 // consume characters
602 subscription++;
603 message++;
604
605 return topic_match(message, subscription, is_normal, past_separator);
606}
607
608static bool topic_match(const char *message, const char *subscription) {
609 return topic_match(message, subscription, *message != '\0' && *message != '$', false);
610}
611
612void MQTTClientComponent::on_message(const std::string &topic, const std::string &payload) {
613#ifdef USE_ESP8266
614 // on ESP8266, this is called in lwIP/AsyncTCP task; some components do not like running
615 // from a different task.
616 this->defer([this, topic, payload]() {
617#endif
618 for (auto &subscription : this->subscriptions_) {
619 if (topic_match(topic.c_str(), subscription.topic.c_str()))
620 subscription.callback(topic, payload);
621 }
622#ifdef USE_ESP8266
623 });
624#endif
625}
626
627// Setters
629bool MQTTClientComponent::is_log_message_enabled() const { return !this->log_message_.topic.empty(); }
630void MQTTClientComponent::set_reboot_timeout(uint32_t reboot_timeout) { this->reboot_timeout_ = reboot_timeout; }
631void MQTTClientComponent::register_mqtt_component(MQTTComponent *component) { this->children_.push_back(component); }
632void MQTTClientComponent::set_log_level(int level) { this->log_level_ = level; }
633void MQTTClientComponent::set_keep_alive(uint16_t keep_alive_s) { this->mqtt_backend_.set_keep_alive(keep_alive_s); }
634void MQTTClientComponent::set_log_message_template(MQTTMessage &&message) { this->log_message_ = std::move(message); }
635const MQTTDiscoveryInfo &MQTTClientComponent::get_discovery_info() const { return this->discovery_info_; }
636void MQTTClientComponent::set_topic_prefix(const std::string &topic_prefix, const std::string &check_topic_prefix) {
637 if (App.is_name_add_mac_suffix_enabled() && (topic_prefix == check_topic_prefix)) {
639 } else {
640 this->topic_prefix_ = topic_prefix;
641 }
642}
643const std::string &MQTTClientComponent::get_topic_prefix() const { return this->topic_prefix_; }
644void MQTTClientComponent::set_publish_nan_as_none(bool publish_nan_as_none) {
645 this->publish_nan_as_none_ = publish_nan_as_none;
646}
649 this->birth_message_.topic = "";
651}
653 this->shutdown_message_.topic = "";
655}
656bool MQTTClientComponent::is_discovery_enabled() const { return !this->discovery_info_.prefix.empty(); }
658const Availability &MQTTClientComponent::get_availability() { return this->availability_; }
660 if (this->birth_message_.topic.empty() || this->birth_message_.topic != this->last_will_.topic) {
661 this->availability_.topic = "";
662 return;
663 }
667}
668
670 this->last_will_ = std::move(message);
672}
673
675 this->birth_message_ = std::move(message);
677}
678
679void MQTTClientComponent::set_shutdown_message(MQTTMessage &&message) { this->shutdown_message_ = std::move(message); }
680
681void MQTTClientComponent::set_discovery_info(std::string &&prefix, MQTTDiscoveryUniqueIdGenerator unique_id_generator,
682 MQTTDiscoveryObjectIdGenerator object_id_generator, bool retain,
683 bool discover_ip, bool clean) {
684 this->discovery_info_.prefix = std::move(prefix);
685 this->discovery_info_.discover_ip = discover_ip;
686 this->discovery_info_.unique_id_generator = unique_id_generator;
687 this->discovery_info_.object_id_generator = object_id_generator;
688 this->discovery_info_.retain = retain;
689 this->discovery_info_.clean = clean;
690}
691
693
695 this->discovery_info_ = MQTTDiscoveryInfo{
696 .prefix = "",
697 .retain = false,
698 .discover_ip = false,
699 .clean = false,
700 .unique_id_generator = MQTT_LEGACY_UNIQUE_ID_GENERATOR,
701 .object_id_generator = MQTT_NONE_OBJECT_ID_GENERATOR,
702 };
703}
705 if (!this->shutdown_message_.topic.empty()) {
706 yield();
707 this->publish(this->shutdown_message_);
708 yield();
709 }
711}
712
714 this->mqtt_backend_.set_on_connect(std::forward<mqtt_on_connect_callback_t>(callback));
715}
716
718 auto callback_copy = callback;
719 this->mqtt_backend_.set_on_disconnect(std::forward<mqtt_on_disconnect_callback_t>(callback));
720 this->on_disconnect_.add(std::move(callback_copy));
721}
722
723#if ASYNC_TCP_SSL_ENABLED
724void MQTTClientComponent::add_ssl_fingerprint(const std::array<uint8_t, SHA1_SIZE> &fingerprint) {
725 this->mqtt_backend_.setSecure(true);
726 this->mqtt_backend_.addServerFingerprint(fingerprint.data());
727}
728#endif
729
730MQTTClientComponent *global_mqtt_client = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
731
732// MQTTMessageTrigger
733MQTTMessageTrigger::MQTTMessageTrigger(std::string topic) : topic_(std::move(topic)) {}
734void MQTTMessageTrigger::set_qos(uint8_t qos) { this->qos_ = qos; }
735void MQTTMessageTrigger::set_payload(const std::string &payload) { this->payload_ = payload; }
736void MQTTMessageTrigger::setup() {
738 this->topic_,
739 [this](const std::string &topic, const std::string &payload) {
740 if (this->payload_.has_value() && payload != *this->payload_) {
741 return;
742 }
743
744 this->trigger(payload);
745 },
746 this->qos_);
747}
748void MQTTMessageTrigger::dump_config() {
749 ESP_LOGCONFIG(TAG,
750 "MQTT Message Trigger:\n"
751 " Topic: '%s'\n"
752 " QoS: %u",
753 this->topic_.c_str(), this->qos_);
754}
755float MQTTMessageTrigger::get_setup_priority() const { return setup_priority::AFTER_CONNECTION; }
756
757} // namespace esphome::mqtt
758
759#endif // USE_MQTT
const std::string & get_friendly_name() const
Get the friendly name of this Application set by pre_setup().
bool is_name_add_mac_suffix_enabled() const
const std::string & get_name() const
Get the name of this Application set by pre_setup().
uint32_t IRAM_ATTR HOT get_loop_component_start_time() const
Get the cached time in milliseconds from when the current component started its loop execution.
ESPDEPRECATED("Use const char* overload instead. Removed in 2026.7.0", "2026.1.0") void defer(const std voi defer)(const char *name, std::function< void()> &&f)
Defer a callback to the next loop() call.
Definition component.h:492
void status_set_warning(const char *message=nullptr)
void status_momentary_warning(const char *name, uint32_t length=5000)
Set warning status flag and automatically clear it after a timeout.
void status_clear_warning()
APINoiseContext & get_noise_ctx()
Definition api_server.h:78
uint16_t get_port() const
void add_log_listener(LogListener *listener)
Register a log listener to receive log messages.
Definition logger.h:217
void set_keep_alive(uint16_t keep_alive) final
void set_on_message(std::function< on_message_callback_t > &&callback) final
void set_client_id(const char *client_id) final
void set_on_connect(std::function< on_connect_callback_t > &&callback) final
void set_will(const char *topic, uint8_t qos, bool retain, const char *payload) final
bool subscribe(const char *topic, uint8_t qos) final
void set_server(network::IPAddress ip, uint16_t port) final
bool publish(const char *topic, const char *payload, size_t length, uint8_t qos, bool retain) final
void set_clean_session(bool clean_session) final
bool unsubscribe(const char *topic) final
void set_on_disconnect(std::function< on_disconnect_callback_t > &&callback) final
void set_credentials(const char *username, const char *password) final
void set_birth_message(MQTTMessage &&message)
Set the birth message.
void start_connect_()
Reconnect to the MQTT broker if not already connected.
void setup() override
Setup the MQTT client, registering a bunch of callbacks and attempting to connect.
void disable_discovery()
Globally disable Home Assistant discovery.
void recalculate_availability_()
Re-calculate the availability property.
void set_discovery_info(std::string &&prefix, MQTTDiscoveryUniqueIdGenerator unique_id_generator, MQTTDiscoveryObjectIdGenerator object_id_generator, bool retain, bool discover_ip, bool clean=false)
Set the Home Assistant discovery info.
void set_reboot_timeout(uint32_t reboot_timeout)
float get_setup_priority() const override
MQTT client setup priority.
void disable_log_message()
Get the topic used for logging. Defaults to "<topic_prefix>/debug" and the value is cached for speed.
const std::string & get_topic_prefix() const
Get the topic prefix of this device, using default if necessary.
void subscribe_json(const std::string &topic, const mqtt_json_callback_t &callback, uint8_t qos=0)
Subscribe to a MQTT topic and automatically parse JSON payload.
void register_mqtt_component(MQTTComponent *component)
void set_last_will(MQTTMessage &&message)
Set the last will testament message.
bool publish(const MQTTMessage &message)
Publish a MQTTMessage.
const MQTTDiscoveryInfo & get_discovery_info() const
Get Home Assistant discovery info.
void add_ssl_fingerprint(const std::array< uint8_t, SHA1_SIZE > &fingerprint)
Add a SSL fingerprint to use for TCP SSL connections to the MQTT broker.
void disable_birth_message()
Remove the birth message.
static void dns_found_callback(const char *name, ip_addr_t *ipaddr, void *callback_arg)
void subscribe(const std::string &topic, mqtt_callback_t callback, uint8_t qos=0)
Subscribe to an MQTT topic and call callback when a message is received.
MQTTMessage last_will_
The last will message.
void set_topic_prefix(const std::string &topic_prefix, const std::string &check_topic_prefix)
Set the topic prefix that will be prepended to all topics together with "/".
void set_shutdown_message(MQTTMessage &&message)
MQTTMessage birth_message_
The birth message (e.g.
std::vector< MQTTComponent * > children_
void set_on_connect(mqtt_on_connect_callback_t &&callback)
optional< MQTTClientDisconnectReason > disconnect_reason_
void unsubscribe(const std::string &topic)
Unsubscribe from an MQTT topic.
void on_log(uint8_t level, const char *tag, const char *message, size_t message_len) override
void set_publish_nan_as_none(bool publish_nan_as_none)
void on_message(const std::string &topic, const std::string &payload)
void set_log_message_template(MQTTMessage &&message)
Manually set the topic used for logging.
void resubscribe_subscription_(MQTTSubscription *sub)
void set_on_disconnect(mqtt_on_disconnect_callback_t &&callback)
bool subscribe_(const char *topic, uint8_t qos)
const Availability & get_availability()
std::vector< MQTTSubscription > subscriptions_
bool publish_json(const std::string &topic, const json::json_build_t &f, uint8_t qos=0, bool retain=false)
Construct and send a JSON MQTT message.
void disable_last_will()
Remove the last will testament message.
void set_keep_alive(uint16_t keep_alive_s)
Set the keep alive time in seconds, every 0.7*keep_alive a ping will be sent.
void loop() override
Reconnect if required.
MQTTDiscoveryInfo discovery_info_
The discovery info options for Home Assistant.
CallbackManager< MQTTBackend::on_disconnect_callback_t > on_disconnect_
Availability availability_
Caches availability.
MQTTMessageTrigger(std::string topic)
bool has_value() const
Definition optional.h:92
const Component * component
Definition component.cpp:37
const char * message
Definition component.cpp:38
in_addr ip_addr_t
Definition ip_address.h:22
APIServer * global_api_server
const char * get_package_import_url()
std::function< void(JsonObject)> json_build_t
Callback function typedef for building JsonObjects.
Definition json_util.h:46
bool parse_json(const std::string &data, const json_parse_t &f)
Parse a JSON string and run the provided json parse function if it's valid.
Definition json_util.cpp:27
std::string build_json(const json_build_t &f)
Build a JSON string with the provided json build function.
Definition json_util.cpp:18
Logger * global_logger
std::function< MQTTBackend::on_disconnect_callback_t > mqtt_on_disconnect_callback_t
Definition mqtt_client.h:32
MQTTDiscoveryObjectIdGenerator
available discovery object_id generators
Definition mqtt_client.h:74
@ MQTT_NONE_OBJECT_ID_GENERATOR
Definition mqtt_client.h:75
MQTTDiscoveryUniqueIdGenerator
available discovery unique_id generators
Definition mqtt_client.h:68
@ MQTT_LEGACY_UNIQUE_ID_GENERATOR
Definition mqtt_client.h:69
std::function< void(const std::string &, JsonObject)> mqtt_json_callback_t
Definition mqtt_client.h:39
std::function< void(const std::string &, const std::string &)> mqtt_callback_t
Callback for MQTT subscriptions.
Definition mqtt_client.h:38
MQTTClientComponent * global_mqtt_client
@ MQTT_CLIENT_DISCONNECTED
Definition mqtt_client.h:94
@ MQTT_CLIENT_RESOLVING_ADDRESS
Definition mqtt_client.h:95
std::function< MQTTBackend::on_connect_callback_t > mqtt_on_connect_callback_t
Callback for MQTT events.
Definition mqtt_client.h:31
bool is_connected()
Return whether the node is connected to the network (through wifi, eth, ...)
Definition util.cpp:26
network::IPAddresses get_ip_addresses()
Definition util.cpp:66
bool is_disabled()
Return whether the network is disabled (only wifi for now)
Definition util.cpp:53
const float AFTER_WIFI
For components that should be initialized after WiFi is connected.
Definition component.cpp:88
const char *const TAG
Definition spi.cpp:7
std::string str_sanitize(const std::string &str)
Sanitizes the input string by removing all characters but alphanumerics, dashes and underscores.
Definition helpers.cpp:202
std::string size_t len
Definition helpers.h:595
void IRAM_ATTR HOT yield()
Definition core.cpp:24
void get_mac_address_into_buffer(std::span< char, MAC_ADDRESS_BUFFER_SIZE > buf)
Get the device MAC address into the given buffer, in lowercase hex notation.
Definition helpers.cpp:731
void IRAM_ATTR HOT delay(uint32_t ms)
Definition core.cpp:26
uint32_t IRAM_ATTR HOT millis()
Definition core.cpp:25
Application App
Global storage of Application pointer - only one Application can exist.
std::string make_name_with_suffix(const char *name, size_t name_len, char sep, const char *suffix_ptr, size_t suffix_len)
Optimized string concatenation: name + separator + suffix (const char* overload) Uses a fixed stack b...
Definition helpers.cpp:262
std::string payload_not_available
Definition mqtt_client.h:64
std::string topic
Empty means disabled.
Definition mqtt_client.h:62
std::string address
The address of the server without port number.
Definition mqtt_client.h:52
bool clean_session
Whether the session will be cleaned or remembered between connects.
Definition mqtt_client.h:57
std::string client_id
The client ID. Will automatically be truncated to 23 characters.
Definition mqtt_client.h:56
MQTTDiscoveryUniqueIdGenerator unique_id_generator
Definition mqtt_client.h:88
bool discover_ip
Enable the Home Assistant device discovery.
Definition mqtt_client.h:86
std::string prefix
The Home Assistant discovery prefix. Empty means disabled.
Definition mqtt_client.h:84
MQTTDiscoveryObjectIdGenerator object_id_generator
Definition mqtt_client.h:89
bool retain
Whether to retain discovery messages.
Definition mqtt_client.h:85
uint8_t qos
QoS. Only for last will testaments.
char * str_to(char *buf) const
Write IP address to buffer. Buffer must be at least IP_ADDRESS_BUFFER_SIZE bytes.
Definition ip_address.h:69