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:
@@ -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_;
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user