Skip to content

Commit

Permalink
sns: comments & update sensor::Value helpers
Browse files Browse the repository at this point in the history
  • Loading branch information
mcspr committed Feb 12, 2022
1 parent e5e8f86 commit afd9146
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 36 deletions.
6 changes: 3 additions & 3 deletions code/espurna/prometheus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ void _prometheusRequestHandler(AsyncWebServerRequest* request) {
#endif

#if SENSOR_SUPPORT
char buffer[64] { 0 };
for (unsigned char index = 0; index < magnitudeCount(); ++index) {
auto value = magnitudeValue(index);
if (std::isnan(value.get()) || std::isinf(value.get())) {
Expand All @@ -45,8 +44,9 @@ void _prometheusRequestHandler(AsyncWebServerRequest* request) {
String topic(magnitudeTopicIndex(index));
topic.replace("/", "");

magnitudeFormat(value, buffer, sizeof(buffer));
response->printf("%s %s\n", topic.c_str(), buffer);
response->printf("%s %s\n",
topic.c_str(),
value.toString().c_str());
}
#endif

Expand Down
48 changes: 25 additions & 23 deletions code/espurna/sensor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,6 @@ namespace {

class sensor_magnitude_t {
private:
constexpr static double _unset = std::numeric_limits<double>::quiet_NaN();
static unsigned char _counts[MAGNITUDE_MAX];

sensor_magnitude_t& operator=(const sensor_magnitude_t&) = default;
Expand Down Expand Up @@ -272,13 +271,13 @@ class sensor_magnitude_t {
sensor::Unit units { sensor::Unit::None }; // Units of measurement
unsigned char decimals { 0u }; // Number of decimals in textual representation

double last { _unset }; // Last raw value from sensor (unfiltered)
double reported { _unset }; // Last reported value
double last { sensor::Value::Unknown }; // Last raw value from sensor (unfiltered)
double reported { sensor::Value::Unknown }; // Last reported value
double min_delta { 0.0 }; // Minimum value change to report
double max_delta { 0.0 }; // Maximum value change to report
double correction { 0.0 }; // Value correction (applied when processing)

double zero_threshold { _unset }; // Reset value to zero when below threshold (applied when reading)
double zero_threshold { sensor::Value::Unknown }; // Reset value to zero when below threshold (applied when reading)
};

static_assert(
Expand Down Expand Up @@ -471,7 +470,17 @@ static_assert(celcius_to_farenheit(farenheit_to_celcius(0.0)) == 0.0, "");
static_assert(farenheit_to_kelvin(kelvin_to_farenheit(0.0)) == 0.0, "");
static_assert(farenheit_to_celcius(celcius_to_farenheit(0.0)) == 0.0, "");
static_assert(kelvin_to_celcius(celcius_to_kelvin(0.0)) == 0.0, "");
static_assert(std::numeric_limits<double>::epsilon() < kelvin_to_farenheit(farenheit_to_kelvin(0.0)), "");

// ref. https://en.cppreference.com/w/cpp/types/numeric_limits/epsilon
static constexpr bool almost_equal(double lhs, double rhs, int ulp) {
// the machine epsilon has to be scaled to the magnitude of the values used
// and multiplied by the desired precision in ULPs (units in the last place)
return __builtin_fabs(lhs - rhs) <= std::numeric_limits<double>::epsilon() * __builtin_fabs(lhs + rhs) * ulp
// unless the result is subnormal
|| __builtin_fabs(lhs - rhs) < std::numeric_limits<double>::min();
}

static_assert(almost_equal(10.0, kelvin_to_farenheit(farenheit_to_kelvin(10.0)), 3), "");

template <>
struct Converter<Kelvin, Kelvin> {
Expand Down Expand Up @@ -553,7 +562,9 @@ static_assert(unit_cast<Kelvin>(AbsoluteZero).value() == 0.0, "");
static_assert(unit_cast<Celcius>(AbsoluteZero).value() == AbsoluteZero.value(), "");

// since the outside api only works with the enumeration, make sure to cast it to our types for conversion
// notice that a table like {sensor::Unit(from), sensor::Unit(to), Converter(double(*)(double))} is ~500KiB larger in practice
// a table like this could've also worked
// > {sensor::Unit(from), sensor::Unit(to), Converter(double(*)(double))}
// but, it is ~0.6KiB vs. ~0.1KiB for this one. plus, some obstacles with c++11 implementation
// although, there may be a way to make this cheaper in both compile-time and runtime

// attempt to convert the input value from one unit to the other
Expand Down Expand Up @@ -3283,7 +3294,7 @@ void _sensorConfigure() {
{
magnitude.zero_threshold = getSetting(
{_magnitudeSettingsKey(magnitude, F("ZeroThreshold")), magnitude.index_global},
std::numeric_limits<double>::quiet_NaN()
sensor::Value::Unknown
);
}

Expand Down Expand Up @@ -3339,10 +3350,16 @@ String magnitudeTopic(unsigned char type) {
return _magnitudeTopic(type);
}

double sensor::Value::get() {
double sensor::Value::get() const {
return real_time ? last : reported;
}

String sensor::Value::toString() const {
char buffer[64] { 0 };
dtostrf(real_time ? last : reported, 1, decimals, buffer);
return buffer;
}

sensor::Value magnitudeValue(unsigned char index) {
sensor::Value result;

Expand All @@ -3352,26 +3369,11 @@ sensor::Value magnitudeValue(unsigned char index) {
result.last = magnitude.last;
result.reported = magnitude.reported;
result.decimals = magnitude.decimals;
} else {
result.real_time = false;
result.last = std::numeric_limits<double>::quiet_NaN(),
result.reported = std::numeric_limits<double>::quiet_NaN(),
result.decimals = 0u;
}

return result;
}

void magnitudeFormat(const sensor::Value& value, char* out, size_t) {
// TODO: 'size' does not do anything, since dtostrf used here is expected to be 'sane', but
// it does not allow any size arguments besides for digits after the decimal point
dtostrf(
_sensor_real_time ? value.last : value.reported,
1, value.decimals,
out
);
}

unsigned char magnitudeIndex(unsigned char index) {
if (index < _magnitudes.size()) {
return _magnitudes[index].index_global;
Expand Down
14 changes: 8 additions & 6 deletions code/espurna/sensor.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,12 +132,15 @@ struct ReadValue {
};

struct Value {
double get();
static constexpr double Unknown { std::numeric_limits<double>::quiet_NaN() };

bool real_time;
double last;
double reported;
unsigned char decimals;
double get() const;
String toString() const;

bool real_time { false };
double last { Unknown };
double reported { Unknown };
unsigned char decimals { 0 };
};

} // namespace sensor
Expand All @@ -158,7 +161,6 @@ String magnitudeTopicIndex(unsigned char index);
unsigned char magnitudeCount();

sensor::Value magnitudeValue(unsigned char index);
void magnitudeFormat(const sensor::Value& value, char* output, size_t size);

// XXX: without param name it is kind of vague what exactly unsigned char is
// consider adding stronger param type e.g. enum class
Expand Down
7 changes: 3 additions & 4 deletions code/espurna/thermostat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -413,14 +413,13 @@ double _getLocalValue(const char* description, unsigned char type) {
if (magnitudeType(index) != type) continue;
auto value = magnitudeValue(index);

char tmp_str[16];
magnitudeFormat(value, tmp_str, sizeof(tmp_str));
DEBUG_MSG_P(PSTR("[THERMOSTAT] %s: %s\n"), description, tmp_str);
DEBUG_MSG_P(PSTR("[THERMOSTAT] %s: %s\n"),
description, value.toString().c_str());

return value.get();
}
#endif
return std::numeric_limits<double>::quiet_NaN();
return sensor::Value::Unknown;
}

String _getLocalUnit(unsigned char type) {
Expand Down

0 comments on commit afd9146

Please sign in to comment.