[mqtt] Avoid intermediate string allocations in publish calls (#13174)

This commit is contained in:
J. Nick Koston
2026-01-13 08:05:04 -10:00
committed by GitHub
parent 7fed9144a6
commit 3d40979c96
8 changed files with 42 additions and 28 deletions

View File

@@ -13,13 +13,13 @@ bool CustomMQTTDevice::publish(const std::string &topic, const std::string &payl
}
bool CustomMQTTDevice::publish(const std::string &topic, float value, int8_t number_decimals) {
char buf[VALUE_ACCURACY_MAX_LEN];
value_accuracy_to_buf(buf, value, number_decimals);
return this->publish(topic, buf);
size_t len = value_accuracy_to_buf(buf, value, number_decimals);
return global_mqtt_client->publish(topic, buf, len);
}
bool CustomMQTTDevice::publish(const std::string &topic, int value) {
char buffer[24];
sprintf(buffer, "%d", value);
return this->publish(topic, buffer);
int len = snprintf(buffer, sizeof(buffer), "%d", value);
return global_mqtt_client->publish(topic, buffer, len);
}
bool CustomMQTTDevice::publish_json(const std::string &topic, const json::json_build_t &f, uint8_t qos, bool retain) {
return global_mqtt_client->publish_json(topic, f, qos, retain);

View File

@@ -292,36 +292,37 @@ bool MQTTClimateComponent::publish_state_() {
int8_t target_accuracy = traits.get_target_temperature_accuracy_decimals();
int8_t current_accuracy = traits.get_current_temperature_accuracy_decimals();
char payload[VALUE_ACCURACY_MAX_LEN];
size_t len;
if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_CURRENT_TEMPERATURE) &&
!std::isnan(this->device_->current_temperature)) {
value_accuracy_to_buf(payload, this->device_->current_temperature, current_accuracy);
if (!this->publish(this->get_current_temperature_state_topic(), payload))
len = value_accuracy_to_buf(payload, this->device_->current_temperature, current_accuracy);
if (!this->publish(this->get_current_temperature_state_topic(), payload, len))
success = false;
}
if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_TWO_POINT_TARGET_TEMPERATURE |
climate::CLIMATE_REQUIRES_TWO_POINT_TARGET_TEMPERATURE)) {
value_accuracy_to_buf(payload, this->device_->target_temperature_low, target_accuracy);
if (!this->publish(this->get_target_temperature_low_state_topic(), payload))
len = value_accuracy_to_buf(payload, this->device_->target_temperature_low, target_accuracy);
if (!this->publish(this->get_target_temperature_low_state_topic(), payload, len))
success = false;
value_accuracy_to_buf(payload, this->device_->target_temperature_high, target_accuracy);
if (!this->publish(this->get_target_temperature_high_state_topic(), payload))
len = value_accuracy_to_buf(payload, this->device_->target_temperature_high, target_accuracy);
if (!this->publish(this->get_target_temperature_high_state_topic(), payload, len))
success = false;
} else {
value_accuracy_to_buf(payload, this->device_->target_temperature, target_accuracy);
if (!this->publish(this->get_target_temperature_state_topic(), payload))
len = value_accuracy_to_buf(payload, this->device_->target_temperature, target_accuracy);
if (!this->publish(this->get_target_temperature_state_topic(), payload, len))
success = false;
}
if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_CURRENT_HUMIDITY) &&
!std::isnan(this->device_->current_humidity)) {
value_accuracy_to_buf(payload, this->device_->current_humidity, 0);
if (!this->publish(this->get_current_humidity_state_topic(), payload))
len = value_accuracy_to_buf(payload, this->device_->current_humidity, 0);
if (!this->publish(this->get_current_humidity_state_topic(), payload, len))
success = false;
}
if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_TARGET_HUMIDITY) &&
!std::isnan(this->device_->target_humidity)) {
value_accuracy_to_buf(payload, this->device_->target_humidity, 0);
if (!this->publish(this->get_target_humidity_state_topic(), payload))
len = value_accuracy_to_buf(payload, this->device_->target_humidity, 0);
if (!this->publish(this->get_target_humidity_state_topic(), payload, len))
success = false;
}

View File

@@ -106,9 +106,13 @@ 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());
}
bool MQTTComponent::publish(const std::string &topic, const char *payload, size_t payload_length) {
if (topic.empty())
return false;
return global_mqtt_client->publish(topic, payload, this->qos_, this->retain_);
return global_mqtt_client->publish(topic, payload, payload_length, this->qos_, this->retain_);
}
bool MQTTComponent::publish_json(const std::string &topic, const json::json_build_t &f) {

View File

@@ -140,6 +140,14 @@ class MQTTComponent : public Component {
*/
bool publish(const std::string &topic, const std::string &payload);
/** Send a MQTT message.
*
* @param topic The topic.
* @param payload The payload buffer.
* @param payload_length The length of the payload.
*/
bool publish(const std::string &topic, const char *payload, size_t payload_length);
/** Construct and send a JSON MQTT message.
*
* @param topic The topic.

View File

@@ -99,14 +99,14 @@ bool MQTTCoverComponent::publish_state() {
bool success = true;
if (traits.get_supports_position()) {
char pos[VALUE_ACCURACY_MAX_LEN];
value_accuracy_to_buf(pos, roundf(this->cover_->position * 100), 0);
if (!this->publish(this->get_position_state_topic(), pos))
size_t len = value_accuracy_to_buf(pos, roundf(this->cover_->position * 100), 0);
if (!this->publish(this->get_position_state_topic(), pos, len))
success = false;
}
if (traits.get_supports_tilt()) {
char pos[VALUE_ACCURACY_MAX_LEN];
value_accuracy_to_buf(pos, roundf(this->cover_->tilt * 100), 0);
if (!this->publish(this->get_tilt_state_topic(), pos))
size_t len = value_accuracy_to_buf(pos, roundf(this->cover_->tilt * 100), 0);
if (!this->publish(this->get_tilt_state_topic(), pos, len))
success = false;
}
const char *state_s = this->cover_->current_operation == COVER_OPERATION_OPENING ? "opening"

View File

@@ -174,8 +174,9 @@ bool MQTTFanComponent::publish_state() {
}
auto traits = this->state_->get_traits();
if (traits.supports_speed()) {
std::string payload = to_string(this->state_->speed);
bool success = this->publish(this->get_speed_level_state_topic(), payload);
char buf[12];
int len = snprintf(buf, sizeof(buf), "%d", this->state_->speed);
bool success = this->publish(this->get_speed_level_state_topic(), buf, len);
failed = failed || !success;
}
return !failed;

View File

@@ -80,11 +80,11 @@ bool MQTTSensorComponent::send_initial_state() {
}
bool MQTTSensorComponent::publish_state(float value) {
if (mqtt::global_mqtt_client->is_publish_nan_as_none() && std::isnan(value))
return this->publish(this->get_state_topic_(), "None");
return this->publish(this->get_state_topic_(), "None", 4);
int8_t accuracy = this->sensor_->get_accuracy_decimals();
char buf[VALUE_ACCURACY_MAX_LEN];
value_accuracy_to_buf(buf, value, accuracy);
return this->publish(this->get_state_topic_(), buf);
size_t len = value_accuracy_to_buf(buf, value, accuracy);
return this->publish(this->get_state_topic_(), buf, len);
}
} // namespace esphome::mqtt

View File

@@ -74,8 +74,8 @@ bool MQTTValveComponent::publish_state() {
bool success = true;
if (traits.get_supports_position()) {
char pos[VALUE_ACCURACY_MAX_LEN];
value_accuracy_to_buf(pos, roundf(this->valve_->position * 100), 0);
if (!this->publish(this->get_position_state_topic(), pos))
size_t len = value_accuracy_to_buf(pos, roundf(this->valve_->position * 100), 0);
if (!this->publish(this->get_position_state_topic(), pos, len))
success = false;
}
const char *state_s = this->valve_->current_operation == VALVE_OPERATION_OPENING ? "opening"