From 1583548c3a2bbc7310e2ef3c0368150f1f51a74f Mon Sep 17 00:00:00 2001 From: Max Prokhorov Date: Fri, 3 Jul 2020 22:48:28 +0300 Subject: [PATCH] sns: more magnitude settings (#2290) - introduce zero threshold setting to reset value to 0 below a certain point (resolve #2264) for example, set pwrPZeroThreshold0 10.0 for active power (or pwrQ... for apparent, pwrModS... for reactive) will reset always reset value to 0, similar to what turned off relay does. Default value is nan, since we can't use 0.0 on account of negative values. - fix energy magnitude indexes usage, properly reset in API - simplify sending pwr and emon Visible flags - allow to use settings prefixes more, remove snsMinDelta & snsMaxDelta and use relative magnitude indexes --- code/espurna/sensor.cpp | 82 +++++++++++++++++++++------------------ code/espurna/settings.cpp | 6 +-- code/espurna/settings.h | 27 +++++++------ 3 files changed, 63 insertions(+), 52 deletions(-) diff --git a/code/espurna/sensor.cpp b/code/espurna/sensor.cpp index fcc91989..73649544 100644 --- a/code/espurna/sensor.cpp +++ b/code/espurna/sensor.cpp @@ -117,7 +117,7 @@ Copyright (C) 2016-2019 by Xose PĂ©rez #if MAX6675_SUPPORT #include "sensors/MAX6675Sensor.h" -#endif +#endif #if MICS2710_SUPPORT #include "sensors/MICS2710Sensor.h" @@ -233,6 +233,7 @@ struct sensor_magnitude_t { double min_change; // Minimum value change to report double max_change; // Maximum value change to report double correction; // Value correction (applied when processing) + double zero_threshold; // Reset value to zero when below threshold (applied when reading) }; @@ -395,12 +396,11 @@ sensor::Energy _sensorParseEnergy(const String& value) { void _sensorApiResetEnergy(const sensor_magnitude_t& magnitude, const char* payload) { if (!payload || !strlen(payload)) return; - if (payload[0] != '0') return; auto* sensor = static_cast(magnitude.sensor); auto energy = _sensorParseEnergy(payload); - sensor->resetEnergy(magnitude.index_global, energy); + sensor->resetEnergy(magnitude.index_local, energy); } sensor::Energy _sensorEnergyTotal(unsigned char index) { @@ -928,6 +928,11 @@ const char * const _magnitudeSettingsPrefix(unsigned char type) { } } +template +String _magnitudeSettingsKey(sensor_magnitude_t& magnitude, T&& suffix) { + return String(_magnitudeSettingsPrefix(magnitude.type)) + suffix; +} + bool _sensorMatchKeyPrefix(const char * key) { if (strncmp(key, "sns", 3) == 0) return true; @@ -1278,10 +1283,13 @@ void _sensorWebSocketOnConnected(JsonObject& root) { for (auto* sensor [[gnu::unused]] : _sensors) { + if (_sensorIsEmon(sensor)) { + root["emonVisible"] = 1; + root["pwrVisible"] = 1; + } + #if EMON_ANALOG_SUPPORT if (sensor->getID() == SENSOR_EMON_ANALOG_ID) { - root["emonVisible"] = 1; - root["pwrVisible"] = 1; root["pwrVoltage"] = ((EmonAnalogSensor *) sensor)->getVoltage(); } #endif @@ -1289,33 +1297,18 @@ void _sensorWebSocketOnConnected(JsonObject& root) { #if HLW8012_SUPPORT if (sensor->getID() == SENSOR_HLW8012_ID) { root["hlwVisible"] = 1; - root["pwrVisible"] = 1; } #endif #if CSE7766_SUPPORT if (sensor->getID() == SENSOR_CSE7766_ID) { root["cseVisible"] = 1; - root["pwrVisible"] = 1; - } - #endif - - #if V9261F_SUPPORT - if (sensor->getID() == SENSOR_V9261F_ID) { - root["pwrVisible"] = 1; - } - #endif - - #if ECH1560_SUPPORT - if (sensor->getID() == SENSOR_ECH1560_ID) { - root["pwrVisible"] = 1; } #endif #if PZEM004T_SUPPORT if (sensor->getID() == SENSOR_PZEM004T_ID) { root["pzemVisible"] = 1; - root["pwrVisible"] = 1; } #endif @@ -1328,12 +1321,12 @@ void _sensorWebSocketOnConnected(JsonObject& root) { #if MICS2710_SUPPORT || MICS5525_SUPPORT switch (sensor->getID()) { - case SENSOR_MICS2710_ID: - case SENSOR_MICS5525_ID: - root["micsVisible"] = 1; - break; - default: - break; + case SENSOR_MICS2710_ID: + case SENSOR_MICS5525_ID: + root["micsVisible"] = 1; + break; + default: + break; } #endif @@ -2214,10 +2207,7 @@ void _sensorConfigure() { _sensor_realtime = getSetting("apiRealTime", 1 == API_REAL_TIME_VALUES); - // Per-magnitude min & max delta settings - // - min controls whether we report at all when report_count overflows - // - max will trigger report as soon as read value is greater than the specified delta - // (atm this works best for accumulated magnitudes, like energy) + // pre-load some settings that are controlled via old build flags const auto tmp_min_delta = getSetting("tmpMinDelta", TEMPERATURE_MIN_CHANGE); const auto hum_min_delta = getSetting("humMinDelta", HUMIDITY_MIN_CHANGE); const auto ene_max_delta = getSetting("eneMaxDelta", ENERGY_MAX_CHANGE); @@ -2345,8 +2335,6 @@ void _sensorConfigure() { getSetting({"tmpUnits", magnitude.index_global}, tmpUnits) ); break; - case MAGNITUDE_HUMIDITY: - break; case MAGNITUDE_POWER_ACTIVE: magnitude.units = _magnitudeUnitFilter( magnitude, @@ -2379,9 +2367,10 @@ void _sensorConfigure() { magnitude.decimals = (unsigned char) decimals; } - // adjust min & max change delta value to trigger report - // TODO: find a proper way to extend this to min/max of any magnitude - // TODO: we can't use index_global b/c we don't specify type in the setting + // Per-magnitude min & max delta settings + // - min controls whether we report at all when report_count overflows + // - max will trigger report as soon as read value is greater than the specified delta + // (atm this works best for accumulated magnitudes, like energy) { auto min_default = 0.0; auto max_default = 0.0; @@ -2400,8 +2389,22 @@ void _sensorConfigure() { break; } - magnitude.min_change = getSetting({"snsMinDelta", index}, min_default); - magnitude.max_change = getSetting({"snsMaxDelta", index}, max_default); + magnitude.min_change = getSetting( + {_magnitudeSettingsKey(magnitude, F("MinDelta")), magnitude.index_global}, + min_default + ); + magnitude.max_change = getSetting( + {_magnitudeSettingsKey(magnitude, F("MaxDelta")), magnitude.index_global}, + max_default + ); + } + + // Sometimes we want to ensure the value is above certain threshold before reporting + { + magnitude.zero_threshold = getSetting( + {_magnitudeSettingsKey(magnitude, F("ZeroThreshold")), magnitude.index_global}, + std::numeric_limits::quiet_NaN() + ); } // in case we don't save energy periodically, purge existing value in ram & settings @@ -2615,6 +2618,11 @@ void sensorLoop() { } #endif + // In addition to that, we also check that value is above a certain threshold + if ((!std::isnan(magnitude.zero_threshold)) && ((value_raw < magnitude.zero_threshold))) { + value_raw = 0.0; + } + _magnitudes[i].last = value_raw; // ------------------------------------------------------------- diff --git a/code/espurna/settings.cpp b/code/espurna/settings.cpp index db0b8790..bb4cad60 100644 --- a/code/espurna/settings.cpp +++ b/code/espurna/settings.cpp @@ -220,10 +220,10 @@ String settingsQueryDefaults(const String& key) { // ----------------------------------------------------------------------------- String settings_key_t::toString() const { - if (index < 0) { - return value; + if (_index < 0) { + return _value; } else { - return value + index; + return _value + _index; } } diff --git a/code/espurna/settings.h b/code/espurna/settings.h index 60adff0f..cf4dc130 100644 --- a/code/espurna/settings.h +++ b/code/espurna/settings.h @@ -56,30 +56,33 @@ class settings_key_t { public: settings_key_t(const char* value, unsigned char index) : - value(value), index(index) + _value(value), _index(index) {} settings_key_t(const String& value, unsigned char index) : - value(value), index(index) + _value(value), _index(index) + {} + settings_key_t(String&& value, unsigned char index) : + _value(std::move(value)), _index(index) {} settings_key_t(const char* value) : - value(value), index(-1) + _value(value), _index(-1) {} settings_key_t(const String& value) : - value(value), index(-1) + _value(value), _index(-1) {} settings_key_t(const __FlashStringHelper* value) : - value(value), index(-1) + _value(value), _index(-1) {} settings_key_t() : - value(), index(-1) + _value(), _index(-1) {} - bool match(const char* _value) const { - return (value == _value) || (toString() == _value); + bool match(const char* value) const { + return (_value == value) || (toString() == value); } - bool match(const String& _value) const { - return (value == _value) || (toString() == _value); + bool match(const String& value) const { + return (_value == value) || (toString() == value); } String toString() const; @@ -89,8 +92,8 @@ class settings_key_t { } private: - const String value; - int index; + const String _value; + int _index; }; using settings_move_key_t = std::pair;