Skip to content

Commit fc8ef5a

Browse files
committed
sns: min & max threshold, revert zero threshold changes
- same as min & max delta, check the value itself before reporting - refactor more of the report func, revert zero threshold to force the value to be zero. move condition check to the top, causing every other filter to check against zero. - force zero threshold to be >= 0 in ui
1 parent 404a0ea commit fc8ef5a

14 files changed

+13343
-13259
lines changed

code/espurna/sensor.cpp

+105-53
Original file line numberDiff line numberDiff line change
@@ -496,8 +496,12 @@ class Magnitude {
496496

497497
double min_delta { 0.0 }; // Minimum value change to report
498498
double max_delta { 0.0 }; // Maximum value change to report
499-
double correction { 0.0 }; // Value correction (applied when processing)
500-
double zero_threshold { Value::Unknown }; // Reset value to zero when below threshold (applied when reading)
499+
//
500+
double min_threshold { Value::Unknown }; // Minimum value to report
501+
double max_threshold { Value::Unknown }; // Maximum value to report
502+
503+
double zero_threshold { Value::Unknown }; // Reset value to zero when equal or below threshold (applied when reading)
504+
double correction { 0.0 }; // Value correction (applied when reading)
501505
};
502506

503507
static_assert(
@@ -1078,6 +1082,10 @@ PROGMEM_STRING(MinDelta, "MinDelta");
10781082
PROGMEM_STRING(Precision, "Precision");
10791083
PROGMEM_STRING(Ratio, "Ratio");
10801084
PROGMEM_STRING(Units, "Units");
1085+
1086+
PROGMEM_STRING(MinThreshold, "MinThreshold");
1087+
PROGMEM_STRING(MaxThreshold, "MaxThreshold");
1088+
10811089
PROGMEM_STRING(ZeroThreshold, "ZeroThreshold");
10821090

10831091
PROGMEM_STRING(Mains, "Mains");
@@ -3449,6 +3457,14 @@ void list(JsonObject& root) {
34493457
});
34503458
}
34513459

3460+
void threshold_or_nan(JsonArray& out, const double& threshold) {
3461+
if (!std::isnan(threshold)) {
3462+
out.add(threshold);
3463+
} else {
3464+
out.add("NaN");
3465+
}
3466+
}
3467+
34523468
void settings(JsonObject& root) {
34533469
if (!sensor::ready()) {
34543470
return;
@@ -3457,7 +3473,7 @@ void settings(JsonObject& root) {
34573473
// XXX: inject 'null' in the output. need this for optional fields, since the current
34583474
// version of serializer only does this for char ptr and even makes NaN serialized as
34593475
// NaN, instead of more commonly used null (but, expect this to be fixed after switching to v6+)
3460-
static const char* const NullSymbol { nullptr };
3476+
constexpr char* const NullSymbol { nullptr };
34613477

34623478
espurna::web::ws::EnumerablePayload payload{root, STRING_VIEW("magnitudes-settings")};
34633479
payload(STRING_VIEW("values"), magnitude::count(),
@@ -3479,11 +3495,15 @@ void settings(JsonObject& root) {
34793495
}},
34803496
{settings::suffix::ZeroThreshold, [](JsonArray& out, size_t index) {
34813497
const auto threshold = magnitude::get(index).zero_threshold;
3482-
if (!std::isnan(threshold)) {
3483-
out.add(threshold);
3484-
} else {
3485-
out.add("NaN");
3486-
}
3498+
threshold_or_nan(out, threshold);
3499+
}},
3500+
{settings::suffix::MinThreshold, [](JsonArray& out, size_t index) {
3501+
const auto threshold = magnitude::get(index).min_threshold;
3502+
threshold_or_nan(out, threshold);
3503+
}},
3504+
{settings::suffix::MaxThreshold, [](JsonArray& out, size_t index) {
3505+
const auto threshold = magnitude::get(index).max_threshold;
3506+
threshold_or_nan(out, threshold);
34873507
}},
34883508
{settings::suffix::MinDelta, [](JsonArray& out, size_t index) {
34893509
out.add(magnitude::get(index).min_delta);
@@ -3964,23 +3984,30 @@ void configure_magnitude(Magnitude& magnitude) {
39643984
: magnitude::decimals(magnitude.units));
39653985
}
39663986

3967-
// Per-magnitude min & max delta settings for reporting the value
3968-
// - ${prefix}MinDelta${index} controls whether we report when report counter overflows
3969-
// (default is set to 0.0 aka value has changed from the last recorded one)
3970-
// - ${prefix}MaxDelta${index} will trigger report as soon as read value is greater than the specified delta
3971-
// (default is 0.0 as well, but this needs to be >0 to actually do something)
3987+
// Per-magnitude min & max delta of the report value, may trigger reports independent of the read counter overflow
3988+
// - ${prefix}MinDelta${index} for value change greater than or equal to the specified delta
3989+
// - ${prefix}MaxDelta${index} for value change less than or equal to the specified delta
3990+
// Both are 0. by default, meaning these checks are ignored when processing read data
39723991
magnitude.min_delta = getSetting(
39733992
settings::keys::get(magnitude, settings::suffix::MinDelta),
39743993
build::DefaultMinDelta);
39753994
magnitude.max_delta = getSetting(
39763995
settings::keys::get(magnitude, settings::suffix::MaxDelta),
39773996
build::DefaultMaxDelta);
39783997

3979-
// Sometimes we want to ensure the value is above certain threshold before reporting
3998+
// Overwrite value with 0 when below a certain threshold. Happens when report is triggered, before any further checks
39803999
magnitude.zero_threshold = getSetting(
39814000
settings::keys::get(magnitude, settings::suffix::ZeroThreshold),
39824001
Value::Unknown);
39834002

4003+
// Per-magnitude min & max checks of the report value
4004+
magnitude.min_threshold = getSetting(
4005+
settings::keys::get(magnitude, settings::suffix::MinThreshold),
4006+
Value::Unknown);
4007+
magnitude.max_threshold = getSetting(
4008+
settings::keys::get(magnitude, settings::suffix::MaxThreshold),
4009+
Value::Unknown);
4010+
39844011
// When we don't save energy, purge existing value in both RAM & settings
39854012
if (isEmon(magnitude.sensor) && (MAGNITUDE_ENERGY == magnitude.type) && (0 == energy::every())) {
39864013
energy::reset(magnitude.index_global);
@@ -4175,6 +4202,66 @@ bool ready_to_read() {
41754202
return internal::read_flag.wait(internal::read_interval);
41764203
}
41774204

4205+
bool ready_to_report(ValuePair& out, const ValuePair& processed, const Magnitude& magnitude, bool report) {
4206+
// Ensure that reported value change is greater or equal to this delta value
4207+
const bool compare_min_delta { magnitude.min_delta > build::DefaultMinDelta };
4208+
report = report || compare_min_delta;
4209+
4210+
// Ensure that reported value change is less or equal to this delta value
4211+
const bool compare_max_delta { magnitude.max_delta > build::DefaultMaxDelta };
4212+
report = report || compare_max_delta;
4213+
4214+
// Ensure that reported value is greater than or equal to this value
4215+
const bool check_min_threshold { !std::isnan(magnitude.min_threshold) };
4216+
report = report || check_min_threshold;
4217+
4218+
// Ensure that reported value is less than or equal to this value
4219+
const bool check_max_threshold { !std::isnan(magnitude.max_threshold) };
4220+
report = report || check_max_threshold;
4221+
4222+
// Figure out whether report value is zero or not
4223+
const bool check_zero_threshold { !std::isnan(magnitude.zero_threshold) };
4224+
report = report || check_zero_threshold;
4225+
4226+
if (report) {
4227+
if (magnitude.filter->ready()) {
4228+
out = ValuePair{
4229+
.value = magnitude.filter->value(),
4230+
.units = processed.units,
4231+
};
4232+
magnitude.filter->restart();
4233+
} else {
4234+
out = processed;
4235+
}
4236+
4237+
if (check_zero_threshold && out.value < magnitude.zero_threshold) {
4238+
out.value = 0.0;
4239+
}
4240+
4241+
const bool previous_report { !std::isnan(magnitude.reported.value) };
4242+
4243+
if (report && previous_report && compare_min_delta) {
4244+
report = std::abs(out.value - magnitude.reported.value)
4245+
>= magnitude.min_delta;
4246+
}
4247+
4248+
if (report && previous_report && compare_max_delta) {
4249+
report = std::abs(out.value - magnitude.reported.value)
4250+
<= magnitude.max_delta;
4251+
}
4252+
4253+
if (report && check_min_threshold) {
4254+
report = out.value >= magnitude.min_threshold;
4255+
}
4256+
4257+
if (report && check_max_threshold) {
4258+
report = out.value <= magnitude.max_threshold;
4259+
}
4260+
}
4261+
4262+
return report;
4263+
}
4264+
41784265
void loop() {
41794266
// TODO: allow to do nothing
41804267
if (internal::state == State::Idle) {
@@ -4296,45 +4383,10 @@ void loop() {
42964383
energy::update(magnitude, report);
42974384
}
42984385

4299-
// Ensure that reported value change is greater or equal to this delta value
4300-
const bool compare_min_delta { magnitude.min_delta > build::DefaultMinDelta };
4301-
report = report || compare_min_delta;
4302-
4303-
// Ensure that reported value change is less or equal to this delta value
4304-
const bool compare_max_delta { magnitude.max_delta > build::DefaultMaxDelta };
4305-
report = report || compare_max_delta;
4306-
4307-
// Ensure that report value is greater than this threshold value
4308-
const bool check_zero_threshold { !std::isnan(magnitude.zero_threshold) };
4309-
report = report || check_zero_threshold;
4310-
4311-
if (report) {
4312-
if (magnitude.filter->ready()) {
4313-
state.report = ValuePair{
4314-
.value = magnitude.filter->value(),
4315-
.units = state.processed.units,
4316-
};
4317-
magnitude.filter->restart();
4318-
} else {
4319-
state.report = state.processed;
4320-
}
4321-
4322-
const bool previous_report { !std::isnan(magnitude.reported.value) };
4323-
4324-
if (report && previous_report && compare_min_delta) {
4325-
report = std::abs(state.report.value - magnitude.reported.value)
4326-
>= magnitude.min_delta;
4327-
}
4328-
4329-
if (report && previous_report && compare_max_delta) {
4330-
report = std::abs(state.report.value - magnitude.reported.value)
4331-
<= magnitude.max_delta;
4332-
}
4333-
4334-
if (report && check_zero_threshold) {
4335-
report = state.report.value >= magnitude.zero_threshold;
4336-
}
4337-
}
4386+
// Prepare and verify report value before proceeding
4387+
report = ready_to_report(
4388+
state.report, state.processed,
4389+
magnitude, report);
43384390

43394391
// If flag was not reset by the checks above, continue and finally report the value
43404392
if (report) {

0 commit comments

Comments
 (0)