mirror of
https://github.com/ashaduri/gsmartcontrol.git
synced 2026-09-25 05:15:33 +00:00
Temperature: Fixed reporting unreasonably large values when raw value encodes min/max values as well (#78); support protocol-independent temperature reporting in JSON.
This commit is contained in:
@@ -378,6 +378,11 @@ hz::ExpectedVoid<SmartctlParserError> SmartctlJsonAtaParser::parse_section_info(
|
||||
{"write_cache/enabled", _("Write Cache"), bool_formatter(_("Enabled"), _("Disabled"))},
|
||||
{"ata_dsn/enabled", _("DSN Feature"), bool_formatter(_("Enabled"), _("Disabled"))},
|
||||
{"ata_security/string", _("ATA Security"), string_formatter()},
|
||||
|
||||
// Protocol-independent JSON-only values
|
||||
{"power_cycle_count", _("Number of Power Cycles"), integer_formatter<int64_t>()},
|
||||
{"power_on_time/hours", _("Powered for"), integer_formatter<int64_t>("{} hours")},
|
||||
{"temperature/current", _("Current Temperature"), integer_formatter<int64_t>("{}° Celsius")},
|
||||
};
|
||||
|
||||
bool any_found = false;
|
||||
@@ -1090,58 +1095,162 @@ hz::ExpectedVoid<SmartctlParserError> SmartctlJsonAtaParser::parse_section_sctte
|
||||
std::vector<std::string> lines;
|
||||
|
||||
if (get_node_exists(json_root_node, "ata_sct_status/format_version").value_or(false)) {
|
||||
StorageProperty p;
|
||||
p.set_name("ata_sct_status/format_version", _("SCT status version"));
|
||||
p.section = StoragePropertySection::TemperatureLog;
|
||||
p.value = get_node_data<int64_t>(json_root_node, "ata_sct_status/format_version").value_or(0);
|
||||
add_property(p);
|
||||
|
||||
lines.emplace_back(fmt::format("SCT status version: {}", get_node_data<int64_t>(json_root_node, "ata_sct_status/format_version").value_or(0)));
|
||||
}
|
||||
if (get_node_exists(json_root_node, "ata_sct_status/sct_version").value_or(false)) {
|
||||
StorageProperty p;
|
||||
p.set_name("ata_sct_status/sct_version", _("SCT format version"));
|
||||
p.section = StoragePropertySection::TemperatureLog;
|
||||
p.value = get_node_data<int64_t>(json_root_node, "ata_sct_status/sct_version").value_or(0);
|
||||
add_property(p);
|
||||
|
||||
lines.emplace_back(fmt::format("SCT format version: {}", get_node_data<int64_t>(json_root_node, "ata_sct_status/sct_version").value_or(0)));
|
||||
}
|
||||
if (get_node_exists(json_root_node, "ata_sct_status/device_state").value_or(false)) {
|
||||
if (get_node_exists(json_root_node, "ata_sct_status/device_state/string").value_or(false)) {
|
||||
StorageProperty p;
|
||||
p.set_name("ata_sct_status/device_state/string", _("Device state"));
|
||||
p.section = StoragePropertySection::TemperatureLog;
|
||||
p.value = get_node_data<std::string>(json_root_node, "ata_sct_status/device_state/string").value_or(std::string());
|
||||
add_property(p);
|
||||
|
||||
lines.emplace_back(fmt::format("Device state: {}", get_node_data<std::string>(json_root_node, "ata_sct_status/device_state/string").value_or(std::string())));
|
||||
}
|
||||
if (get_node_exists(json_root_node, "ata_sct_status/temperature/current").value_or(false)) {
|
||||
StorageProperty p;
|
||||
p.set_name("ata_sct_status/temperature/current", _("Current temperature (C)"));
|
||||
p.section = StoragePropertySection::TemperatureLog;
|
||||
p.value = get_node_data<int64_t>(json_root_node, "ata_sct_status/temperature/current").value_or(0);
|
||||
add_property(p);
|
||||
|
||||
lines.emplace_back(fmt::format("Current temperature: {}° Celsius", get_node_data<int64_t>(json_root_node, "ata_sct_status/temperature/current").value_or(0)));
|
||||
}
|
||||
if (get_node_exists(json_root_node, "ata_sct_status/temperature/power_cycle_min").value_or(false)) {
|
||||
StorageProperty p;
|
||||
p.set_name("ata_sct_status/temperature/power_cycle_min", _("Power cycle min. temperature (C)"));
|
||||
p.section = StoragePropertySection::TemperatureLog;
|
||||
p.value = get_node_data<int64_t>(json_root_node, "ata_sct_status/temperature/power_cycle_min").value_or(0);
|
||||
add_property(p);
|
||||
|
||||
lines.emplace_back(fmt::format("Power cycle min. temperature: {}° Celsius", get_node_data<int64_t>(json_root_node, "ata_sct_status/temperature/power_cycle_min").value_or(0)));
|
||||
}
|
||||
if (get_node_exists(json_root_node, "ata_sct_status/temperature/power_cycle_max").value_or(false)) {
|
||||
StorageProperty p;
|
||||
p.set_name("ata_sct_status/temperature/power_cycle_max", _("Power cycle max. temperature (C)"));
|
||||
p.section = StoragePropertySection::TemperatureLog;
|
||||
p.value = get_node_data<int64_t>(json_root_node, "ata_sct_status/temperature/power_cycle_max").value_or(0);
|
||||
add_property(p);
|
||||
|
||||
lines.emplace_back(fmt::format("Power cycle max. temperature: {}° Celsius", get_node_data<int64_t>(json_root_node, "ata_sct_status/temperature/power_cycle_max").value_or(0)));
|
||||
}
|
||||
if (get_node_exists(json_root_node, "ata_sct_status/temperature/lifetime_min").value_or(false)) {
|
||||
StorageProperty p;
|
||||
p.set_name("ata_sct_status/temperature/lifetime_min", _("Lifetime min. temperature (C)"));
|
||||
p.section = StoragePropertySection::TemperatureLog;
|
||||
p.value = get_node_data<int64_t>(json_root_node, "ata_sct_status/temperature/lifetime_min").value_or(0);
|
||||
add_property(p);
|
||||
|
||||
lines.emplace_back(fmt::format("Lifetime min. temperature: {}° Celsius", get_node_data<int64_t>(json_root_node, "ata_sct_status/temperature/lifetime_min").value_or(0)));
|
||||
}
|
||||
if (get_node_exists(json_root_node, "ata_sct_status/temperature/lifetime_max").value_or(false)) {
|
||||
StorageProperty p;
|
||||
p.set_name("ata_sct_status/temperature/lifetime_max", _("Lifetime max. temperature (C)"));
|
||||
p.section = StoragePropertySection::TemperatureLog;
|
||||
p.value = get_node_data<int64_t>(json_root_node, "ata_sct_status/temperature/lifetime_max").value_or(0);
|
||||
add_property(p);
|
||||
|
||||
lines.emplace_back(fmt::format("Lifetime max. temperature: {}° Celsius", get_node_data<int64_t>(json_root_node, "ata_sct_status/temperature/lifetime_max").value_or(0)));
|
||||
}
|
||||
if (get_node_exists(json_root_node, "ata_sct_status/temperature/under_limit_count").value_or(false)) {
|
||||
StorageProperty p;
|
||||
p.set_name("ata_sct_status/temperature/under_limit_count", _("Under limit count"));
|
||||
p.section = StoragePropertySection::TemperatureLog;
|
||||
p.value = get_node_data<int64_t>(json_root_node, "ata_sct_status/temperature/under_limit_count").value_or(0);
|
||||
add_property(p);
|
||||
|
||||
lines.emplace_back(fmt::format("Under limit count: {}", get_node_data<int64_t>(json_root_node, "ata_sct_status/temperature/under_limit_count").value_or(0)));
|
||||
}
|
||||
if (get_node_exists(json_root_node, "ata_sct_status/temperature/over_limit_count").value_or(false)) {
|
||||
StorageProperty p;
|
||||
p.set_name("ata_sct_status/temperature/over_limit_count", _("Over limit count"));
|
||||
p.section = StoragePropertySection::TemperatureLog;
|
||||
p.value = get_node_data<int64_t>(json_root_node, "ata_sct_status/temperature/over_limit_count").value_or(0);
|
||||
add_property(p);
|
||||
|
||||
lines.emplace_back(fmt::format("Over limit count: {}", get_node_data<int64_t>(json_root_node, "ata_sct_status/temperature/over_limit_count").value_or(0)));
|
||||
}
|
||||
|
||||
lines.emplace_back();
|
||||
|
||||
if (get_node_exists(json_root_node, "ata_sct_temperature_history/version").value_or(false)) {
|
||||
StorageProperty p;
|
||||
p.set_name("ata_sct_temperature_history/version", _("SCT temperature history version"));
|
||||
p.section = StoragePropertySection::TemperatureLog;
|
||||
p.value = get_node_data<int64_t>(json_root_node, "ata_sct_temperature_history/version").value_or(0);
|
||||
add_property(p);
|
||||
|
||||
lines.emplace_back(fmt::format("SCT temperature history version: {}", get_node_data<int64_t>(json_root_node, "ata_sct_temperature_history/version").value_or(0)));
|
||||
}
|
||||
if (get_node_exists(json_root_node, "ata_sct_temperature_history/sampling_period_minutes").value_or(false)) {
|
||||
StorageProperty p;
|
||||
p.set_name("ata_sct_temperature_history/sampling_period_minutes", _("Temperature sampling period (min)"));
|
||||
p.section = StoragePropertySection::TemperatureLog;
|
||||
p.value = get_node_data<int64_t>(json_root_node, "ata_sct_temperature_history/sampling_period_minutes").value_or(0);
|
||||
add_property(p);
|
||||
|
||||
lines.emplace_back(fmt::format("Temperature sampling period: {} min.", get_node_data<int64_t>(json_root_node, "ata_sct_temperature_history/sampling_period_minutes").value_or(0)));
|
||||
}
|
||||
if (get_node_exists(json_root_node, "ata_sct_temperature_history/logging_interval_minutes").value_or(false)) {
|
||||
StorageProperty p;
|
||||
p.set_name("ata_sct_temperature_history/logging_interval_minutes", _("Temperature logging interval (min)"));
|
||||
p.section = StoragePropertySection::TemperatureLog;
|
||||
p.value = get_node_data<int64_t>(json_root_node, "ata_sct_temperature_history/logging_interval_minutes").value_or(0);
|
||||
add_property(p);
|
||||
|
||||
lines.emplace_back(fmt::format("Temperature logging interval: {} min.", get_node_data<int64_t>(json_root_node, "ata_sct_temperature_history/logging_interval_minutes").value_or(0)));
|
||||
}
|
||||
if (get_node_exists(json_root_node, "ata_sct_temperature_history/temperature/op_limit_min").value_or(false)) {
|
||||
StorageProperty p;
|
||||
p.set_name("ata_sct_temperature_history/temperature/op_limit_min", _("Recommended operating temperature (minimum) (C)"));
|
||||
p.section = StoragePropertySection::TemperatureLog;
|
||||
p.value = get_node_data<int64_t>(json_root_node, "ata_sct_temperature_history/temperature/op_limit_min").value_or(0);
|
||||
add_property(p);
|
||||
|
||||
lines.emplace_back(fmt::format("Recommended operating temperature (minimum): {}° Celsius",
|
||||
get_node_data<int64_t>(json_root_node, "ata_sct_temperature_history/temperature/op_limit_min").value_or(0)));
|
||||
}
|
||||
if (get_node_exists(json_root_node, "ata_sct_temperature_history/temperature/op_limit_max").value_or(false)) {
|
||||
StorageProperty p;
|
||||
p.set_name("ata_sct_temperature_history/temperature/op_limit_max", _("Recommended operating temperature (maximum) (C)"));
|
||||
p.section = StoragePropertySection::TemperatureLog;
|
||||
p.value = get_node_data<int64_t>(json_root_node, "ata_sct_temperature_history/temperature/op_limit_max").value_or(0);
|
||||
add_property(p);
|
||||
|
||||
lines.emplace_back(fmt::format("Recommended operating temperature (maximum): {}° Celsius",
|
||||
get_node_data<int64_t>(json_root_node, "ata_sct_temperature_history/temperature/op_limit_max").value_or(0)));
|
||||
}
|
||||
if (get_node_exists(json_root_node, "ata_sct_temperature_history/temperature/limit_min").value_or(false)) {
|
||||
StorageProperty p;
|
||||
p.set_name("ata_sct_temperature_history/temperature/limit_min", _("Allowed operating temperature (minimum) (C)"));
|
||||
p.section = StoragePropertySection::TemperatureLog;
|
||||
p.value = get_node_data<int64_t>(json_root_node, "ata_sct_temperature_history/temperature/limit_min").value_or(0);
|
||||
add_property(p);
|
||||
|
||||
lines.emplace_back(fmt::format("Allowed operating temperature (minimum): {}° Celsius",
|
||||
get_node_data<int64_t>(json_root_node, "ata_sct_temperature_history/temperature/limit_min").value_or(0)));
|
||||
}
|
||||
if (get_node_exists(json_root_node, "ata_sct_temperature_history/temperature/limit_max").value_or(false)) {
|
||||
StorageProperty p;
|
||||
p.set_name("ata_sct_temperature_history/temperature/limit_max", _("Allowed operating temperature (maximum) (C)"));
|
||||
p.section = StoragePropertySection::TemperatureLog;
|
||||
p.value = get_node_data<int64_t>(json_root_node, "ata_sct_temperature_history/temperature/limit_max").value_or(0);
|
||||
add_property(p);
|
||||
|
||||
lines.emplace_back(fmt::format("Allowed operating temperature (maximum): {}° Celsius",
|
||||
get_node_data<int64_t>(json_root_node, "ata_sct_temperature_history/temperature/limit_max").value_or(0)));
|
||||
}
|
||||
@@ -1230,8 +1339,8 @@ hz::ExpectedVoid<SmartctlParserError> SmartctlJsonAtaParser::parse_section_devst
|
||||
|
||||
StorageProperty page_prop;
|
||||
{
|
||||
std::string gen_name = get_node_data<std::string>(page_entry, "name").value_or(std::string());
|
||||
std::string disp_name = gen_name; // TODO: Translate
|
||||
const std::string gen_name = get_node_data<std::string>(page_entry, "name").value_or(std::string());
|
||||
const std::string disp_name = gen_name; // TODO: Translate
|
||||
page_prop.set_name(gen_name, disp_name);
|
||||
page_prop.section = StoragePropertySection::Statistics;
|
||||
page_prop.value = page_stat;
|
||||
@@ -1251,7 +1360,7 @@ hz::ExpectedVoid<SmartctlParserError> SmartctlJsonAtaParser::parse_section_devst
|
||||
s.offset = get_node_data<int64_t>(table_entry, "offset").value_or(0);
|
||||
|
||||
StorageProperty p;
|
||||
std::string gen_name = get_node_data<std::string>(table_entry, "name").value_or(std::string());
|
||||
const std::string gen_name = get_node_data<std::string>(table_entry, "name").value_or(std::string());
|
||||
p.set_name(gen_name, gen_name, gen_name); // The description database will correct this.
|
||||
p.section = StoragePropertySection::Statistics;
|
||||
p.value = s;
|
||||
|
||||
@@ -21,6 +21,7 @@ Copyright:
|
||||
#include "storage_property_descr_ata_attribute.h"
|
||||
//#include "warning_colors.h"
|
||||
#include "storage_property_descr_helpers.h"
|
||||
#include "hz/string_num.h"
|
||||
|
||||
|
||||
namespace {
|
||||
@@ -1282,12 +1283,16 @@ void storage_property_ata_attribute_autoset_warning(StorageProperty& p)
|
||||
"This could be an indication of future failures and/or potential data loss in bad sectors.";
|
||||
|
||||
// Temperature (for some it may be 10xTemp, so limit the upper bound.)
|
||||
} else if (attr_match(p, "attr_temperature_celsius")
|
||||
&& attr.raw_value_int > 50 && attr.raw_value_int <= 120) { // 50C
|
||||
w = WarningLevel::Notice;
|
||||
reason = "The temperature of the drive is higher than 50 degrees Celsius. "
|
||||
"This may shorten its lifespan and cause damage under severe load. Please install a cooling solution.";
|
||||
|
||||
} else if (attr_match(p, "attr_temperature_celsius")) {
|
||||
// Raw value may be 27, or 253403791387 (which encodes min/max values as well).
|
||||
// Use string instead.
|
||||
std::int64_t temp_int = 0;
|
||||
if (hz::string_is_numeric_nolocale(attr.raw_value, temp_int, false)
|
||||
&& temp_int > 50 && temp_int <= 120) { // 50C
|
||||
w = WarningLevel::Notice;
|
||||
reason = "The temperature of the drive is higher than 50 degrees Celsius. "
|
||||
"This may shorten its lifespan and cause damage under severe load. Please install a cooling solution.";
|
||||
}
|
||||
// Temperature (for some it may be 10xTemp, so limit the upper bound.)
|
||||
} else if (attr_match(p, "attr_temperature_celsius_x10") && attr.raw_value_int > 500) { // 50C
|
||||
w = WarningLevel::Notice;
|
||||
|
||||
@@ -156,7 +156,7 @@ namespace {
|
||||
|
||||
// Temperature Statistics
|
||||
|
||||
add("Current Temperature", "Current Temperature (C)", "",
|
||||
add("Current Temperature", "Current Temperature (C)", "stat_temperature_celsius",
|
||||
"Drive temperature (Celsius)");
|
||||
|
||||
add("Average Short Term Temperature", "Average Short Term Temperature (C)", "",
|
||||
|
||||
@@ -1734,11 +1734,16 @@ void GscInfoWindow::fill_ui_temperature_log(const StoragePropertyRepository& pro
|
||||
|
||||
std::string temperature;
|
||||
StorageProperty temp_property;
|
||||
enum { temp_attr2 = 1, temp_attr1, temp_stat, temp_sct }; // less important to more important
|
||||
enum { temp_attr2 = 1, temp_attr1, temp_stat, temp_sct, temp_info }; // less important to more important
|
||||
int temp_prop_source = 0;
|
||||
|
||||
for (const auto& p : props) {
|
||||
// Find temperature
|
||||
if (temp_prop_source < temp_info && p.generic_name == "temperature/current") { // Protocol-independent temperature
|
||||
temperature = hz::number_to_string_locale(p.get_value<int64_t>());
|
||||
temp_property = p;
|
||||
temp_prop_source = temp_info;
|
||||
}
|
||||
if (temp_prop_source < temp_sct && p.generic_name == "ata_sct_status/temperature/current") {
|
||||
temperature = hz::number_to_string_locale(p.get_value<int64_t>());
|
||||
temp_property = p;
|
||||
@@ -1750,9 +1755,14 @@ void GscInfoWindow::fill_ui_temperature_log(const StoragePropertyRepository& pro
|
||||
temp_prop_source = temp_stat;
|
||||
}
|
||||
if (temp_prop_source < temp_attr1 && p.generic_name == "attr_temperature_celsius") {
|
||||
temperature = hz::number_to_string_locale(p.get_value<AtaStorageAttribute>().raw_value_int);
|
||||
temp_property = p;
|
||||
temp_prop_source = temp_attr1;
|
||||
// Note: raw value may encode min/max as well, leading to very large values.
|
||||
// Instead, convert the string value (can be "27" or "27 (Min/Max 11/59)").
|
||||
std::int64_t temp_int = 0;
|
||||
if (hz::string_is_numeric_nolocale(p.get_value<AtaStorageAttribute>().raw_value, temp_int, false)) {
|
||||
temperature = hz::number_to_string_locale(temp_int);
|
||||
temp_property = p;
|
||||
temp_prop_source = temp_attr1;
|
||||
}
|
||||
}
|
||||
if (temp_prop_source < temp_attr2 && p.generic_name == "attr_temperature_celsius_x10") {
|
||||
temperature = hz::number_to_string_locale(p.get_value<AtaStorageAttribute>().raw_value_int / 10);
|
||||
@@ -1785,7 +1795,7 @@ void GscInfoWindow::fill_ui_temperature_log(const StoragePropertyRepository& pro
|
||||
if (temperature.empty()) {
|
||||
temperature = C_("value", "Unknown");
|
||||
} else {
|
||||
temperature = Glib::ustring::compose(C_("temperature", "%1 C"), temperature);
|
||||
temperature = Glib::ustring::compose(C_("temperature", "%1° C"), temperature);
|
||||
}
|
||||
temp_property.set_description(_("Current drive temperature in Celsius.")); // overrides attribute description
|
||||
label_strings.emplace_back(Glib::ustring::compose(_("Current temperature: %1"),
|
||||
|
||||
Reference in New Issue
Block a user