diff --git a/esphome/components/mqtt/__init__.py b/esphome/components/mqtt/__init__.py index 99f8ad76d8..10f4a67721 100644 --- a/esphome/components/mqtt/__init__.py +++ b/esphome/components/mqtt/__init__.py @@ -382,23 +382,23 @@ async def to_code(config): if not birth_message: cg.add(var.disable_birth_message()) else: - cg.add(var.set_birth_message(exp_mqtt_message(birth_message))) + cg.add(var.set_birth_message(exp_mqtt_message(birth_message), CORE.name)) will_message = config[CONF_WILL_MESSAGE] if not will_message: cg.add(var.disable_last_will()) else: - cg.add(var.set_last_will(exp_mqtt_message(will_message))) + cg.add(var.set_last_will(exp_mqtt_message(will_message), CORE.name)) shutdown_message = config[CONF_SHUTDOWN_MESSAGE] if not shutdown_message: cg.add(var.disable_shutdown_message()) else: - cg.add(var.set_shutdown_message(exp_mqtt_message(shutdown_message))) + cg.add(var.set_shutdown_message(exp_mqtt_message(shutdown_message), CORE.name)) log_topic = config[CONF_LOG_TOPIC] if not log_topic: cg.add(var.disable_log_message()) else: - cg.add(var.set_log_message_template(exp_mqtt_message(log_topic))) + cg.add(var.set_log_message_template(exp_mqtt_message(log_topic), CORE.name)) if CONF_LEVEL in log_topic: cg.add(var.set_log_level(logger.LOG_LEVELS[log_topic[CONF_LEVEL]])) diff --git a/esphome/components/mqtt/mqtt_client.cpp b/esphome/components/mqtt/mqtt_client.cpp index 9afa3a588d..e47c7d6e37 100644 --- a/esphome/components/mqtt/mqtt_client.cpp +++ b/esphome/components/mqtt/mqtt_client.cpp @@ -22,6 +22,9 @@ #include "esphome/components/dashboard_import/dashboard_import.h" #endif +#include +#include + namespace esphome { namespace mqtt { @@ -84,6 +87,29 @@ void MQTTClientComponent::setup() { } } +void MQTTClientComponent::parse_topic_(const std::string &topic, std::string &top_name, std::string &rest) { + std::stringstream ss(topic); + // Extract the first part + if (std::getline(ss, top_name, '/')) { + // Extract the rest of the string + std::getline(ss, rest); // Reads everything after the first '/' + rest = "/" + rest; + } else { + top_name = topic; // If no delimiter, the whole string is the first name + rest = ""; // No rest part + } +} + +void MQTTClientComponent::fix_topic_(std::string &topic, const std::string &check_topic_prefix) { + if (App.is_name_add_mac_suffix_enabled()) { + std::string top_name(""), rest(""); + parse_topic_(topic, top_name, rest); + if (top_name == check_topic_prefix) { + topic = str_sanitize(App.get_name()) + rest; + } + } +} + void MQTTClientComponent::send_device_info_() { if (!this->is_connected() or !this->is_discovery_ip_enabled()) { return; @@ -604,7 +630,10 @@ void MQTTClientComponent::set_reboot_timeout(uint32_t reboot_timeout) { this->re void MQTTClientComponent::register_mqtt_component(MQTTComponent *component) { this->children_.push_back(component); } void MQTTClientComponent::set_log_level(int level) { this->log_level_ = level; } void MQTTClientComponent::set_keep_alive(uint16_t keep_alive_s) { this->mqtt_backend_.set_keep_alive(keep_alive_s); } -void MQTTClientComponent::set_log_message_template(MQTTMessage &&message) { this->log_message_ = std::move(message); } +void MQTTClientComponent::set_log_message_template(MQTTMessage &&message, const std::string &check_topic_prefix) { + this->log_message_ = std::move(message); + fix_topic_(this->log_message_.topic, check_topic_prefix); +} const MQTTDiscoveryInfo &MQTTClientComponent::get_discovery_info() const { return this->discovery_info_; } void MQTTClientComponent::set_topic_prefix(const std::string &topic_prefix, const std::string &check_topic_prefix) { if (App.is_name_add_mac_suffix_enabled() && (topic_prefix == check_topic_prefix)) { @@ -639,17 +668,22 @@ void MQTTClientComponent::recalculate_availability_() { this->availability_.payload_not_available = this->last_will_.payload; } -void MQTTClientComponent::set_last_will(MQTTMessage &&message) { +void MQTTClientComponent::set_last_will(MQTTMessage &&message, const std::string &check_topic_prefix) { this->last_will_ = std::move(message); + fix_topic_(this->last_will_.topic, check_topic_prefix); this->recalculate_availability_(); } -void MQTTClientComponent::set_birth_message(MQTTMessage &&message) { +void MQTTClientComponent::set_birth_message(MQTTMessage &&message, const std::string &check_topic_prefix) { this->birth_message_ = std::move(message); + fix_topic_(this->birth_message_.topic, check_topic_prefix); this->recalculate_availability_(); } -void MQTTClientComponent::set_shutdown_message(MQTTMessage &&message) { this->shutdown_message_ = std::move(message); } +void MQTTClientComponent::set_shutdown_message(MQTTMessage &&message, const std::string &check_topic_prefix) { + this->shutdown_message_ = std::move(message); + fix_topic_(this->shutdown_message_.topic, check_topic_prefix); +} void MQTTClientComponent::set_discovery_info(std::string &&prefix, MQTTDiscoveryUniqueIdGenerator unique_id_generator, MQTTDiscoveryObjectIdGenerator object_id_generator, bool retain, diff --git a/esphome/components/mqtt/mqtt_client.h b/esphome/components/mqtt/mqtt_client.h index c68b3c62eb..bfc31ff745 100644 --- a/esphome/components/mqtt/mqtt_client.h +++ b/esphome/components/mqtt/mqtt_client.h @@ -101,16 +101,16 @@ class MQTTClientComponent : public Component { MQTTClientComponent(); /// Set the last will testament message. - void set_last_will(MQTTMessage &&message); + void set_last_will(MQTTMessage &&message, const std::string &check_topic_prefix); /// Remove the last will testament message. void disable_last_will(); /// Set the birth message. - void set_birth_message(MQTTMessage &&message); + void set_birth_message(MQTTMessage &&message, const std::string &check_topic_prefix); /// Remove the birth message. void disable_birth_message(); - void set_shutdown_message(MQTTMessage &&message); + void set_shutdown_message(MQTTMessage &&message, const std::string &check_topic_prefix); void disable_shutdown_message(); /// Set the keep alive time in seconds, every 0.7*keep_alive a ping will be sent. @@ -170,7 +170,7 @@ class MQTTClientComponent : public Component { const std::string &get_topic_prefix() const; /// Manually set the topic used for logging. - void set_log_message_template(MQTTMessage &&message); + void set_log_message_template(MQTTMessage &&message, const std::string &check_topic_prefix); void set_log_level(int level); /// Get the topic used for logging. Defaults to "/debug" and the value is cached for speed. void disable_log_message(); @@ -268,6 +268,8 @@ class MQTTClientComponent : public Component { bool is_publish_nan_as_none() const; protected: + void parse_topic_(const std::string &topic, std::string &top_name, std::string &rest); + void fix_topic_(std::string &topic, const std::string &check_topic_prefix); void send_device_info_(); /// Reconnect to the MQTT broker if not already connected.