1
0
mirror of https://github.com/esphome/esphome.git synced 2026-02-08 00:31:58 +00:00

[mqtt][prometheus][graph] Migrate value_accuracy_to_string() to stack-based alternative (#13159)

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
J. Nick Koston
2026-01-12 07:38:20 -10:00
committed by GitHub
parent 7ea6bcef88
commit 8cccfa5369
9 changed files with 60 additions and 45 deletions

View File

@@ -232,17 +232,19 @@ void GraphLegend::init(Graph *g) {
ESP_LOGI(TAGL, " %s %d %d", txtstr.c_str(), fw, fh);
if (this->values_ != VALUE_POSITION_TYPE_NONE) {
std::string valstr =
value_accuracy_to_string(trace->sensor_->get_state(), trace->sensor_->get_accuracy_decimals());
char valstr[VALUE_ACCURACY_MAX_LEN];
if (this->units_) {
valstr += trace->sensor_->get_unit_of_measurement_ref();
value_accuracy_with_uom_to_buf(valstr, trace->sensor_->get_state(), trace->sensor_->get_accuracy_decimals(),
trace->sensor_->get_unit_of_measurement_ref());
} else {
value_accuracy_to_buf(valstr, trace->sensor_->get_state(), trace->sensor_->get_accuracy_decimals());
}
this->font_value_->measure(valstr.c_str(), &fw, &fos, &fbl, &fh);
this->font_value_->measure(valstr, &fw, &fos, &fbl, &fh);
if (fw > valw)
valw = fw;
if (fh > valh)
valh = fh;
ESP_LOGI(TAGL, " %s %d %d", valstr.c_str(), fw, fh);
ESP_LOGI(TAGL, " %s %d %d", valstr, fw, fh);
}
}
// Add extra margin
@@ -368,13 +370,15 @@ void Graph::draw_legend(display::Display *buff, uint16_t x_offset, uint16_t y_of
if (legend_->values_ != VALUE_POSITION_TYPE_NONE) {
int xv = x + legend_->xv_;
int yv = y + legend_->yv_;
std::string valstr =
value_accuracy_to_string(trace->sensor_->get_state(), trace->sensor_->get_accuracy_decimals());
char valstr[VALUE_ACCURACY_MAX_LEN];
if (legend_->units_) {
valstr += trace->sensor_->get_unit_of_measurement_ref();
value_accuracy_with_uom_to_buf(valstr, trace->sensor_->get_state(), trace->sensor_->get_accuracy_decimals(),
trace->sensor_->get_unit_of_measurement_ref());
} else {
value_accuracy_to_buf(valstr, trace->sensor_->get_state(), trace->sensor_->get_accuracy_decimals());
}
buff->printf(xv, yv, legend_->font_value_, trace->get_line_color(), TextAlign::TOP_CENTER, "%s", valstr.c_str());
ESP_LOGV(TAG, " value: %s", valstr.c_str());
buff->printf(xv, yv, legend_->font_value_, trace->get_line_color(), TextAlign::TOP_CENTER, "%s", valstr);
ESP_LOGV(TAG, " value: %s", valstr);
}
x += legend_->xs_;
y += legend_->ys_;

View File

@@ -12,8 +12,9 @@ bool CustomMQTTDevice::publish(const std::string &topic, const std::string &payl
return global_mqtt_client->publish(topic, payload, qos, retain);
}
bool CustomMQTTDevice::publish(const std::string &topic, float value, int8_t number_decimals) {
auto str = value_accuracy_to_string(value, number_decimals);
return this->publish(topic, str);
char buf[VALUE_ACCURACY_MAX_LEN];
value_accuracy_to_buf(buf, value, number_decimals);
return this->publish(topic, buf);
}
bool CustomMQTTDevice::publish(const std::string &topic, int value) {
char buffer[24];

View File

@@ -291,35 +291,36 @@ bool MQTTClimateComponent::publish_state_() {
success = false;
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];
if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_CURRENT_TEMPERATURE) &&
!std::isnan(this->device_->current_temperature)) {
std::string payload = value_accuracy_to_string(this->device_->current_temperature, current_accuracy);
value_accuracy_to_buf(payload, this->device_->current_temperature, current_accuracy);
if (!this->publish(this->get_current_temperature_state_topic(), payload))
success = false;
}
if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_TWO_POINT_TARGET_TEMPERATURE |
climate::CLIMATE_REQUIRES_TWO_POINT_TARGET_TEMPERATURE)) {
std::string payload = value_accuracy_to_string(this->device_->target_temperature_low, target_accuracy);
value_accuracy_to_buf(payload, this->device_->target_temperature_low, target_accuracy);
if (!this->publish(this->get_target_temperature_low_state_topic(), payload))
success = false;
payload = value_accuracy_to_string(this->device_->target_temperature_high, target_accuracy);
value_accuracy_to_buf(payload, this->device_->target_temperature_high, target_accuracy);
if (!this->publish(this->get_target_temperature_high_state_topic(), payload))
success = false;
} else {
std::string payload = value_accuracy_to_string(this->device_->target_temperature, target_accuracy);
value_accuracy_to_buf(payload, this->device_->target_temperature, target_accuracy);
if (!this->publish(this->get_target_temperature_state_topic(), payload))
success = false;
}
if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_CURRENT_HUMIDITY) &&
!std::isnan(this->device_->current_humidity)) {
std::string payload = value_accuracy_to_string(this->device_->current_humidity, 0);
value_accuracy_to_buf(payload, this->device_->current_humidity, 0);
if (!this->publish(this->get_current_humidity_state_topic(), payload))
success = false;
}
if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_TARGET_HUMIDITY) &&
!std::isnan(this->device_->target_humidity)) {
std::string payload = value_accuracy_to_string(this->device_->target_humidity, 0);
value_accuracy_to_buf(payload, this->device_->target_humidity, 0);
if (!this->publish(this->get_target_humidity_state_topic(), payload))
success = false;
}

View File

@@ -98,12 +98,14 @@ bool MQTTCoverComponent::publish_state() {
auto traits = this->cover_->get_traits();
bool success = true;
if (traits.get_supports_position()) {
std::string pos = value_accuracy_to_string(roundf(this->cover_->position * 100), 0);
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))
success = false;
}
if (traits.get_supports_tilt()) {
std::string pos = value_accuracy_to_string(roundf(this->cover_->tilt * 100), 0);
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))
success = false;
}

View File

@@ -82,7 +82,9 @@ 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");
int8_t accuracy = this->sensor_->get_accuracy_decimals();
return this->publish(this->get_state_topic_(), value_accuracy_to_string(value, accuracy));
char buf[VALUE_ACCURACY_MAX_LEN];
value_accuracy_to_buf(buf, value, accuracy);
return this->publish(this->get_state_topic_(), buf);
}
} // namespace esphome::mqtt

View File

@@ -73,7 +73,8 @@ bool MQTTValveComponent::publish_state() {
auto traits = this->valve_->get_traits();
bool success = true;
if (traits.get_supports_position()) {
std::string pos = value_accuracy_to_string(roundf(this->valve_->position * 100), 0);
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))
success = false;
}

View File

@@ -194,7 +194,9 @@ void PrometheusHandler::sensor_row_(AsyncResponseStream *stream, sensor::Sensor
stream->print(ESPHOME_F("\",unit=\""));
stream->print(obj->get_unit_of_measurement_ref().c_str());
stream->print(ESPHOME_F("\"} "));
stream->print(value_accuracy_to_string(obj->state, obj->get_accuracy_decimals()).c_str());
char value_buf[VALUE_ACCURACY_MAX_LEN];
value_accuracy_to_buf(value_buf, obj->state, obj->get_accuracy_decimals());
stream->print(value_buf);
stream->print(ESPHOME_F("\n"));
} else {
// Invalid state
@@ -954,7 +956,7 @@ void PrometheusHandler::climate_setting_row_(AsyncResponseStream *stream, climat
void PrometheusHandler::climate_value_row_(AsyncResponseStream *stream, climate::Climate *obj, std::string &area,
std::string &node, std::string &friendly_name, std::string &category,
std::string &climate_value) {
const char *climate_value) {
stream->print(ESPHOME_F("esphome_climate_value{id=\""));
stream->print(relabel_id_(obj).c_str());
add_area_label_(stream, area);
@@ -965,7 +967,7 @@ void PrometheusHandler::climate_value_row_(AsyncResponseStream *stream, climate:
stream->print(ESPHOME_F("\",category=\""));
stream->print(category.c_str());
stream->print(ESPHOME_F("\"} "));
stream->print(climate_value.c_str());
stream->print(climate_value);
stream->print(ESPHOME_F("\n"));
}
@@ -1003,14 +1005,15 @@ void PrometheusHandler::climate_row_(AsyncResponseStream *stream, climate::Clima
// Now see if traits is supported
int8_t target_accuracy = traits.get_target_temperature_accuracy_decimals();
int8_t current_accuracy = traits.get_current_temperature_accuracy_decimals();
char value_buf[VALUE_ACCURACY_MAX_LEN];
// max temp
std::string max_temp = "maximum_temperature";
auto max_temp_value = value_accuracy_to_string(traits.get_visual_max_temperature(), target_accuracy);
climate_value_row_(stream, obj, area, node, friendly_name, max_temp, max_temp_value);
// max temp
std::string min_temp = "mininum_temperature";
auto min_temp_value = value_accuracy_to_string(traits.get_visual_min_temperature(), target_accuracy);
climate_value_row_(stream, obj, area, node, friendly_name, min_temp, min_temp_value);
value_accuracy_to_buf(value_buf, traits.get_visual_max_temperature(), target_accuracy);
climate_value_row_(stream, obj, area, node, friendly_name, max_temp, value_buf);
// min temp
std::string min_temp = "minimum_temperature";
value_accuracy_to_buf(value_buf, traits.get_visual_min_temperature(), target_accuracy);
climate_value_row_(stream, obj, area, node, friendly_name, min_temp, value_buf);
// now check optional traits
if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_CURRENT_TEMPERATURE)) {
std::string current_temp = "current_temperature";
@@ -1018,8 +1021,8 @@ void PrometheusHandler::climate_row_(AsyncResponseStream *stream, climate::Clima
climate_failed_row_(stream, obj, area, node, friendly_name, current_temp, true);
any_failures = true;
} else {
auto current_temp_value = value_accuracy_to_string(obj->current_temperature, current_accuracy);
climate_value_row_(stream, obj, area, node, friendly_name, current_temp, current_temp_value);
value_accuracy_to_buf(value_buf, obj->current_temperature, current_accuracy);
climate_value_row_(stream, obj, area, node, friendly_name, current_temp, value_buf);
climate_failed_row_(stream, obj, area, node, friendly_name, current_temp, false);
}
}
@@ -1029,8 +1032,8 @@ void PrometheusHandler::climate_row_(AsyncResponseStream *stream, climate::Clima
climate_failed_row_(stream, obj, area, node, friendly_name, current_humidity, true);
any_failures = true;
} else {
auto current_humidity_value = value_accuracy_to_string(obj->current_humidity, 0);
climate_value_row_(stream, obj, area, node, friendly_name, current_humidity, current_humidity_value);
value_accuracy_to_buf(value_buf, obj->current_humidity, 0);
climate_value_row_(stream, obj, area, node, friendly_name, current_humidity, value_buf);
climate_failed_row_(stream, obj, area, node, friendly_name, current_humidity, false);
}
}
@@ -1040,23 +1043,23 @@ void PrometheusHandler::climate_row_(AsyncResponseStream *stream, climate::Clima
climate_failed_row_(stream, obj, area, node, friendly_name, target_humidity, true);
any_failures = true;
} else {
auto target_humidity_value = value_accuracy_to_string(obj->target_humidity, 0);
climate_value_row_(stream, obj, area, node, friendly_name, target_humidity, target_humidity_value);
value_accuracy_to_buf(value_buf, obj->target_humidity, 0);
climate_value_row_(stream, obj, area, node, friendly_name, target_humidity, value_buf);
climate_failed_row_(stream, obj, area, node, friendly_name, target_humidity, false);
}
}
if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_TWO_POINT_TARGET_TEMPERATURE |
climate::CLIMATE_REQUIRES_TWO_POINT_TARGET_TEMPERATURE)) {
std::string target_temp_low = "target_temperature_low";
auto target_temp_low_value = value_accuracy_to_string(obj->target_temperature_low, target_accuracy);
climate_value_row_(stream, obj, area, node, friendly_name, target_temp_low, target_temp_low_value);
value_accuracy_to_buf(value_buf, obj->target_temperature_low, target_accuracy);
climate_value_row_(stream, obj, area, node, friendly_name, target_temp_low, value_buf);
std::string target_temp_high = "target_temperature_high";
auto target_temp_high_value = value_accuracy_to_string(obj->target_temperature_high, target_accuracy);
climate_value_row_(stream, obj, area, node, friendly_name, target_temp_high, target_temp_high_value);
value_accuracy_to_buf(value_buf, obj->target_temperature_high, target_accuracy);
climate_value_row_(stream, obj, area, node, friendly_name, target_temp_high, value_buf);
} else {
std::string target_temp = "target_temperature";
auto target_temp_value = value_accuracy_to_string(obj->target_temperature, target_accuracy);
climate_value_row_(stream, obj, area, node, friendly_name, target_temp, target_temp_value);
value_accuracy_to_buf(value_buf, obj->target_temperature, target_accuracy);
climate_value_row_(stream, obj, area, node, friendly_name, target_temp, value_buf);
}
if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_ACTION)) {
std::string climate_trait_category = "action";

View File

@@ -207,7 +207,7 @@ class PrometheusHandler : public AsyncWebHandler, public Component {
void climate_setting_row_(AsyncResponseStream *stream, climate::Climate *obj, std::string &area, std::string &node,
std::string &friendly_name, std::string &setting, const LogString *setting_value);
void climate_value_row_(AsyncResponseStream *stream, climate::Climate *obj, std::string &area, std::string &node,
std::string &friendly_name, std::string &category, std::string &climate_value);
std::string &friendly_name, std::string &category, const char *climate_value);
#endif
web_server_base::WebServerBase *base_;

View File

@@ -1027,7 +1027,8 @@ enum ParseOnOffState : uint8_t {
/// Parse a string that contains either on, off or toggle.
ParseOnOffState parse_on_off(const char *str, const char *on = nullptr, const char *off = nullptr);
/// Create a string from a value and an accuracy in decimals.
/// @deprecated Allocates heap memory. Use value_accuracy_to_buf() instead. Removed in 2026.7.0.
ESPDEPRECATED("Allocates heap memory. Use value_accuracy_to_buf() instead. Removed in 2026.7.0.", "2026.1.0")
std::string value_accuracy_to_string(float value, int8_t accuracy_decimals);
/// Maximum buffer size for value_accuracy formatting (float ~15 chars + space + UOM ~40 chars + null)