diff --git a/esphome/components/mqtt/mqtt_alarm_control_panel.cpp b/esphome/components/mqtt/mqtt_alarm_control_panel.cpp index 715e6feed8..fbdc6dce23 100644 --- a/esphome/components/mqtt/mqtt_alarm_control_panel.cpp +++ b/esphome/components/mqtt/mqtt_alarm_control_panel.cpp @@ -119,7 +119,8 @@ bool MQTTAlarmControlPanelComponent::publish_state() { default: state_s = "unknown"; } - return this->publish(this->get_state_topic_(), state_s); + char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN]; + return this->publish(this->get_state_topic_to_(topic_buf), state_s); } } // namespace esphome::mqtt diff --git a/esphome/components/mqtt/mqtt_binary_sensor.cpp b/esphome/components/mqtt/mqtt_binary_sensor.cpp index 7cbb5dcc0e..75995f61e0 100644 --- a/esphome/components/mqtt/mqtt_binary_sensor.cpp +++ b/esphome/components/mqtt/mqtt_binary_sensor.cpp @@ -52,8 +52,9 @@ bool MQTTBinarySensorComponent::publish_state(bool state) { if (this->binary_sensor_->is_status_binary_sensor()) return true; + char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN]; const char *state_s = state ? "ON" : "OFF"; - return this->publish(this->get_state_topic_(), state_s); + return this->publish(this->get_state_topic_to_(topic_buf), state_s); } } // namespace esphome::mqtt diff --git a/esphome/components/mqtt/mqtt_component.cpp b/esphome/components/mqtt/mqtt_component.cpp index 7607a4e817..aec6140e3f 100644 --- a/esphome/components/mqtt/mqtt_component.cpp +++ b/esphome/components/mqtt/mqtt_component.cpp @@ -132,17 +132,29 @@ std::string MQTTComponent::get_command_topic_() const { } bool MQTTComponent::publish(const std::string &topic, const std::string &payload) { - return this->publish(topic, payload.data(), payload.size()); + return this->publish(topic.c_str(), payload.data(), payload.size()); } bool MQTTComponent::publish(const std::string &topic, const char *payload, size_t payload_length) { - if (topic.empty()) + return this->publish(topic.c_str(), payload, payload_length); +} + +bool MQTTComponent::publish(const char *topic, const char *payload, size_t payload_length) { + if (topic[0] == '\0') return false; return global_mqtt_client->publish(topic, payload, payload_length, this->qos_, this->retain_); } +bool MQTTComponent::publish(const char *topic, const char *payload) { + return this->publish(topic, payload, strlen(payload)); +} + bool MQTTComponent::publish_json(const std::string &topic, const json::json_build_t &f) { - if (topic.empty()) + return this->publish_json(topic.c_str(), f); +} + +bool MQTTComponent::publish_json(const char *topic, const json::json_build_t &f) { + if (topic[0] == '\0') return false; return global_mqtt_client->publish_json(topic, f, this->qos_, this->retain_); } diff --git a/esphome/components/mqtt/mqtt_component.h b/esphome/components/mqtt/mqtt_component.h index 1a5e6db3af..304a2c0d0e 100644 --- a/esphome/components/mqtt/mqtt_component.h +++ b/esphome/components/mqtt/mqtt_component.h @@ -157,6 +157,38 @@ class MQTTComponent : public Component { */ bool publish(const std::string &topic, const char *payload, size_t payload_length); + /** Send a MQTT message (no heap allocation for topic). + * + * @param topic The topic as C string. + * @param payload The payload buffer. + * @param payload_length The length of the payload. + */ + bool publish(const char *topic, const char *payload, size_t payload_length); + + /** Send a MQTT message (no heap allocation for topic). + * + * @param topic The topic as StringRef (for use with get_state_topic_to_()). + * @param payload The payload buffer. + * @param payload_length The length of the payload. + */ + bool publish(StringRef topic, const char *payload, size_t payload_length) { + return this->publish(topic.c_str(), payload, payload_length); + } + + /** Send a MQTT message (no heap allocation for topic). + * + * @param topic The topic as C string. + * @param payload The null-terminated payload. + */ + bool publish(const char *topic, const char *payload); + + /** Send a MQTT message (no heap allocation for topic). + * + * @param topic The topic as StringRef (for use with get_state_topic_to_()). + * @param payload The null-terminated payload. + */ + bool publish(StringRef topic, const char *payload) { return this->publish(topic.c_str(), payload); } + /** Construct and send a JSON MQTT message. * * @param topic The topic. @@ -164,6 +196,20 @@ class MQTTComponent : public Component { */ bool publish_json(const std::string &topic, const json::json_build_t &f); + /** Construct and send a JSON MQTT message (no heap allocation for topic). + * + * @param topic The topic as C string. + * @param f The Json Message builder. + */ + bool publish_json(const char *topic, const json::json_build_t &f); + + /** Construct and send a JSON MQTT message (no heap allocation for topic). + * + * @param topic The topic as StringRef (for use with get_state_topic_to_()). + * @param f The Json Message builder. + */ + bool publish_json(StringRef topic, const json::json_build_t &f) { return this->publish_json(topic.c_str(), f); } + /** Subscribe to a MQTT topic. * * @param topic The topic. Wildcards are currently not supported. diff --git a/esphome/components/mqtt/mqtt_cover.cpp b/esphome/components/mqtt/mqtt_cover.cpp index 493514c8fb..d5bd13869a 100644 --- a/esphome/components/mqtt/mqtt_cover.cpp +++ b/esphome/components/mqtt/mqtt_cover.cpp @@ -115,7 +115,8 @@ bool MQTTCoverComponent::publish_state() { : this->cover_->position == COVER_OPEN ? "open" : traits.get_supports_position() ? "open" : "unknown"; - if (!this->publish(this->get_state_topic_(), state_s)) + char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN]; + if (!this->publish(this->get_state_topic_to_(topic_buf), state_s)) success = false; return success; } diff --git a/esphome/components/mqtt/mqtt_date.cpp b/esphome/components/mqtt/mqtt_date.cpp index cbe4045486..c422bb3058 100644 --- a/esphome/components/mqtt/mqtt_date.cpp +++ b/esphome/components/mqtt/mqtt_date.cpp @@ -53,7 +53,8 @@ bool MQTTDateComponent::send_initial_state() { } } bool MQTTDateComponent::publish_state(uint16_t year, uint8_t month, uint8_t day) { - return this->publish_json(this->get_state_topic_(), [year, month, day](JsonObject root) { + char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN]; + return this->publish_json(this->get_state_topic_to_(topic_buf), [year, month, day](JsonObject root) { // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson root[ESPHOME_F("year")] = year; root[ESPHOME_F("month")] = month; diff --git a/esphome/components/mqtt/mqtt_datetime.cpp b/esphome/components/mqtt/mqtt_datetime.cpp index f7b4ef0685..1492abd011 100644 --- a/esphome/components/mqtt/mqtt_datetime.cpp +++ b/esphome/components/mqtt/mqtt_datetime.cpp @@ -66,15 +66,17 @@ bool MQTTDateTimeComponent::send_initial_state() { } bool MQTTDateTimeComponent::publish_state(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) { - return this->publish_json(this->get_state_topic_(), [year, month, day, hour, minute, second](JsonObject root) { - // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson - root[ESPHOME_F("year")] = year; - root[ESPHOME_F("month")] = month; - root[ESPHOME_F("day")] = day; - root[ESPHOME_F("hour")] = hour; - root[ESPHOME_F("minute")] = minute; - root[ESPHOME_F("second")] = second; - }); + char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN]; + return this->publish_json(this->get_state_topic_to_(topic_buf), + [year, month, day, hour, minute, second](JsonObject root) { + // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson + root[ESPHOME_F("year")] = year; + root[ESPHOME_F("month")] = month; + root[ESPHOME_F("day")] = day; + root[ESPHOME_F("hour")] = hour; + root[ESPHOME_F("minute")] = minute; + root[ESPHOME_F("second")] = second; + }); } } // namespace esphome::mqtt diff --git a/esphome/components/mqtt/mqtt_event.cpp b/esphome/components/mqtt/mqtt_event.cpp index 42fbc1eabd..37d5c2551a 100644 --- a/esphome/components/mqtt/mqtt_event.cpp +++ b/esphome/components/mqtt/mqtt_event.cpp @@ -44,7 +44,8 @@ void MQTTEventComponent::dump_config() { } bool MQTTEventComponent::publish_event_(const std::string &event_type) { - return this->publish_json(this->get_state_topic_(), [event_type](JsonObject root) { + char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN]; + return this->publish_json(this->get_state_topic_to_(topic_buf), [event_type](JsonObject root) { // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson root[MQTT_EVENT_TYPE] = event_type; }); diff --git a/esphome/components/mqtt/mqtt_fan.cpp b/esphome/components/mqtt/mqtt_fan.cpp index 0909090023..c9791fb0f1 100644 --- a/esphome/components/mqtt/mqtt_fan.cpp +++ b/esphome/components/mqtt/mqtt_fan.cpp @@ -158,9 +158,10 @@ void MQTTFanComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig } } bool MQTTFanComponent::publish_state() { + char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN]; const char *state_s = this->state_->state ? "ON" : "OFF"; ESP_LOGD(TAG, "'%s' Sending state %s.", this->state_->get_name().c_str(), state_s); - this->publish(this->get_state_topic_(), state_s); + this->publish(this->get_state_topic_to_(topic_buf), state_s); bool failed = false; if (this->state_->get_traits().supports_direction()) { bool success = this->publish(this->get_direction_state_topic(), diff --git a/esphome/components/mqtt/mqtt_light.cpp b/esphome/components/mqtt/mqtt_light.cpp index e43cb63f4f..3e3537fa5c 100644 --- a/esphome/components/mqtt/mqtt_light.cpp +++ b/esphome/components/mqtt/mqtt_light.cpp @@ -34,7 +34,8 @@ void MQTTJSONLightComponent::on_light_remote_values_update() { MQTTJSONLightComponent::MQTTJSONLightComponent(LightState *state) : state_(state) {} bool MQTTJSONLightComponent::publish_state_() { - return this->publish_json(this->get_state_topic_(), [this](JsonObject root) { + char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN]; + return this->publish_json(this->get_state_topic_to_(topic_buf), [this](JsonObject root) { // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson LightJSONSchema::dump_json(*this->state_, root); }); diff --git a/esphome/components/mqtt/mqtt_lock.cpp b/esphome/components/mqtt/mqtt_lock.cpp index 43ef60bdf4..96c9397da8 100644 --- a/esphome/components/mqtt/mqtt_lock.cpp +++ b/esphome/components/mqtt/mqtt_lock.cpp @@ -47,13 +47,14 @@ void MQTTLockComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfi bool MQTTLockComponent::send_initial_state() { return this->publish_state(); } bool MQTTLockComponent::publish_state() { + char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN]; #ifdef USE_STORE_LOG_STR_IN_FLASH char buf[LOCK_STATE_STR_SIZE]; strncpy_P(buf, (PGM_P) lock_state_to_string(this->lock_->state), sizeof(buf) - 1); buf[sizeof(buf) - 1] = '\0'; - return this->publish(this->get_state_topic_(), buf); + return this->publish(this->get_state_topic_to_(topic_buf), buf); #else - return this->publish(this->get_state_topic_(), LOG_STR_ARG(lock_state_to_string(this->lock_->state))); + return this->publish(this->get_state_topic_to_(topic_buf), LOG_STR_ARG(lock_state_to_string(this->lock_->state))); #endif } diff --git a/esphome/components/mqtt/mqtt_number.cpp b/esphome/components/mqtt/mqtt_number.cpp index a014096c5f..7dc93eee0c 100644 --- a/esphome/components/mqtt/mqtt_number.cpp +++ b/esphome/components/mqtt/mqtt_number.cpp @@ -74,9 +74,10 @@ bool MQTTNumberComponent::send_initial_state() { } } bool MQTTNumberComponent::publish_state(float value) { + char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN]; char buffer[64]; - buf_append_printf(buffer, sizeof(buffer), 0, "%f", value); - return this->publish(this->get_state_topic_(), buffer); + size_t len = buf_append_printf(buffer, sizeof(buffer), 0, "%f", value); + return this->publish(this->get_state_topic_to_(topic_buf), buffer, len); } } // namespace esphome::mqtt diff --git a/esphome/components/mqtt/mqtt_select.cpp b/esphome/components/mqtt/mqtt_select.cpp index 2d830998ec..25fd813496 100644 --- a/esphome/components/mqtt/mqtt_select.cpp +++ b/esphome/components/mqtt/mqtt_select.cpp @@ -50,7 +50,8 @@ bool MQTTSelectComponent::send_initial_state() { } } bool MQTTSelectComponent::publish_state(const std::string &value) { - return this->publish(this->get_state_topic_(), value); + char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN]; + return this->publish(this->get_state_topic_to_(topic_buf), value.data(), value.size()); } } // namespace esphome::mqtt diff --git a/esphome/components/mqtt/mqtt_sensor.cpp b/esphome/components/mqtt/mqtt_sensor.cpp index f136b82355..e83eab6732 100644 --- a/esphome/components/mqtt/mqtt_sensor.cpp +++ b/esphome/components/mqtt/mqtt_sensor.cpp @@ -79,12 +79,13 @@ bool MQTTSensorComponent::send_initial_state() { } } bool MQTTSensorComponent::publish_state(float value) { + char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN]; if (mqtt::global_mqtt_client->is_publish_nan_as_none() && std::isnan(value)) - return this->publish(this->get_state_topic_(), "None", 4); + return this->publish(this->get_state_topic_to_(topic_buf), "None", 4); int8_t accuracy = this->sensor_->get_accuracy_decimals(); char buf[VALUE_ACCURACY_MAX_LEN]; size_t len = value_accuracy_to_buf(buf, value, accuracy); - return this->publish(this->get_state_topic_(), buf, len); + return this->publish(this->get_state_topic_to_(topic_buf), buf, len); } } // namespace esphome::mqtt diff --git a/esphome/components/mqtt/mqtt_switch.cpp b/esphome/components/mqtt/mqtt_switch.cpp index a985ec66be..70cd03a4eb 100644 --- a/esphome/components/mqtt/mqtt_switch.cpp +++ b/esphome/components/mqtt/mqtt_switch.cpp @@ -52,8 +52,9 @@ void MQTTSwitchComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryCon bool MQTTSwitchComponent::send_initial_state() { return this->publish_state(this->switch_->state); } bool MQTTSwitchComponent::publish_state(bool state) { + char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN]; const char *state_s = state ? "ON" : "OFF"; - return this->publish(this->get_state_topic_(), state_s); + return this->publish(this->get_state_topic_to_(topic_buf), state_s); } } // namespace esphome::mqtt diff --git a/esphome/components/mqtt/mqtt_text.cpp b/esphome/components/mqtt/mqtt_text.cpp index fed9224b42..16293c0603 100644 --- a/esphome/components/mqtt/mqtt_text.cpp +++ b/esphome/components/mqtt/mqtt_text.cpp @@ -53,7 +53,8 @@ bool MQTTTextComponent::send_initial_state() { } } bool MQTTTextComponent::publish_state(const std::string &value) { - return this->publish(this->get_state_topic_(), value); + char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN]; + return this->publish(this->get_state_topic_to_(topic_buf), value.data(), value.size()); } } // namespace esphome::mqtt diff --git a/esphome/components/mqtt/mqtt_text_sensor.cpp b/esphome/components/mqtt/mqtt_text_sensor.cpp index 5346923b41..a6b9f90b68 100644 --- a/esphome/components/mqtt/mqtt_text_sensor.cpp +++ b/esphome/components/mqtt/mqtt_text_sensor.cpp @@ -31,7 +31,10 @@ void MQTTTextSensor::dump_config() { LOG_MQTT_COMPONENT(true, false); } -bool MQTTTextSensor::publish_state(const std::string &value) { return this->publish(this->get_state_topic_(), value); } +bool MQTTTextSensor::publish_state(const std::string &value) { + char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN]; + return this->publish(this->get_state_topic_to_(topic_buf), value.data(), value.size()); +} bool MQTTTextSensor::send_initial_state() { if (this->sensor_->has_state()) { return this->publish_state(this->sensor_->state); diff --git a/esphome/components/mqtt/mqtt_time.cpp b/esphome/components/mqtt/mqtt_time.cpp index 8749c3b59e..be391ce88c 100644 --- a/esphome/components/mqtt/mqtt_time.cpp +++ b/esphome/components/mqtt/mqtt_time.cpp @@ -53,7 +53,8 @@ bool MQTTTimeComponent::send_initial_state() { } } bool MQTTTimeComponent::publish_state(uint8_t hour, uint8_t minute, uint8_t second) { - return this->publish_json(this->get_state_topic_(), [hour, minute, second](JsonObject root) { + char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN]; + return this->publish_json(this->get_state_topic_to_(topic_buf), [hour, minute, second](JsonObject root) { // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson root[ESPHOME_F("hour")] = hour; root[ESPHOME_F("minute")] = minute; diff --git a/esphome/components/mqtt/mqtt_update.cpp b/esphome/components/mqtt/mqtt_update.cpp index 99e0c85509..c01fb9e52e 100644 --- a/esphome/components/mqtt/mqtt_update.cpp +++ b/esphome/components/mqtt/mqtt_update.cpp @@ -28,7 +28,8 @@ void MQTTUpdateComponent::setup() { } bool MQTTUpdateComponent::publish_state() { - return this->publish_json(this->get_state_topic_(), [this](JsonObject root) { + char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN]; + return this->publish_json(this->get_state_topic_to_(topic_buf), [this](JsonObject root) { root[ESPHOME_F("installed_version")] = this->update_->update_info.current_version; root[ESPHOME_F("latest_version")] = this->update_->update_info.latest_version; root[ESPHOME_F("title")] = this->update_->update_info.title; diff --git a/esphome/components/mqtt/mqtt_valve.cpp b/esphome/components/mqtt/mqtt_valve.cpp index 8e66a69c6f..2e100823bf 100644 --- a/esphome/components/mqtt/mqtt_valve.cpp +++ b/esphome/components/mqtt/mqtt_valve.cpp @@ -84,7 +84,8 @@ bool MQTTValveComponent::publish_state() { : this->valve_->position == VALVE_OPEN ? "open" : traits.get_supports_position() ? "open" : "unknown"; - if (!this->publish(this->get_state_topic_(), state_s)) + char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN]; + if (!this->publish(this->get_state_topic_to_(topic_buf), state_s)) success = false; return success; }