21#ifdef USE_DASHBOARD_IMPORT
28static const char *
const TAG =
"mqtt";
39 [
this](
const char *topic,
const char *payload,
size_t len,
size_t index,
size_t total) {
47 if (
len + index == total) {
61 [
this](
int level,
const char *tag,
const char *
message,
size_t message_len) {
64 .payload = std::string(
message, message_len),
74 "esphome/discover", [
this](
const std::string &topic,
const std::string &payload) { this->
send_device_info_(); },
77 std::string topic =
"esphome/ping/";
80 topic, [
this](
const std::string &topic,
const std::string &payload) { this->
send_device_info_(); }, 2);
92 std::string topic =
"esphome/discover/";
102 root[
"ip" + (index == 0 ?
"" : esphome::to_string(index))] = ip.str();
113 root[
"version"] = ESPHOME_VERSION;
117 root[
"platform"] =
"ESP8266";
120 root[
"platform"] =
"ESP32";
123 root[
"platform"] = lt_cpu_get_model_name();
126 root[
"board"] = ESPHOME_BOARD;
128 root[
"network"] =
"wifi";
129#elif defined(USE_ETHERNET)
130 root[
"network"] =
"ethernet";
133#ifdef ESPHOME_PROJECT_NAME
134 root[
"project_name"] = ESPHOME_PROJECT_NAME;
135 root[
"project_version"] = ESPHOME_PROJECT_VERSION;
138#ifdef USE_DASHBOARD_IMPORT
144 "Noise_NNpsk0_25519_ChaChaPoly_SHA256";
154 " Server Address: %s:%u (%s)\n"
155 " Username: " LOG_SECRET(
"'%s'")
"\n"
156 " Client ID: " LOG_SECRET(
"'%s'")
"\n"
157 " Clean Session: %s",
159 this->credentials_.username.c_str(), this->credentials_.client_id.c_str(),
162 ESP_LOGCONFIG(TAG,
" Discovery IP enabled");
166 " Discovery prefix: '%s'\n"
167 " Discovery retain: %s",
170 ESP_LOGCONFIG(TAG,
" Topic Prefix: '%s'", this->
topic_prefix_.c_str());
185 subscription.subscribed =
false;
186 subscription.resubscribe_timeout = 0;
198 this, LWIP_DNS_ADDRTYPE_IPV6_IPV4);
201 this, LWIP_DNS_ADDRTYPE_IPV4);
208 this->
ip_ = network::IPAddress(&addr);
212 case ERR_INPROGRESS: {
214 ESP_LOGD(TAG,
"Resolving broker IP address");
220 ESP_LOGW(TAG,
"Error resolving broker IP address: %d", err);
245 ESP_LOGD(TAG,
"Resolved broker IP address to %s", this->
ip_.
str().c_str());
248#if defined(USE_ESP8266) && LWIP_VERSION_MAJOR == 1
254 if (ipaddr ==
nullptr) {
255 a_this->dns_resolve_error_ =
true;
257 a_this->ip_ = network::IPAddress(ipaddr);
258 a_this->dns_resolved_ =
true;
266 ESP_LOGI(TAG,
"Connecting");
272 const char *username =
nullptr;
275 const char *password =
nullptr;
284 this->last_will_.payload.c_str());
307 ESP_LOGI(TAG,
"Connected");
323 const LogString *reason_s;
326 reason_s = LOG_STR(
"TCP disconnected");
329 reason_s = LOG_STR(
"Unacceptable Protocol Version");
332 reason_s = LOG_STR(
"Identifier Rejected");
335 reason_s = LOG_STR(
"Server Unavailable");
338 reason_s = LOG_STR(
"Malformed Credentials");
341 reason_s = LOG_STR(
"Not Authorized");
344 reason_s = LOG_STR(
"Not Enough Space");
347 reason_s = LOG_STR(
"TLS Bad Fingerprint");
350 reason_s = LOG_STR(
"Unknown");
354 reason_s = LOG_STR(
"WiFi disconnected");
356 ESP_LOGW(TAG,
"Disconnected: %s", LOG_STR_ARG(reason_s));
379 ESP_LOGW(TAG,
"Lost client connection");
393 ESP_LOGE(TAG,
"Can't connect; restarting");
408 ESP_LOGV(TAG,
"subscribe(topic='%s')", topic);
411 ESP_LOGV(TAG,
"Subscribe failed for topic='%s'. Will retry", topic);
421 bool do_resub = sub->resubscribe_timeout == 0 || now - sub->resubscribe_timeout > 1000;
424 sub->subscribed = this->
subscribe_(sub->topic.c_str(), sub->qos);
425 sub->resubscribe_timeout = now;
429 for (
auto &subscription : this->subscriptions_) {
435 MQTTSubscription subscription{
438 .callback = std::move(callback),
440 .resubscribe_timeout = 0,
443 this->subscriptions_.push_back(subscription);
447 auto f = [callback](
const std::string &topic,
const std::string &payload) {
449 callback(topic, root);
453 MQTTSubscription subscription{
458 .resubscribe_timeout = 0,
461 this->subscriptions_.push_back(subscription);
468 ESP_LOGV(TAG,
"unsubscribe(topic='%s')", topic.c_str());
471 ESP_LOGV(TAG,
"Unsubscribe failed for topic='%s'.", topic.c_str());
477 if (it->topic == topic) {
487 return this->
publish(topic, payload.data(), payload.size(), qos, retain);
492 return publish({.topic = topic, .payload = std::string(payload, payload_length), .qos = qos, .retain = retain});
509 if (!logging_topic) {
511 ESP_LOGV(TAG,
"Publish(topic='%s' payload='%s' retain=%d qos=%d)",
message.topic.c_str(),
message.payload.c_str(),
514 ESP_LOGV(TAG,
"Publish failed for topic='%s' (len=%u). Will retry",
message.topic.c_str(),
530 ESP_LOGD(TAG,
"Enabling");
539 ESP_LOGD(TAG,
"Disabling");
555static bool topic_match(
const char *
message,
const char *subscription,
bool is_normal,
bool past_separator) {
557 if (*
message ==
'\0' && *subscription ==
'\0')
561 if (*
message ==
'\0' || *subscription ==
'\0')
564 bool do_wildcards = is_normal || past_separator;
566 if (*subscription ==
'+' && do_wildcards) {
576 return topic_match(
message, subscription, is_normal,
true);
579 if (*subscription ==
'#' && do_wildcards) {
588 past_separator = past_separator || *subscription ==
'/';
594 return topic_match(
message, subscription, is_normal, past_separator);
597static bool topic_match(
const char *
message,
const char *subscription) {
605 this->
defer([
this, topic, payload]() {
607 for (
auto &subscription : this->subscriptions_) {
608 if (topic_match(topic.c_str(), subscription.topic.c_str()))
609 subscription.callback(topic, payload);
649 if (this->
birth_message_.
topic.empty() || this->birth_message_.topic != this->last_will_.topic) {
672 bool discover_ip,
bool clean) {
687 .discover_ip =
false,
707 auto callback_copy = callback;
712#if ASYNC_TCP_SSL_ENABLED
715 this->
mqtt_backend_.addServerFingerprint(fingerprint.data());
723void MQTTMessageTrigger::set_qos(uint8_t qos) { this->qos_ = qos; }
724void MQTTMessageTrigger::set_payload(
const std::string &payload) { this->payload_ = payload; }
725void MQTTMessageTrigger::setup() {
728 [
this](
const std::string &topic,
const std::string &payload) {
729 if (this->payload_.has_value() && payload != *this->payload_) {
733 this->trigger(payload);
737void MQTTMessageTrigger::dump_config() {
739 "MQTT Message Trigger:\n"
742 this->topic_.c_str(), this->qos_);
744float 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_set_warning(const char *message=nullptr)
void status_momentary_warning(const std::string &name, uint32_t length=5000)
void defer(const std::string &name, std::function< void()> &&f)
Defer a callback to the next loop() call.
void status_clear_warning()
std::shared_ptr< APINoiseContext > get_noise_ctx()
uint16_t get_port() const
void add_on_log_callback(std::function< void(uint8_t, const char *, const char *, size_t)> &&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)
bool wait_for_connection_
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.
CallbackManager< MQTTBackend::on_disconnect_callback_t > on_disconnect_
Availability availability_
Caches availability.
MQTTMessageTrigger(std::string topic)
const Component * component
APIServer * global_api_server
const 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 make_name_with_suffix(const std::string &name, char sep, const char *suffix_ptr, size_t suffix_len)
Concatenate a name with a separator and suffix using an efficient stack-based approach.
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()
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.