ESPHome  2024.4.1
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  });
54  this->disconnect_reason_ = reason;
55  });
56 #ifdef USE_LOGGER
57  if (this->is_log_message_enabled() && logger::global_logger != nullptr) {
58  logger::global_logger->add_on_log_callback([this](int level, const char *tag, const char *message) {
59  if (level <= this->log_level_ && this->is_connected()) {
60  this->publish({.topic = this->log_message_.topic,
61  .payload = message,
62  .qos = this->log_message_.qos,
63  .retain = this->log_message_.retain});
64  }
65  });
66  }
67 #endif
68 
69  if (this->is_discovery_enabled()) {
70  this->subscribe(
71  "esphome/discover", [this](const std::string &topic, const std::string &payload) { this->send_device_info_(); },
72  2);
73 
74  std::string topic = "esphome/ping/";
75  topic.append(App.get_name());
76  this->subscribe(
77  topic, [this](const std::string &topic, const std::string &payload) { this->send_device_info_(); }, 2);
78  }
79 
80  this->last_connected_ = millis();
81  this->start_dnslookup_();
82 }
83 
85  if (!this->is_connected() or !this->is_discovery_enabled()) {
86  return;
87  }
88  std::string topic = "esphome/discover/";
89  topic.append(App.get_name());
90 
91  this->publish_json(
92  topic,
93  [](JsonObject root) {
94  uint8_t index = 0;
95  for (auto &ip : network::get_ip_addresses()) {
96  if (ip.is_set()) {
97  root["ip" + (index == 0 ? "" : esphome::to_string(index))] = ip.str();
98  index++;
99  }
100  }
101  root["name"] = App.get_name();
102 #ifdef USE_API
103  root["port"] = api::global_api_server->get_port();
104 #endif
105  root["version"] = ESPHOME_VERSION;
106  root["mac"] = get_mac_address();
107 
108 #ifdef USE_ESP8266
109  root["platform"] = "ESP8266";
110 #endif
111 #ifdef USE_ESP32
112  root["platform"] = "ESP32";
113 #endif
114 #ifdef USE_LIBRETINY
115  root["platform"] = lt_cpu_get_model_name();
116 #endif
117 
118  root["board"] = ESPHOME_BOARD;
119 #if defined(USE_WIFI)
120  root["network"] = "wifi";
121 #elif defined(USE_ETHERNET)
122  root["network"] = "ethernet";
123 #endif
124 
125 #ifdef ESPHOME_PROJECT_NAME
126  root["project_name"] = ESPHOME_PROJECT_NAME;
127  root["project_version"] = ESPHOME_PROJECT_VERSION;
128 #endif // ESPHOME_PROJECT_NAME
129 
130 #ifdef USE_DASHBOARD_IMPORT
131  root["package_import_url"] = dashboard_import::get_package_import_url();
132 #endif
133  },
134  2, this->discovery_info_.retain);
135 }
136 
138  ESP_LOGCONFIG(TAG, "MQTT:");
139  ESP_LOGCONFIG(TAG, " Server Address: %s:%u (%s)", this->credentials_.address.c_str(), this->credentials_.port,
140  this->ip_.str().c_str());
141  ESP_LOGCONFIG(TAG, " Username: " LOG_SECRET("'%s'"), this->credentials_.username.c_str());
142  ESP_LOGCONFIG(TAG, " Client ID: " LOG_SECRET("'%s'"), this->credentials_.client_id.c_str());
143  if (!this->discovery_info_.prefix.empty()) {
144  ESP_LOGCONFIG(TAG, " Discovery prefix: '%s'", this->discovery_info_.prefix.c_str());
145  ESP_LOGCONFIG(TAG, " Discovery retain: %s", YESNO(this->discovery_info_.retain));
146  }
147  ESP_LOGCONFIG(TAG, " Topic Prefix: '%s'", this->topic_prefix_.c_str());
148  if (!this->log_message_.topic.empty()) {
149  ESP_LOGCONFIG(TAG, " Log Topic: '%s'", this->log_message_.topic.c_str());
150  }
151  if (!this->availability_.topic.empty()) {
152  ESP_LOGCONFIG(TAG, " Availability: '%s'", this->availability_.topic.c_str());
153  }
154 }
156 
158  for (auto &subscription : this->subscriptions_) {
159  subscription.subscribed = false;
160  subscription.resubscribe_timeout = 0;
161  }
162 
163  this->status_set_warning();
164  this->dns_resolve_error_ = false;
165  this->dns_resolved_ = false;
166  ip_addr_t addr;
167 #if USE_NETWORK_IPV6
168  err_t err = dns_gethostbyname_addrtype(this->credentials_.address.c_str(), &addr,
169  MQTTClientComponent::dns_found_callback, this, LWIP_DNS_ADDRTYPE_IPV6_IPV4);
170 #else
171  err_t err = dns_gethostbyname_addrtype(this->credentials_.address.c_str(), &addr,
172  MQTTClientComponent::dns_found_callback, this, LWIP_DNS_ADDRTYPE_IPV4);
173 #endif /* USE_NETWORK_IPV6 */
174  switch (err) {
175  case ERR_OK: {
176  // Got IP immediately
177  this->dns_resolved_ = true;
178  this->ip_ = network::IPAddress(&addr);
179  this->start_connect_();
180  return;
181  }
182  case ERR_INPROGRESS: {
183  // wait for callback
184  ESP_LOGD(TAG, "Resolving MQTT broker IP address...");
185  break;
186  }
187  default:
188  case ERR_ARG: {
189  // error
190  ESP_LOGW(TAG, "Error resolving MQTT broker IP address: %d", err);
191  break;
192  }
193  }
194 
196  this->connect_begin_ = millis();
197 }
199  if (!this->dns_resolved_ && millis() - this->connect_begin_ > 20000) {
200  this->dns_resolve_error_ = true;
201  }
202 
203  if (this->dns_resolve_error_) {
204  ESP_LOGW(TAG, "Couldn't resolve IP address for '%s'!", this->credentials_.address.c_str());
206  return;
207  }
208 
209  if (!this->dns_resolved_) {
210  return;
211  }
212 
213  ESP_LOGD(TAG, "Resolved broker IP address to %s", this->ip_.str().c_str());
214  this->start_connect_();
215 }
216 #if defined(USE_ESP8266) && LWIP_VERSION_MAJOR == 1
217 void MQTTClientComponent::dns_found_callback(const char *name, ip_addr_t *ipaddr, void *callback_arg) {
218 #else
219 void MQTTClientComponent::dns_found_callback(const char *name, const ip_addr_t *ipaddr, void *callback_arg) {
220 #endif
221  auto *a_this = (MQTTClientComponent *) callback_arg;
222  if (ipaddr == nullptr) {
223  a_this->dns_resolve_error_ = true;
224  } else {
225  a_this->ip_ = network::IPAddress(ipaddr);
226  a_this->dns_resolved_ = true;
227  }
228 }
229 
231  if (!network::is_connected())
232  return;
233 
234  ESP_LOGI(TAG, "Connecting to MQTT...");
235  // Force disconnect first
236  this->mqtt_backend_.disconnect();
237 
238  this->mqtt_backend_.set_client_id(this->credentials_.client_id.c_str());
239  const char *username = nullptr;
240  if (!this->credentials_.username.empty())
241  username = this->credentials_.username.c_str();
242  const char *password = nullptr;
243  if (!this->credentials_.password.empty())
244  password = this->credentials_.password.c_str();
245 
246  this->mqtt_backend_.set_credentials(username, password);
247 
248  this->mqtt_backend_.set_server(this->credentials_.address.c_str(), this->credentials_.port);
249  if (!this->last_will_.topic.empty()) {
250  this->mqtt_backend_.set_will(this->last_will_.topic.c_str(), this->last_will_.qos, this->last_will_.retain,
251  this->last_will_.payload.c_str());
252  }
253 
254  this->mqtt_backend_.connect();
256  this->connect_begin_ = millis();
257 }
259  return this->state_ == MQTT_CLIENT_CONNECTED && this->mqtt_backend_.connected();
260 }
261 
263  if (!this->mqtt_backend_.connected()) {
264  if (millis() - this->connect_begin_ > 60000) {
266  this->start_dnslookup_();
267  }
268  return;
269  }
270 
272  this->sent_birth_message_ = false;
273  this->status_clear_warning();
274  ESP_LOGI(TAG, "MQTT Connected!");
275  // MQTT Client needs some time to be fully set up.
276  delay(100); // NOLINT
277 
279  this->send_device_info_();
280 
281  for (MQTTComponent *component : this->children_)
282  component->schedule_resend_state();
283 }
284 
286  // Call the backend loop first
288 
289  if (this->disconnect_reason_.has_value()) {
290  const LogString *reason_s;
291  switch (*this->disconnect_reason_) {
293  reason_s = LOG_STR("TCP disconnected");
294  break;
296  reason_s = LOG_STR("Unacceptable Protocol Version");
297  break;
299  reason_s = LOG_STR("Identifier Rejected");
300  break;
302  reason_s = LOG_STR("Server Unavailable");
303  break;
305  reason_s = LOG_STR("Malformed Credentials");
306  break;
308  reason_s = LOG_STR("Not Authorized");
309  break;
311  reason_s = LOG_STR("Not Enough Space");
312  break;
314  reason_s = LOG_STR("TLS Bad Fingerprint");
315  break;
316  default:
317  reason_s = LOG_STR("Unknown");
318  break;
319  }
320  if (!network::is_connected()) {
321  reason_s = LOG_STR("WiFi disconnected");
322  }
323  ESP_LOGW(TAG, "MQTT Disconnected: %s.", LOG_STR_ARG(reason_s));
324  this->disconnect_reason_.reset();
325  }
326 
327  const uint32_t now = millis();
328 
329  switch (this->state_) {
331  if (now - this->connect_begin_ > 5000) {
332  this->start_dnslookup_();
333  }
334  break;
336  this->check_dnslookup_();
337  break;
339  this->check_connected();
340  break;
342  if (!this->mqtt_backend_.connected()) {
344  ESP_LOGW(TAG, "Lost MQTT Client connection!");
345  this->start_dnslookup_();
346  } else {
347  if (!this->birth_message_.topic.empty() && !this->sent_birth_message_) {
348  this->sent_birth_message_ = this->publish(this->birth_message_);
349  }
350 
351  this->last_connected_ = now;
353  }
354  break;
355  }
356 
357  if (millis() - this->last_connected_ > this->reboot_timeout_ && this->reboot_timeout_ != 0) {
358  ESP_LOGE(TAG, "Can't connect to MQTT... Restarting...");
359  App.reboot();
360  }
361 }
363 
364 // Subscribe
365 bool MQTTClientComponent::subscribe_(const char *topic, uint8_t qos) {
366  if (!this->is_connected())
367  return false;
368 
369  bool ret = this->mqtt_backend_.subscribe(topic, qos);
370  yield();
371 
372  if (ret) {
373  ESP_LOGV(TAG, "subscribe(topic='%s')", topic);
374  } else {
375  delay(5);
376  ESP_LOGV(TAG, "Subscribe failed for topic='%s'. Will retry later.", topic);
377  this->status_momentary_warning("subscribe", 1000);
378  }
379  return ret != 0;
380 }
381 void MQTTClientComponent::resubscribe_subscription_(MQTTSubscription *sub) {
382  if (sub->subscribed)
383  return;
384 
385  const uint32_t now = millis();
386  bool do_resub = sub->resubscribe_timeout == 0 || now - sub->resubscribe_timeout > 1000;
387 
388  if (do_resub) {
389  sub->subscribed = this->subscribe_(sub->topic.c_str(), sub->qos);
390  sub->resubscribe_timeout = now;
391  }
392 }
394  for (auto &subscription : this->subscriptions_) {
395  this->resubscribe_subscription_(&subscription);
396  }
397 }
398 
399 void MQTTClientComponent::subscribe(const std::string &topic, mqtt_callback_t callback, uint8_t qos) {
400  MQTTSubscription subscription{
401  .topic = topic,
402  .qos = qos,
403  .callback = std::move(callback),
404  .subscribed = false,
405  .resubscribe_timeout = 0,
406  };
407  this->resubscribe_subscription_(&subscription);
408  this->subscriptions_.push_back(subscription);
409 }
410 
411 void MQTTClientComponent::subscribe_json(const std::string &topic, const mqtt_json_callback_t &callback, uint8_t qos) {
412  auto f = [callback](const std::string &topic, const std::string &payload) {
413  json::parse_json(payload, [topic, callback](JsonObject root) { callback(topic, root); });
414  };
415  MQTTSubscription subscription{
416  .topic = topic,
417  .qos = qos,
418  .callback = f,
419  .subscribed = false,
420  .resubscribe_timeout = 0,
421  };
422  this->resubscribe_subscription_(&subscription);
423  this->subscriptions_.push_back(subscription);
424 }
425 
426 void MQTTClientComponent::unsubscribe(const std::string &topic) {
427  bool ret = this->mqtt_backend_.unsubscribe(topic.c_str());
428  yield();
429  if (ret) {
430  ESP_LOGV(TAG, "unsubscribe(topic='%s')", topic.c_str());
431  } else {
432  delay(5);
433  ESP_LOGV(TAG, "Unsubscribe failed for topic='%s'.", topic.c_str());
434  this->status_momentary_warning("unsubscribe", 1000);
435  }
436 
437  auto it = subscriptions_.begin();
438  while (it != subscriptions_.end()) {
439  if (it->topic == topic) {
440  it = subscriptions_.erase(it);
441  } else {
442  ++it;
443  }
444  }
445 }
446 
447 // Publish
448 bool MQTTClientComponent::publish(const std::string &topic, const std::string &payload, uint8_t qos, bool retain) {
449  return this->publish(topic, payload.data(), payload.size(), qos, retain);
450 }
451 
452 bool MQTTClientComponent::publish(const std::string &topic, const char *payload, size_t payload_length, uint8_t qos,
453  bool retain) {
454  return publish({.topic = topic, .payload = payload, .qos = qos, .retain = retain});
455 }
456 
457 bool MQTTClientComponent::publish(const MQTTMessage &message) {
458  if (!this->is_connected()) {
459  // critical components will re-transmit their messages
460  return false;
461  }
462  bool logging_topic = this->log_message_.topic == message.topic;
463  bool ret = this->mqtt_backend_.publish(message);
464  delay(0);
465  if (!ret && !logging_topic && this->is_connected()) {
466  delay(0);
467  ret = this->mqtt_backend_.publish(message);
468  delay(0);
469  }
470 
471  if (!logging_topic) {
472  if (ret) {
473  ESP_LOGV(TAG, "Publish(topic='%s' payload='%s' retain=%d qos=%d)", message.topic.c_str(), message.payload.c_str(),
474  message.retain, message.qos);
475  } else {
476  ESP_LOGV(TAG, "Publish failed for topic='%s' (len=%u). will retry later..", message.topic.c_str(),
477  message.payload.length());
478  this->status_momentary_warning("publish", 1000);
479  }
480  }
481  return ret != 0;
482 }
483 bool MQTTClientComponent::publish_json(const std::string &topic, const json::json_build_t &f, uint8_t qos,
484  bool retain) {
485  std::string message = json::build_json(f);
486  return this->publish(topic, message, qos, retain);
487 }
488 
500 static bool topic_match(const char *message, const char *subscription, bool is_normal, bool past_separator) {
501  // Reached end of both strings at the same time, this means we have a successful match
502  if (*message == '\0' && *subscription == '\0')
503  return true;
504 
505  // Either the message or the subscribe are at the end. This means they don't match.
506  if (*message == '\0' || *subscription == '\0')
507  return false;
508 
509  bool do_wildcards = is_normal || past_separator;
510 
511  if (*subscription == '+' && do_wildcards) {
512  // single level wildcard
513  // consume + from subscription
514  subscription++;
515  // consume everything from message until '/' found or end of string
516  while (*message != '\0' && *message != '/') {
517  message++;
518  }
519  // after this, both pointers will point to a '/' or to the end of the string
520 
521  return topic_match(message, subscription, is_normal, true);
522  }
523 
524  if (*subscription == '#' && do_wildcards) {
525  // multilevel wildcard - MQTT mandates that this must be at end of subscribe topic
526  return true;
527  }
528 
529  // this handles '/' and normal characters at the same time.
530  if (*message != *subscription)
531  return false;
532 
533  past_separator = past_separator || *subscription == '/';
534 
535  // consume characters
536  subscription++;
537  message++;
538 
539  return topic_match(message, subscription, is_normal, past_separator);
540 }
541 
542 static bool topic_match(const char *message, const char *subscription) {
543  return topic_match(message, subscription, *message != '\0' && *message != '$', false);
544 }
545 
546 void MQTTClientComponent::on_message(const std::string &topic, const std::string &payload) {
547 #ifdef USE_ESP8266
548  // on ESP8266, this is called in lwIP/AsyncTCP task; some components do not like running
549  // from a different task.
550  this->defer([this, topic, payload]() {
551 #endif
552  for (auto &subscription : this->subscriptions_) {
553  if (topic_match(topic.c_str(), subscription.topic.c_str()))
554  subscription.callback(topic, payload);
555  }
556 #ifdef USE_ESP8266
557  });
558 #endif
559 }
560 
561 // Setters
563 bool MQTTClientComponent::is_log_message_enabled() const { return !this->log_message_.topic.empty(); }
564 void MQTTClientComponent::set_reboot_timeout(uint32_t reboot_timeout) { this->reboot_timeout_ = reboot_timeout; }
565 void MQTTClientComponent::register_mqtt_component(MQTTComponent *component) { this->children_.push_back(component); }
566 void MQTTClientComponent::set_log_level(int level) { this->log_level_ = level; }
567 void MQTTClientComponent::set_keep_alive(uint16_t keep_alive_s) { this->mqtt_backend_.set_keep_alive(keep_alive_s); }
568 void MQTTClientComponent::set_log_message_template(MQTTMessage &&message) { this->log_message_ = std::move(message); }
569 const MQTTDiscoveryInfo &MQTTClientComponent::get_discovery_info() const { return this->discovery_info_; }
570 void MQTTClientComponent::set_topic_prefix(const std::string &topic_prefix) { this->topic_prefix_ = topic_prefix; }
571 const std::string &MQTTClientComponent::get_topic_prefix() const { return this->topic_prefix_; }
573  this->birth_message_.topic = "";
575 }
577  this->shutdown_message_.topic = "";
579 }
580 bool MQTTClientComponent::is_discovery_enabled() const { return !this->discovery_info_.prefix.empty(); }
581 const Availability &MQTTClientComponent::get_availability() { return this->availability_; }
583  if (this->birth_message_.topic.empty() || this->birth_message_.topic != this->last_will_.topic) {
584  this->availability_.topic = "";
585  return;
586  }
587  this->availability_.topic = this->birth_message_.topic;
590 }
591 
592 void MQTTClientComponent::set_last_will(MQTTMessage &&message) {
593  this->last_will_ = std::move(message);
595 }
596 
597 void MQTTClientComponent::set_birth_message(MQTTMessage &&message) {
598  this->birth_message_ = std::move(message);
600 }
601 
602 void MQTTClientComponent::set_shutdown_message(MQTTMessage &&message) { this->shutdown_message_ = std::move(message); }
603 
604 void MQTTClientComponent::set_discovery_info(std::string &&prefix, MQTTDiscoveryUniqueIdGenerator unique_id_generator,
605  MQTTDiscoveryObjectIdGenerator object_id_generator, bool retain,
606  bool clean) {
607  this->discovery_info_.prefix = std::move(prefix);
608  this->discovery_info_.unique_id_generator = unique_id_generator;
609  this->discovery_info_.object_id_generator = object_id_generator;
610  this->discovery_info_.retain = retain;
611  this->discovery_info_.clean = clean;
612 }
613 
615 
617  this->discovery_info_ = MQTTDiscoveryInfo{
618  .prefix = "",
619  .retain = false,
620  .clean = false,
621  .unique_id_generator = MQTT_LEGACY_UNIQUE_ID_GENERATOR,
622  .object_id_generator = MQTT_NONE_OBJECT_ID_GENERATOR,
623  };
624 }
626  if (!this->shutdown_message_.topic.empty()) {
627  yield();
628  this->publish(this->shutdown_message_);
629  yield();
630  }
631  this->mqtt_backend_.disconnect();
632 }
633 
635  this->mqtt_backend_.set_on_connect(std::forward<mqtt_on_connect_callback_t>(callback));
636 }
637 
639  this->mqtt_backend_.set_on_disconnect(std::forward<mqtt_on_disconnect_callback_t>(callback));
640 }
641 
642 #if ASYNC_TCP_SSL_ENABLED
643 void MQTTClientComponent::add_ssl_fingerprint(const std::array<uint8_t, SHA1_SIZE> &fingerprint) {
644  this->mqtt_backend_.setSecure(true);
645  this->mqtt_backend_.addServerFingerprint(fingerprint.data());
646 }
647 #endif
648 
649 MQTTClientComponent *global_mqtt_client = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
650 
651 // MQTTMessageTrigger
652 MQTTMessageTrigger::MQTTMessageTrigger(std::string topic) : topic_(std::move(topic)) {}
653 void MQTTMessageTrigger::set_qos(uint8_t qos) { this->qos_ = qos; }
654 void MQTTMessageTrigger::set_payload(const std::string &payload) { this->payload_ = payload; }
656  global_mqtt_client->subscribe(
657  this->topic_,
658  [this](const std::string &topic, const std::string &payload) {
659  if (this->payload_.has_value() && payload != *this->payload_) {
660  return;
661  }
662 
663  this->trigger(payload);
664  },
665  this->qos_);
666 }
668  ESP_LOGCONFIG(TAG, "MQTT Message Trigger:");
669  ESP_LOGCONFIG(TAG, " Topic: '%s'", this->topic_.c_str());
670  ESP_LOGCONFIG(TAG, " QoS: %u", this->qos_);
671 }
673 
674 } // namespace mqtt
675 } // namespace esphome
676 
677 #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:159
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
void 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
std::string topic
Empty means disabled.
Definition: mqtt_client.h:58
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:83
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:290
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:120
std::vector< MQTTComponent * > children_
Definition: mqtt_client.h:315
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.
MQTTMessage last_will_
The last will message.
Definition: mqtt_client.h:280
void set_topic_prefix(const std::string &topic_prefix)
Set the topic prefix that will be prepended to all topics together with "/".
std::string prefix
The Home Assistant discovery prefix. Empty means disabled.
Definition: mqtt_client.h:80
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.
void set_discovery_info(std::string &&prefix, MQTTDiscoveryUniqueIdGenerator unique_id_generator, MQTTDiscoveryObjectIdGenerator object_id_generator, bool retain, bool clean=false)
Set the Home Assistant discovery info.
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:179
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 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:64
std::string get_mac_address()
Get the device MAC address as a string, in lowercase hex notation.
Definition: helpers.cpp:587
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:70
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 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:174
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:82
void set_last_will(MQTTMessage &&message)
Set the last will testament message.
std::string size_t len
Definition: helpers.h:292
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:283
in_addr ip_addr_t
Definition: ip_address.h:20
void set_shutdown_message(MQTTMessage &&message)
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
Definition: a01nyub.cpp:7
std::string payload_not_available
Definition: mqtt_client.h:60
std::vector< MQTTSubscription > subscriptions_
Definition: mqtt_client.h:302
MQTTDiscoveryObjectIdGenerator object_id_generator
Definition: mqtt_client.h:84
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:26
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:319
uint16_t get_port() const
Definition: api_server.cpp:335
void set_on_disconnect(mqtt_on_disconnect_callback_t &&callback)
APIServer * global_api_server
Definition: api_server.cpp:314
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:287
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:81
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