21#ifdef USE_DASHBOARD_IMPORT
28static const char *
const TAG =
"mqtt";
37 ESP_LOGCONFIG(TAG,
"Setting up MQTT...");
39 [
this](
const char *topic,
const char *payload,
size_t len,
size_t index,
size_t total) {
47 if (
len + index == total) {
73 "esphome/discover", [
this](
const std::string &topic,
const std::string &payload) { this->
send_device_info_(); },
76 std::string topic =
"esphome/ping/";
79 topic, [
this](
const std::string &topic,
const std::string &payload) { this->
send_device_info_(); }, 2);
91 std::string topic =
"esphome/discover/";
111 root[
"version"] = ESPHOME_VERSION;
115 root[
"platform"] =
"ESP8266";
118 root[
"platform"] =
"ESP32";
121 root[
"platform"] = lt_cpu_get_model_name();
124 root[
"board"] = ESPHOME_BOARD;
126 root[
"network"] =
"wifi";
127#elif defined(USE_ETHERNET)
128 root[
"network"] =
"ethernet";
131#ifdef ESPHOME_PROJECT_NAME
132 root[
"project_name"] = ESPHOME_PROJECT_NAME;
133 root[
"project_version"] = ESPHOME_PROJECT_VERSION;
136#ifdef USE_DASHBOARD_IMPORT
142 root[
"api_encryption"] =
"Noise_NNpsk0_25519_ChaChaPoly_SHA256";
144 root[
"api_encryption_supported"] =
"Noise_NNpsk0_25519_ChaChaPoly_SHA256";
152 ESP_LOGCONFIG(TAG,
"MQTT:");
153 ESP_LOGCONFIG(TAG,
" Server Address: %s:%u (%s)", this->
credentials_.
address.c_str(), this->credentials_.port,
154 this->ip_.str().c_str());
159 ESP_LOGCONFIG(TAG,
" Discovery IP enabled");
165 ESP_LOGCONFIG(TAG,
" Topic Prefix: '%s'", this->
topic_prefix_.c_str());
179 subscription.subscribed =
false;
180 subscription.resubscribe_timeout = 0;
198 this->
ip_ = network::IPAddress(&addr);
202 case ERR_INPROGRESS: {
204 ESP_LOGD(TAG,
"Resolving MQTT broker IP address...");
210 ESP_LOGW(TAG,
"Error resolving MQTT broker IP address: %d", err);
224 ESP_LOGW(TAG,
"Couldn't resolve IP address for '%s'!", this->
credentials_.
address.c_str());
233 ESP_LOGD(TAG,
"Resolved broker IP address to %s", this->
ip_.
str().c_str());
236#if defined(USE_ESP8266) && LWIP_VERSION_MAJOR == 1
242 if (ipaddr ==
nullptr) {
243 a_this->dns_resolve_error_ =
true;
245 a_this->ip_ = network::IPAddress(ipaddr);
246 a_this->dns_resolved_ =
true;
254 ESP_LOGI(TAG,
"Connecting to MQTT...");
260 const char *username =
nullptr;
263 const char *password =
nullptr;
272 this->last_will_.payload.c_str());
295 ESP_LOGI(TAG,
"MQTT Connected!");
302 for (MQTTComponent *component : this->
children_)
303 component->schedule_resend_state();
311 const LogString *reason_s;
314 reason_s = LOG_STR(
"TCP disconnected");
317 reason_s = LOG_STR(
"Unacceptable Protocol Version");
320 reason_s = LOG_STR(
"Identifier Rejected");
323 reason_s = LOG_STR(
"Server Unavailable");
326 reason_s = LOG_STR(
"Malformed Credentials");
329 reason_s = LOG_STR(
"Not Authorized");
332 reason_s = LOG_STR(
"Not Enough Space");
335 reason_s = LOG_STR(
"TLS Bad Fingerprint");
338 reason_s = LOG_STR(
"Unknown");
342 reason_s = LOG_STR(
"WiFi disconnected");
344 ESP_LOGW(TAG,
"MQTT Disconnected: %s.", LOG_STR_ARG(reason_s));
367 ESP_LOGW(TAG,
"Lost MQTT Client connection!");
381 ESP_LOGE(TAG,
"Can't connect to MQTT... Restarting...");
396 ESP_LOGV(TAG,
"subscribe(topic='%s')", topic);
399 ESP_LOGV(TAG,
"Subscribe failed for topic='%s'. Will retry later.", topic);
408 const uint32_t now =
millis();
409 bool do_resub = sub->resubscribe_timeout == 0 || now - sub->resubscribe_timeout > 1000;
412 sub->subscribed = this->
subscribe_(sub->topic.c_str(), sub->qos);
413 sub->resubscribe_timeout = now;
417 for (
auto &subscription : this->subscriptions_) {
423 MQTTSubscription subscription{
426 .callback = std::move(callback),
428 .resubscribe_timeout = 0,
431 this->subscriptions_.push_back(subscription);
435 auto f = [callback](
const std::string &topic,
const std::string &payload) {
437 callback(topic, root);
441 MQTTSubscription subscription{
446 .resubscribe_timeout = 0,
449 this->subscriptions_.push_back(subscription);
456 ESP_LOGV(TAG,
"unsubscribe(topic='%s')", topic.c_str());
459 ESP_LOGV(TAG,
"Unsubscribe failed for topic='%s'.", topic.c_str());
465 if (it->topic == topic) {
475 return this->
publish(topic, payload.data(), payload.size(), qos, retain);
480 return publish({.topic = topic, .payload = payload, .qos = qos, .retain = retain});
497 if (!logging_topic) {
499 ESP_LOGV(TAG,
"Publish(topic='%s' payload='%s' retain=%d qos=%d)", message.topic.c_str(), message.payload.c_str(),
500 message.retain, message.qos);
502 ESP_LOGV(TAG,
"Publish failed for topic='%s' (len=%u). will retry later..", message.topic.c_str(),
503 message.payload.length());
512 return this->
publish(topic, message, qos, retain);
518 ESP_LOGD(TAG,
"Enabling MQTT...");
527 ESP_LOGD(TAG,
"Disabling MQTT...");
543static bool topic_match(
const char *message,
const char *subscription,
bool is_normal,
bool past_separator) {
545 if (*message ==
'\0' && *subscription ==
'\0')
549 if (*message ==
'\0' || *subscription ==
'\0')
552 bool do_wildcards = is_normal || past_separator;
554 if (*subscription ==
'+' && do_wildcards) {
559 while (*message !=
'\0' && *message !=
'/') {
564 return topic_match(message, subscription, is_normal,
true);
567 if (*subscription ==
'#' && do_wildcards) {
573 if (*message != *subscription)
576 past_separator = past_separator || *subscription ==
'/';
582 return topic_match(message, subscription, is_normal, past_separator);
585static bool topic_match(
const char *message,
const char *subscription) {
586 return topic_match(message, subscription, *message !=
'\0' && *message !=
'$',
false);
593 this->
defer([
this, topic, payload]() {
595 for (
auto &subscription : this->subscriptions_) {
596 if (topic_match(topic.c_str(), subscription.topic.c_str()))
597 subscription.callback(topic, payload);
637 if (this->
birth_message_.
topic.empty() || this->birth_message_.topic != this->last_will_.topic) {
660 bool discover_ip,
bool clean) {
675 .discover_ip =
false,
698#if ASYNC_TCP_SSL_ENABLED
701 this->
mqtt_backend_.addServerFingerprint(fingerprint.data());
709void MQTTMessageTrigger::set_qos(uint8_t qos) { this->qos_ = qos; }
710void MQTTMessageTrigger::set_payload(
const std::string &payload) { this->payload_ = payload; }
711void MQTTMessageTrigger::setup() {
714 [
this](
const std::string &topic,
const std::string &payload) {
715 if (this->payload_.has_value() && payload != *this->payload_) {
719 this->trigger(payload);
723void MQTTMessageTrigger::dump_config() {
724 ESP_LOGCONFIG(TAG,
"MQTT Message Trigger:");
725 ESP_LOGCONFIG(TAG,
" Topic: '%s'", this->topic_.c_str());
726 ESP_LOGCONFIG(TAG,
" QoS: %u", this->qos_);
728float MQTTMessageTrigger::get_setup_priority()
const {
return setup_priority::AFTER_CONNECTION; }
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.
void status_momentary_warning(const std::string &name, uint32_t length=5000)
void status_set_warning(const char *message="unspecified")
void defer(const std::string &name, std::function< void()> &&f)
Defer a callback to the next loop() call.
void status_clear_warning()
uint16_t get_port() const
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.
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
bool connected() const 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.
MQTTMessage shutdown_message_
bool is_log_message_enabled() const
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)
bool can_proceed() override
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)
bool is_discovery_ip_enabled() const
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.
void on_shutdown() override
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.
MQTTCredentials credentials_
std::vector< MQTTComponent * > children_
void dump_config() override
void set_on_connect(mqtt_on_connect_callback_t &&callback)
optional< MQTTClientDisconnectReason > disconnect_reason_
bool is_publish_nan_as_none() const
void resubscribe_subscriptions_()
void disable_shutdown_message()
void unsubscribe(const std::string &topic)
Unsubscribe from an MQTT topic.
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 set_log_level(int level)
void resubscribe_subscription_(MQTTSubscription *sub)
void set_on_disconnect(mqtt_on_disconnect_callback_t &&callback)
bool subscribe_(const char *topic, uint8_t qos)
bool publish_nan_as_none_
const Availability & get_availability()
std::string topic_prefix_
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.
bool is_discovery_enabled() const
MQTTBackendESP32 mqtt_backend_
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.
std::string payload_buffer_
MQTTDiscoveryInfo discovery_info_
The discovery info options for Home Assistant.
Availability availability_
Caches availability.
MQTTMessageTrigger(std::string topic)
APIServer * global_api_server
std::string get_package_import_url()
std::function< void(JsonObject)> json_build_t
Callback function typedef for building JsonObjects.
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.
std::string build_json(const json_build_t &f)
Build a JSON string with the provided json build function.
std::function< MQTTBackend::on_disconnect_callback_t > mqtt_on_disconnect_callback_t
MQTTDiscoveryObjectIdGenerator
available discovery object_id generators
@ MQTT_NONE_OBJECT_ID_GENERATOR
MQTTDiscoveryUniqueIdGenerator
available discovery unique_id generators
@ MQTT_LEGACY_UNIQUE_ID_GENERATOR
std::function< void(const std::string &, JsonObject)> mqtt_json_callback_t
std::function< void(const std::string &, const std::string &)> mqtt_callback_t
Callback for MQTT subscriptions.
MQTTClientDisconnectReason
@ MQTT_SERVER_UNAVAILABLE
@ MQTT_MALFORMED_CREDENTIALS
@ MQTT_UNACCEPTABLE_PROTOCOL_VERSION
@ ESP8266_NOT_ENOUGH_SPACE
@ MQTT_IDENTIFIER_REJECTED
MQTTClientComponent * global_mqtt_client
@ MQTT_CLIENT_DISCONNECTED
@ MQTT_CLIENT_RESOLVING_ADDRESS
std::function< MQTTBackend::on_connect_callback_t > mqtt_on_connect_callback_t
Callback for MQTT events.
bool is_connected()
Return whether the node is connected to the network (through wifi, eth, ...)
network::IPAddresses get_ip_addresses()
bool is_disabled()
Return whether the network is disabled (only wifi for now)
const float AFTER_WIFI
For components that should be initialized after WiFi is connected.
Providing packet encoding functions for exchanging data with a remote host.
std::string str_sanitize(const std::string &str)
Sanitizes the input string by removing all characters but alphanumerics, dashes and underscores.
void IRAM_ATTR HOT yield()
std::string to_string(int value)
void IRAM_ATTR HOT delay(uint32_t ms)
uint32_t IRAM_ATTR HOT millis()
std::string get_mac_address()
Get the device MAC address as a string, in lowercase hex notation.
Application App
Global storage of Application pointer - only one Application can exist.
std::string payload_not_available
std::string topic
Empty means disabled.
std::string payload_available
std::string address
The address of the server without port number.
bool clean_session
Whether the session will be cleaned or remembered between connects.
std::string client_id
The client ID. Will automatically be truncated to 23 characters.
MQTTDiscoveryUniqueIdGenerator unique_id_generator
bool discover_ip
Enable the Home Assistant device discovery.
std::string prefix
The Home Assistant discovery prefix. Empty means disabled.
MQTTDiscoveryObjectIdGenerator object_id_generator
bool retain
Whether to retain discovery messages.
uint8_t qos
QoS. Only for last will testaments.