ESPHome  2024.11.2
mqtt_client.cpp
Go to the documentation of this file.
1 #include "mqtt_client.h"
2 
3 #ifdef USE_MQTT
4 
5 #include <utility>
8 #include "esphome/core/helpers.h"
9 #include "esphome/core/log.h"
10 #include "esphome/core/version.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 
25 namespace esphome {
26 namespace mqtt {
27 
28 static const char *const TAG = "mqtt";
29 
31  global_mqtt_client = this;
33 }
34 
35 // Connection
37  ESP_LOGCONFIG(TAG, "Setting up MQTT...");
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) {
60  logger::global_logger->add_on_log_callback([this](int level, const char *tag, const char *message) {
61  if (level <= this->log_level_ && this->is_connected()) {
62  this->publish({.topic = this->log_message_.topic,
63  .payload = message,
64  .qos = this->log_message_.qos,
65  .retain = this->log_message_.retain});
66  }
67  });
68  }
69 #endif
70 
71  if (this->is_discovery_ip_enabled()) {
72  this->subscribe(
73  "esphome/discover", [this](const std::string &topic, const std::string &payload) { this->send_device_info_(); },
74  2);
75 
76  std::string topic = "esphome/ping/";
77  topic.append(App.get_name());
78  this->subscribe(
79  topic, [this](const std::string &topic, const std::string &payload) { this->send_device_info_(); }, 2);
80  }
81 
82  if (this->enable_on_boot_) {
83  this->enable();
84  }
85 }
86 
88  if (!this->is_connected() or !this->is_discovery_ip_enabled()) {
89  return;
90  }
91  std::string topic = "esphome/discover/";
92  topic.append(App.get_name());
93 
94  this->publish_json(
95  topic,
96  [](JsonObject root) {
97  uint8_t index = 0;
98  for (auto &ip : network::get_ip_addresses()) {
99  if (ip.is_set()) {
100  root["ip" + (index == 0 ? "" : esphome::to_string(index))] = ip.str();
101  index++;
102  }
103  }
104  root["name"] = App.get_name();
105  if (!App.get_friendly_name().empty()) {
106  root["friendly_name"] = App.get_friendly_name();
107  }
108 #ifdef USE_API
109  root["port"] = api::global_api_server->get_port();
110 #endif
111  root["version"] = ESPHOME_VERSION;
112  root["mac"] = get_mac_address();
113 
114 #ifdef USE_ESP8266
115  root["platform"] = "ESP8266";
116 #endif
117 #ifdef USE_ESP32
118  root["platform"] = "ESP32";
119 #endif
120 #ifdef USE_LIBRETINY
121  root["platform"] = lt_cpu_get_model_name();
122 #endif
123 
124  root["board"] = ESPHOME_BOARD;
125 #if defined(USE_WIFI)
126  root["network"] = "wifi";
127 #elif defined(USE_ETHERNET)
128  root["network"] = "ethernet";
129 #endif
130 
131 #ifdef ESPHOME_PROJECT_NAME
132  root["project_name"] = ESPHOME_PROJECT_NAME;
133  root["project_version"] = ESPHOME_PROJECT_VERSION;
134 #endif // ESPHOME_PROJECT_NAME
135 
136 #ifdef USE_DASHBOARD_IMPORT
137  root["package_import_url"] = dashboard_import::get_package_import_url();
138 #endif
139 
140 #ifdef USE_API_NOISE
141  root["api_encryption"] = "Noise_NNpsk0_25519_ChaChaPoly_SHA256";
142 #endif
143  },
144  2, this->discovery_info_.retain);
145 }
146 
148  ESP_LOGCONFIG(TAG, "MQTT:");
149  ESP_LOGCONFIG(TAG, " Server Address: %s:%u (%s)", this->credentials_.address.c_str(), this->credentials_.port,
150  this->ip_.str().c_str());
151  ESP_LOGCONFIG(TAG, " Username: " LOG_SECRET("'%s'"), this->credentials_.username.c_str());
152  ESP_LOGCONFIG(TAG, " Client ID: " LOG_SECRET("'%s'"), this->credentials_.client_id.c_str());
153  ESP_LOGCONFIG(TAG, " Clean Session: %s", YESNO(this->credentials_.clean_session));
154  if (this->is_discovery_ip_enabled()) {
155  ESP_LOGCONFIG(TAG, " Discovery IP enabled");
156  }
157  if (!this->discovery_info_.prefix.empty()) {
158  ESP_LOGCONFIG(TAG, " Discovery prefix: '%s'", this->discovery_info_.prefix.c_str());
159  ESP_LOGCONFIG(TAG, " Discovery retain: %s", YESNO(this->discovery_info_.retain));
160  }
161  ESP_LOGCONFIG(TAG, " Topic Prefix: '%s'", this->topic_prefix_.c_str());
162  if (!this->log_message_.topic.empty()) {
163  ESP_LOGCONFIG(TAG, " Log Topic: '%s'", this->log_message_.topic.c_str());
164  }
165  if (!this->availability_.topic.empty()) {
166  ESP_LOGCONFIG(TAG, " Availability: '%s'", this->availability_.topic.c_str());
167  }
168 }
170  return network::is_disabled() || this->state_ == MQTT_CLIENT_DISABLED || this->is_connected();
171 }
172 
174  for (auto &subscription : this->subscriptions_) {
175  subscription.subscribed = false;
176  subscription.resubscribe_timeout = 0;
177  }
178 
179  this->status_set_warning();
180  this->dns_resolve_error_ = false;
181  this->dns_resolved_ = false;
182  ip_addr_t addr;
183 #if USE_NETWORK_IPV6
184  err_t err = dns_gethostbyname_addrtype(this->credentials_.address.c_str(), &addr,
185  MQTTClientComponent::dns_found_callback, this, LWIP_DNS_ADDRTYPE_IPV6_IPV4);
186 #else
187  err_t err = dns_gethostbyname_addrtype(this->credentials_.address.c_str(), &addr,
188  MQTTClientComponent::dns_found_callback, this, LWIP_DNS_ADDRTYPE_IPV4);
189 #endif /* USE_NETWORK_IPV6 */
190  switch (err) {
191  case ERR_OK: {
192  // Got IP immediately
193  this->dns_resolved_ = true;
194  this->ip_ = network::IPAddress(&addr);
195  this->start_connect_();
196  return;
197  }
198  case ERR_INPROGRESS: {
199  // wait for callback
200  ESP_LOGD(TAG, "Resolving MQTT broker IP address...");
201  break;
202  }
203  default:
204  case ERR_ARG: {
205  // error
206  ESP_LOGW(TAG, "Error resolving MQTT broker IP address: %d", err);
207  break;
208  }
209  }
210 
212  this->connect_begin_ = millis();
213 }
215  if (!this->dns_resolved_ && millis() - this->connect_begin_ > 20000) {
216  this->dns_resolve_error_ = true;
217  }
218 
219  if (this->dns_resolve_error_) {
220  ESP_LOGW(TAG, "Couldn't resolve IP address for '%s'!", this->credentials_.address.c_str());
222  return;
223  }
224 
225  if (!this->dns_resolved_) {
226  return;
227  }
228 
229  ESP_LOGD(TAG, "Resolved broker IP address to %s", this->ip_.str().c_str());
230  this->start_connect_();
231 }
232 #if defined(USE_ESP8266) && LWIP_VERSION_MAJOR == 1
233 void MQTTClientComponent::dns_found_callback(const char *name, ip_addr_t *ipaddr, void *callback_arg) {
234 #else
235 void MQTTClientComponent::dns_found_callback(const char *name, const ip_addr_t *ipaddr, void *callback_arg) {
236 #endif
237  auto *a_this = (MQTTClientComponent *) callback_arg;
238  if (ipaddr == nullptr) {
239  a_this->dns_resolve_error_ = true;
240  } else {
241  a_this->ip_ = network::IPAddress(ipaddr);
242  a_this->dns_resolved_ = true;
243  }
244 }
245 
247  if (!network::is_connected())
248  return;
249 
250  ESP_LOGI(TAG, "Connecting to MQTT...");
251  // Force disconnect first
252  this->mqtt_backend_.disconnect();
253 
254  this->mqtt_backend_.set_client_id(this->credentials_.client_id.c_str());
256  const char *username = nullptr;
257  if (!this->credentials_.username.empty())
258  username = this->credentials_.username.c_str();
259  const char *password = nullptr;
260  if (!this->credentials_.password.empty())
261  password = this->credentials_.password.c_str();
262 
263  this->mqtt_backend_.set_credentials(username, password);
264 
265  this->mqtt_backend_.set_server(this->credentials_.address.c_str(), this->credentials_.port);
266  if (!this->last_will_.topic.empty()) {
267  this->mqtt_backend_.set_will(this->last_will_.topic.c_str(), this->last_will_.qos, this->last_will_.retain,
268  this->last_will_.payload.c_str());
269  }
270 
271  this->mqtt_backend_.connect();
273  this->connect_begin_ = millis();
274 }
276  return this->state_ == MQTT_CLIENT_CONNECTED && this->mqtt_backend_.connected();
277 }
278 
280  if (!this->mqtt_backend_.connected()) {
281  if (millis() - this->connect_begin_ > 60000) {
283  this->start_dnslookup_();
284  }
285  return;
286  }
287 
289  this->sent_birth_message_ = false;
290  this->status_clear_warning();
291  ESP_LOGI(TAG, "MQTT Connected!");
292  // MQTT Client needs some time to be fully set up.
293  delay(100); // NOLINT
294 
296  this->send_device_info_();
297 
298  for (MQTTComponent *component : this->children_)
299  component->schedule_resend_state();
300 }
301 
303  // Call the backend loop first
305 
306  if (this->disconnect_reason_.has_value()) {
307  const LogString *reason_s;
308  switch (*this->disconnect_reason_) {
310  reason_s = LOG_STR("TCP disconnected");
311  break;
313  reason_s = LOG_STR("Unacceptable Protocol Version");
314  break;
316  reason_s = LOG_STR("Identifier Rejected");
317  break;
319  reason_s = LOG_STR("Server Unavailable");
320  break;
322  reason_s = LOG_STR("Malformed Credentials");
323  break;
325  reason_s = LOG_STR("Not Authorized");
326  break;
328  reason_s = LOG_STR("Not Enough Space");
329  break;
331  reason_s = LOG_STR("TLS Bad Fingerprint");
332  break;
333  default:
334  reason_s = LOG_STR("Unknown");
335  break;
336  }
337  if (!network::is_connected()) {
338  reason_s = LOG_STR("WiFi disconnected");
339  }
340  ESP_LOGW(TAG, "MQTT Disconnected: %s.", LOG_STR_ARG(reason_s));
341  this->disconnect_reason_.reset();
342  }
343 
344  const uint32_t now = millis();
345 
346  switch (this->state_) {
348  return; // Return to avoid a reboot when disabled
350  if (now - this->connect_begin_ > 5000) {
351  this->start_dnslookup_();
352  }
353  break;
355  this->check_dnslookup_();
356  break;
358  this->check_connected();
359  break;
361  if (!this->mqtt_backend_.connected()) {
363  ESP_LOGW(TAG, "Lost MQTT Client connection!");
364  this->start_dnslookup_();
365  } else {
366  if (!this->birth_message_.topic.empty() && !this->sent_birth_message_) {
367  this->sent_birth_message_ = this->publish(this->birth_message_);
368  }
369 
370  this->last_connected_ = now;
372  }
373  break;
374  }
375 
376  if (millis() - this->last_connected_ > this->reboot_timeout_ && this->reboot_timeout_ != 0) {
377  ESP_LOGE(TAG, "Can't connect to MQTT... Restarting...");
378  App.reboot();
379  }
380 }
382 
383 // Subscribe
384 bool MQTTClientComponent::subscribe_(const char *topic, uint8_t qos) {
385  if (!this->is_connected())
386  return false;
387 
388  bool ret = this->mqtt_backend_.subscribe(topic, qos);
389  yield();
390 
391  if (ret) {
392  ESP_LOGV(TAG, "subscribe(topic='%s')", topic);
393  } else {
394  delay(5);
395  ESP_LOGV(TAG, "Subscribe failed for topic='%s'. Will retry later.", topic);
396  this->status_momentary_warning("subscribe", 1000);
397  }
398  return ret != 0;
399 }
400 void MQTTClientComponent::resubscribe_subscription_(MQTTSubscription *sub) {
401  if (sub->subscribed)
402  return;
403 
404  const uint32_t now = millis();
405  bool do_resub = sub->resubscribe_timeout == 0 || now - sub->resubscribe_timeout > 1000;
406 
407  if (do_resub) {
408  sub->subscribed = this->subscribe_(sub->topic.c_str(), sub->qos);
409  sub->resubscribe_timeout = now;
410  }
411 }
413  for (auto &subscription : this->subscriptions_) {
414  this->resubscribe_subscription_(&subscription);
415  }
416 }
417 
418 void MQTTClientComponent::subscribe(const std::string &topic, mqtt_callback_t callback, uint8_t qos) {
419  MQTTSubscription subscription{
420  .topic = topic,
421  .qos = qos,
422  .callback = std::move(callback),
423  .subscribed = false,
424  .resubscribe_timeout = 0,
425  };
426  this->resubscribe_subscription_(&subscription);
427  this->subscriptions_.push_back(subscription);
428 }
429 
430 void MQTTClientComponent::subscribe_json(const std::string &topic, const mqtt_json_callback_t &callback, uint8_t qos) {
431  auto f = [callback](const std::string &topic, const std::string &payload) {
432  json::parse_json(payload, [topic, callback](JsonObject root) -> bool {
433  callback(topic, root);
434  return true;
435  });
436  };
437  MQTTSubscription subscription{
438  .topic = topic,
439  .qos = qos,
440  .callback = f,
441  .subscribed = false,
442  .resubscribe_timeout = 0,
443  };
444  this->resubscribe_subscription_(&subscription);
445  this->subscriptions_.push_back(subscription);
446 }
447 
448 void MQTTClientComponent::unsubscribe(const std::string &topic) {
449  bool ret = this->mqtt_backend_.unsubscribe(topic.c_str());
450  yield();
451  if (ret) {
452  ESP_LOGV(TAG, "unsubscribe(topic='%s')", topic.c_str());
453  } else {
454  delay(5);
455  ESP_LOGV(TAG, "Unsubscribe failed for topic='%s'.", topic.c_str());
456  this->status_momentary_warning("unsubscribe", 1000);
457  }
458 
459  auto it = subscriptions_.begin();
460  while (it != subscriptions_.end()) {
461  if (it->topic == topic) {
462  it = subscriptions_.erase(it);
463  } else {
464  ++it;
465  }
466  }
467 }
468 
469 // Publish
470 bool MQTTClientComponent::publish(const std::string &topic, const std::string &payload, uint8_t qos, bool retain) {
471  return this->publish(topic, payload.data(), payload.size(), qos, retain);
472 }
473 
474 bool MQTTClientComponent::publish(const std::string &topic, const char *payload, size_t payload_length, uint8_t qos,
475  bool retain) {
476  return publish({.topic = topic, .payload = payload, .qos = qos, .retain = retain});
477 }
478 
479 bool MQTTClientComponent::publish(const MQTTMessage &message) {
480  if (!this->is_connected()) {
481  // critical components will re-transmit their messages
482  return false;
483  }
484  bool logging_topic = this->log_message_.topic == message.topic;
485  bool ret = this->mqtt_backend_.publish(message);
486  delay(0);
487  if (!ret && !logging_topic && this->is_connected()) {
488  delay(0);
489  ret = this->mqtt_backend_.publish(message);
490  delay(0);
491  }
492 
493  if (!logging_topic) {
494  if (ret) {
495  ESP_LOGV(TAG, "Publish(topic='%s' payload='%s' retain=%d qos=%d)", message.topic.c_str(), message.payload.c_str(),
496  message.retain, message.qos);
497  } else {
498  ESP_LOGV(TAG, "Publish failed for topic='%s' (len=%u). will retry later..", message.topic.c_str(),
499  message.payload.length());
500  this->status_momentary_warning("publish", 1000);
501  }
502  }
503  return ret != 0;
504 }
505 bool MQTTClientComponent::publish_json(const std::string &topic, const json::json_build_t &f, uint8_t qos,
506  bool retain) {
507  std::string message = json::build_json(f);
508  return this->publish(topic, message, qos, retain);
509 }
510 
512  if (this->state_ != MQTT_CLIENT_DISABLED)
513  return;
514  ESP_LOGD(TAG, "Enabling MQTT...");
516  this->last_connected_ = millis();
517  this->start_dnslookup_();
518 }
519 
521  if (this->state_ == MQTT_CLIENT_DISABLED)
522  return;
523  ESP_LOGD(TAG, "Disabling MQTT...");
525  this->on_shutdown();
526 }
527 
539 static bool topic_match(const char *message, const char *subscription, bool is_normal, bool past_separator) {
540  // Reached end of both strings at the same time, this means we have a successful match
541  if (*message == '\0' && *subscription == '\0')
542  return true;
543 
544  // Either the message or the subscribe are at the end. This means they don't match.
545  if (*message == '\0' || *subscription == '\0')
546  return false;
547 
548  bool do_wildcards = is_normal || past_separator;
549 
550  if (*subscription == '+' && do_wildcards) {
551  // single level wildcard
552  // consume + from subscription
553  subscription++;
554  // consume everything from message until '/' found or end of string
555  while (*message != '\0' && *message != '/') {
556  message++;
557  }
558  // after this, both pointers will point to a '/' or to the end of the string
559 
560  return topic_match(message, subscription, is_normal, true);
561  }
562 
563  if (*subscription == '#' && do_wildcards) {
564  // multilevel wildcard - MQTT mandates that this must be at end of subscribe topic
565  return true;
566  }
567 
568  // this handles '/' and normal characters at the same time.
569  if (*message != *subscription)
570  return false;
571 
572  past_separator = past_separator || *subscription == '/';
573 
574  // consume characters
575  subscription++;
576  message++;
577 
578  return topic_match(message, subscription, is_normal, past_separator);
579 }
580 
581 static bool topic_match(const char *message, const char *subscription) {
582  return topic_match(message, subscription, *message != '\0' && *message != '$', false);
583 }
584 
585 void MQTTClientComponent::on_message(const std::string &topic, const std::string &payload) {
586 #ifdef USE_ESP8266
587  // on ESP8266, this is called in lwIP/AsyncTCP task; some components do not like running
588  // from a different task.
589  this->defer([this, topic, payload]() {
590 #endif
591  for (auto &subscription : this->subscriptions_) {
592  if (topic_match(topic.c_str(), subscription.topic.c_str()))
593  subscription.callback(topic, payload);
594  }
595 #ifdef USE_ESP8266
596  });
597 #endif
598 }
599 
600 // Setters
602 bool MQTTClientComponent::is_log_message_enabled() const { return !this->log_message_.topic.empty(); }
603 void MQTTClientComponent::set_reboot_timeout(uint32_t reboot_timeout) { this->reboot_timeout_ = reboot_timeout; }
604 void MQTTClientComponent::register_mqtt_component(MQTTComponent *component) { this->children_.push_back(component); }
605 void MQTTClientComponent::set_log_level(int level) { this->log_level_ = level; }
606 void MQTTClientComponent::set_keep_alive(uint16_t keep_alive_s) { this->mqtt_backend_.set_keep_alive(keep_alive_s); }
607 void MQTTClientComponent::set_log_message_template(MQTTMessage &&message) { this->log_message_ = std::move(message); }
608 const MQTTDiscoveryInfo &MQTTClientComponent::get_discovery_info() const { return this->discovery_info_; }
609 void MQTTClientComponent::set_topic_prefix(const std::string &topic_prefix) { this->topic_prefix_ = topic_prefix; }
610 const std::string &MQTTClientComponent::get_topic_prefix() const { return this->topic_prefix_; }
612  this->birth_message_.topic = "";
614 }
616  this->shutdown_message_.topic = "";
618 }
619 bool MQTTClientComponent::is_discovery_enabled() const { return !this->discovery_info_.prefix.empty(); }
621 const Availability &MQTTClientComponent::get_availability() { return this->availability_; }
623  if (this->birth_message_.topic.empty() || this->birth_message_.topic != this->last_will_.topic) {
624  this->availability_.topic = "";
625  return;
626  }
627  this->availability_.topic = this->birth_message_.topic;
630 }
631 
632 void MQTTClientComponent::set_last_will(MQTTMessage &&message) {
633  this->last_will_ = std::move(message);
635 }
636 
637 void MQTTClientComponent::set_birth_message(MQTTMessage &&message) {
638  this->birth_message_ = std::move(message);
640 }
641 
642 void MQTTClientComponent::set_shutdown_message(MQTTMessage &&message) { this->shutdown_message_ = std::move(message); }
643 
644 void MQTTClientComponent::set_discovery_info(std::string &&prefix, MQTTDiscoveryUniqueIdGenerator unique_id_generator,
645  MQTTDiscoveryObjectIdGenerator object_id_generator, bool retain,
646  bool discover_ip, bool clean) {
647  this->discovery_info_.prefix = std::move(prefix);
648  this->discovery_info_.discover_ip = discover_ip;
649  this->discovery_info_.unique_id_generator = unique_id_generator;
650  this->discovery_info_.object_id_generator = object_id_generator;
651  this->discovery_info_.retain = retain;
652  this->discovery_info_.clean = clean;
653 }
654 
656 
658  this->discovery_info_ = MQTTDiscoveryInfo{
659  .prefix = "",
660  .retain = false,
661  .discover_ip = false,
662  .clean = false,
663  .unique_id_generator = MQTT_LEGACY_UNIQUE_ID_GENERATOR,
664  .object_id_generator = MQTT_NONE_OBJECT_ID_GENERATOR,
665  };
666 }
668  if (!this->shutdown_message_.topic.empty()) {
669  yield();
670  this->publish(this->shutdown_message_);
671  yield();
672  }
673  this->mqtt_backend_.disconnect();
674 }
675 
677  this->mqtt_backend_.set_on_connect(std::forward<mqtt_on_connect_callback_t>(callback));
678 }
679 
681  this->mqtt_backend_.set_on_disconnect(std::forward<mqtt_on_disconnect_callback_t>(callback));
682 }
683 
684 #if ASYNC_TCP_SSL_ENABLED
685 void MQTTClientComponent::add_ssl_fingerprint(const std::array<uint8_t, SHA1_SIZE> &fingerprint) {
686  this->mqtt_backend_.setSecure(true);
687  this->mqtt_backend_.addServerFingerprint(fingerprint.data());
688 }
689 #endif
690 
691 MQTTClientComponent *global_mqtt_client = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
692 
693 // MQTTMessageTrigger
694 MQTTMessageTrigger::MQTTMessageTrigger(std::string topic) : topic_(std::move(topic)) {}
695 void MQTTMessageTrigger::set_qos(uint8_t qos) { this->qos_ = qos; }
696 void MQTTMessageTrigger::set_payload(const std::string &payload) { this->payload_ = payload; }
698  global_mqtt_client->subscribe(
699  this->topic_,
700  [this](const std::string &topic, const std::string &payload) {
701  if (this->payload_.has_value() && payload != *this->payload_) {
702  return;
703  }
704 
705  this->trigger(payload);
706  },
707  this->qos_);
708 }
710  ESP_LOGCONFIG(TAG, "MQTT Message Trigger:");
711  ESP_LOGCONFIG(TAG, " Topic: '%s'", this->topic_.c_str());
712  ESP_LOGCONFIG(TAG, " QoS: %u", this->qos_);
713 }
715 
716 } // namespace mqtt
717 } // namespace esphome
718 
719 #endif // USE_MQTT
const Availability & get_availability()
const char * name
Definition: stm32flash.h:78
void add_on_log_callback(std::function< void(int, const char *, const char *)> &&callback)
Register a callback that will be called for every log message sent.
Definition: logger.cpp:178
void set_on_disconnect(std::function< on_disconnect_callback_t > &&callback) final
void disable_last_will()
Remove the last will testament message.
const float AFTER_CONNECTION
For components that should be initialized after a data connection (API/MQTT) is connected.
Definition: component.cpp:27
bool clean_session
Whether the session will be cleaned or remembered between connects.
Definition: mqtt_client.h:54
std::string topic
Empty means disabled.
Definition: mqtt_client.h:59
const float AFTER_WIFI
For components that should be initialized after WiFi is connected.
Definition: component.cpp:26
MQTTDiscoveryUniqueIdGenerator unique_id_generator
Definition: mqtt_client.h:85
void status_set_warning(const char *message="unspecified")
Definition: component.cpp:151
std::function< void(const std::string &, const std::string &)> mqtt_callback_t
Callback for MQTT subscriptions.
Definition: mqtt_client.h:35
std::string client_id
The client ID. Will automatically be truncated to 23 characters.
Definition: mqtt_client.h:53
bool unsubscribe(const char *topic) final
MQTTDiscoveryInfo discovery_info_
The discovery info options for Home Assistant.
Definition: mqtt_client.h:299
void status_momentary_warning(const std::string &name, uint32_t length=5000)
Definition: component.cpp:178
void set_server(network::IPAddress ip, uint16_t port) final
std::string str() const
Definition: ip_address.h:122
std::vector< MQTTComponent * > children_
Definition: mqtt_client.h:326
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&#39;s valid.
Definition: json_util.cpp:65
void set_client_id(const char *client_id) final
void defer(const std::string &name, std::function< void()> &&f)
Defer a callback to the next loop() call.
Definition: component.cpp:130
STL namespace.
const std::string & get_friendly_name() const
Get the friendly name of this Application set by pre_setup().
Definition: application.h:205
MQTTMessage last_will_
The last will message.
Definition: mqtt_client.h:289
void set_topic_prefix(const std::string &topic_prefix)
Set the topic prefix that will be prepended to all topics together with "/".
bool discover_ip
Enable the Home Assistant device discovery.
Definition: mqtt_client.h:83
std::string prefix
The Home Assistant discovery prefix. Empty means disabled.
Definition: mqtt_client.h:81
bool has_value() const
Definition: optional.h:87
void unsubscribe(const std::string &topic)
Unsubscribe from an MQTT topic.
void recalculate_availability_()
Re-calculate the availability property.
bool subscribe_(const char *topic, uint8_t qos)
const std::string & get_topic_prefix() const
Get the topic prefix of this device, using default if necessary.
std::function< MQTTBackend::on_connect_callback_t > mqtt_on_connect_callback_t
Callback for MQTT events.
Definition: mqtt_client.h:28
bool is_connected()
Return whether the node is connected to the network (through wifi, eth, ...)
Definition: util.cpp:15
uint32_t IRAM_ATTR HOT millis()
Definition: core.cpp:25
void set_on_connect(mqtt_on_connect_callback_t &&callback)
void set_log_message_template(MQTTMessage &&message)
Manually set the topic used for logging.
float get_setup_priority() const override
void set_reboot_timeout(uint32_t reboot_timeout)
void set_credentials(const char *username, const char *password) final
void resubscribe_subscription_(MQTTSubscription *sub)
MQTTClientComponent * global_mqtt_client
void set_keep_alive(uint16_t keep_alive) final
Logger * global_logger
Definition: logger.cpp:198
network::IPAddresses get_ip_addresses()
Definition: util.cpp:40
const char *const TAG
Definition: spi.cpp:8
void set_payload(const std::string &payload)
void set_clean_session(bool clean_session) final
void register_mqtt_component(MQTTComponent *component)
void loop() override
Reconnect if required.
uint16_t port
The port number of the server.
Definition: mqtt_client.h:50
bool publish(const MQTTMessage &message)
Publish a MQTTMessage.
void status_clear_warning()
Definition: component.cpp:166
void set_will(const char *topic, uint8_t qos, bool retain, const char *payload) final
MQTTDiscoveryUniqueIdGenerator
available discovery unique_id generators
Definition: mqtt_client.h:65
std::string get_mac_address()
Get the device MAC address as a string, in lowercase hex notation.
Definition: helpers.cpp:706
static void dns_found_callback(const char *name, ip_addr_t *ipaddr, void *callback_arg)
void disable_birth_message()
Remove the birth message.
std::function< void(JsonObject)> json_build_t
Callback function typedef for building JsonObjects.
Definition: json_util.h:20
Application App
Global storage of Application pointer - only one Application can exist.
std::string get_package_import_url()
MQTTMessageTrigger(std::string topic)
void on_message(const std::string &topic, const std::string &payload)
bool subscribe(const char *topic, uint8_t qos) final
MQTTDiscoveryObjectIdGenerator
available discovery object_id generators
Definition: mqtt_client.h:71
std::string build_json(const json_build_t &f)
Build a JSON string with the provided json build function.
Definition: json_util.cpp:21
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 setup() override
Setup the MQTT client, registering a bunch of callbacks and attempting to connect.
const std::string & get_name() const
Get the name of this Application set by pre_setup().
Definition: application.h:202
void set_on_message(std::function< on_message_callback_t > &&callback) final
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_log_message()
Get the topic used for logging. Defaults to "<topic_prefix>/debug" and the value is cached for speed...
const MQTTDiscoveryInfo & get_discovery_info() const
Get Home Assistant discovery info.
std::string address
The address of the server without port number.
Definition: mqtt_client.h:49
bool publish(const char *topic, const char *payload, size_t length, uint8_t qos, bool retain) final
float get_setup_priority() const override
MQTT client setup priority.
bool is_disabled()
Return whether the network is disabled (only wifi for now)
Definition: util.cpp:32
std::string to_string(int value)
Definition: helpers.cpp:81
void set_last_will(MQTTMessage &&message)
Set the last will testament message.
std::string size_t len
Definition: helpers.h:293
void IRAM_ATTR HOT yield()
Definition: core.cpp:24
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.
std::function< MQTTBackend::on_disconnect_callback_t > mqtt_on_disconnect_callback_t
Definition: mqtt_client.h:29
void start_connect_()
Reconnect to the MQTT broker if not already connected.
MQTTMessage birth_message_
The birth message (e.g.
Definition: mqtt_client.h:292
in_addr ip_addr_t
Definition: ip_address.h:22
void set_shutdown_message(MQTTMessage &&message)
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
std::string payload_not_available
Definition: mqtt_client.h:61
std::vector< MQTTSubscription > subscriptions_
Definition: mqtt_client.h:312
MQTTDiscoveryObjectIdGenerator object_id_generator
Definition: mqtt_client.h:86
void disable_discovery()
Globally disable Home Assistant discovery.
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.
uint8_t qos
QoS. Only for last will testaments.
Definition: mqtt_backend.h:27
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.
optional< MQTTClientDisconnectReason > disconnect_reason_
Definition: mqtt_client.h:330
uint16_t get_port() const
Definition: api_server.cpp:378
void set_on_disconnect(mqtt_on_disconnect_callback_t &&callback)
APIServer * global_api_server
Definition: api_server.cpp:347
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.
Availability availability_
Caches availability.
Definition: mqtt_client.h:296
void set_birth_message(MQTTMessage &&message)
Set the birth message.
void set_on_connect(std::function< on_connect_callback_t > &&callback) final
bool retain
Whether to retain discovery messages.
Definition: mqtt_client.h:82
void IRAM_ATTR HOT delay(uint32_t ms)
Definition: core.cpp:26
std::function< void(const std::string &, JsonObject)> mqtt_json_callback_t
Definition: mqtt_client.h:36