diff --git a/src/_P082_GPS.ino b/src/_P082_GPS.ino index 21d3c1a875..d25deecc3a 100644 --- a/src/_P082_GPS.ino +++ b/src/_P082_GPS.ino @@ -50,6 +50,11 @@ boolean Plugin_082(uint8_t function, struct EventStruct *event, String& string) dev.TimerOption = true; dev.PluginStats = true; dev.CustomVTypeVar = true; +# if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE + + // Allow to use double type for improved accuracy + dev.HasFormatUserVar = true; +# endif // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE break; } @@ -68,7 +73,7 @@ boolean Plugin_082(uint8_t function, struct EventStruct *event, String& string) switch (choice) { case P082_query::P082_QUERY_LONG: case P082_query::P082_QUERY_LAT: - ExtraTaskSettings.TaskDeviceValueDecimals[i] = 6; + ExtraTaskSettings.TaskDeviceValueDecimals[i] = P082_MAX_NR_DECIMALS; break; default: ExtraTaskSettings.TaskDeviceValueDecimals[i] = 2; @@ -133,6 +138,37 @@ boolean Plugin_082(uint8_t function, struct EventStruct *event, String& string) break; } +# if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE + case PLUGIN_FORMAT_USERVAR: + { + P082_data_struct *P082_data = + static_cast(getPluginTaskData(event->TaskIndex)); + + if ((nullptr != P082_data) && P082_data->isInitialized()) { + if (event->idx < P082_NR_OUTPUT_VALUES) { + const uint8_t pconfigIndex = event->idx + P082_QUERY1_CONFIG_POS; + const P082_query query = static_cast(PCONFIG(pconfigIndex)); + + if ((query == P082_query::P082_QUERY_LONG) || + (query == P082_query::P082_QUERY_LAT)) + { + const uint8_t nrDecimals = Cache.getTaskDeviceValueDecimals(event->TaskIndex, event->idx); + + if (nrDecimals > 5) { + const ESPEASY_RULES_FLOAT_TYPE value = P082_data->_cache[static_cast(query)]; + + if (!isnan(value)) { + string = doubleToString(value, nrDecimals); + success = true; + } + } + } + } + } + break; + } +# endif // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE + case PLUGIN_GET_CONFIG_VALUE: { P082_data_struct *P082_data = @@ -142,19 +178,22 @@ boolean Plugin_082(uint8_t function, struct EventStruct *event, String& string) const P082_query query = Plugin_082_from_valuename(string); if (query != P082_query::P082_NR_OUTPUT_OPTIONS) { - const float value = P082_data->_cache[static_cast(query)]; - int nrDecimals = 2; + const ESPEASY_RULES_FLOAT_TYPE value = P082_data->_cache[static_cast(query)]; + int nrDecimals = 2; if ((query == P082_query::P082_QUERY_LONG) || (query == P082_query::P082_QUERY_LAT)) { - nrDecimals = 6; + nrDecimals = P082_MAX_NR_DECIMALS; } else if ((query == P082_query::P082_QUERY_SATVIS) || (query == P082_query::P082_QUERY_SATUSE) || (query == P082_query::P082_QUERY_FIXQ) || (query == P082_query::P082_QUERY_CHKSUM_FAIL)) { nrDecimals = 0; } - - string = toString(value, nrDecimals); +# if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE + string = doubleToString(value, nrDecimals); +# else // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE + string = toString(value, nrDecimals); +# endif // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE success = true; } } @@ -417,8 +456,8 @@ boolean Plugin_082(uint8_t function, struct EventStruct *event, String& string) if (curFixStatus) { if (P082_data->gps->location.isUpdated()) { - const float lng = P082_data->gps->location.lng(); - const float lat = P082_data->gps->location.lat(); + const ESPEASY_RULES_FLOAT_TYPE lng = P082_data->gps->location.lng(); + const ESPEASY_RULES_FLOAT_TYPE lat = P082_data->gps->location.lat(); P082_setOutputValue(event, static_cast(P082_query::P082_QUERY_LONG), lng); P082_setOutputValue(event, static_cast(P082_query::P082_QUERY_LAT), lat); @@ -584,7 +623,7 @@ bool P082_referencePointSet(struct EventStruct *event) { && (P082_LAT_REF < 0.1f) && (P082_LAT_REF > -0.1f)); } -void P082_setOutputValue(struct EventStruct *event, uint8_t outputType, float value) { +void P082_setOutputValue(struct EventStruct *event, uint8_t outputType, ESPEASY_RULES_FLOAT_TYPE value) { P082_data_struct *P082_data = static_cast(getPluginTaskData(event->TaskIndex)); diff --git a/src/src/DataStructs/PluginStats.cpp b/src/src/DataStructs/PluginStats.cpp index c836af50ae..946c634e68 100644 --- a/src/src/DataStructs/PluginStats.cpp +++ b/src/src/DataStructs/PluginStats.cpp @@ -24,9 +24,12 @@ PluginStats::PluginStats(uint8_t nrDecimals, float errorValue) : else { _samples = new (ptr) PluginStatsBuffer_t(); } +# if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE + _offset = 0.0f; +# endif // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE _errorValueIsNaN = isnan(_errorValue); - _minValue = std::numeric_limits::max(); - _maxValue = std::numeric_limits::lowest(); + _minValue = std::numeric_limits::max(); + _maxValue = std::numeric_limits::lowest(); _minValueTimestamp = 0; _maxValueTimestamp = 0; } @@ -58,51 +61,55 @@ void PluginStats::processTimeSet(const double& time_offset) } } -bool PluginStats::push(float value) +bool PluginStats::push(ESPEASY_RULES_FLOAT_TYPE value) { if (_samples == nullptr) { return false; } +# if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE + + if (_samples->isEmpty() && usableValue(value)) { + // When the first value isn't usable, we keep the offset at 0 and thus loose accuracy + _offset = value; + } + return _samples->push(value - _offset); +# else // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE return _samples->push(value); +# endif // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE } -bool PluginStats::matchesLastTwoEntries(float value) const +bool PluginStats::matchesLastTwoEntries(ESPEASY_RULES_FLOAT_TYPE value) const { const size_t nrSamples = getNrSamples(); if (nrSamples < 2) { return false; } - const float last = (*_samples)[nrSamples - 1]; - const float beforeLast = (*_samples)[nrSamples - 2]; +# if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE + return matchesLastTwoEntries(doubleToString(value, _nrDecimals)); +# else // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE + return matchesLastTwoEntries(toString(value, _nrDecimals)); +# endif // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE +} + +bool PluginStats::matchesLastTwoEntries(const String& value_str) const +{ + const size_t nrSamples = getNrSamples(); + + if (nrSamples < 2) { return false; } - const String value_str = toString(value, _nrDecimals); + const ESPEASY_RULES_FLOAT_TYPE last = get(nrSamples - 1); + const ESPEASY_RULES_FLOAT_TYPE beforeLast = get(nrSamples - 2); +# if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE + return + doubleToString(last, _nrDecimals).equals(value_str) && + doubleToString(beforeLast, _nrDecimals).equals(value_str); +# else // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE return toString(last, _nrDecimals).equals(value_str) && toString(beforeLast, _nrDecimals).equals(value_str); - - - /* - const bool value_valid = isValidFloat(value); - const bool last_valid = isValidFloat(last); - - if (value_valid != last_valid) { - return false; - } - const bool beforeLast_valid = isValidFloat(beforeLast); - - if (value_valid != beforeLast_valid) { - return false; - } - - if (value_valid) { - return - approximatelyEqual(value, last) && - approximatelyEqual(value, beforeLast); - } - return true; - */ +# endif // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE } -void PluginStats::trackPeak(float value, int64_t timestamp) +void PluginStats::trackPeak(ESPEASY_RULES_FLOAT_TYPE value, int64_t timestamp) { if ((value > _maxValue) || (value < _minValue)) { if (timestamp == 0) { @@ -124,8 +131,8 @@ void PluginStats::trackPeak(float value, int64_t timestamp) void PluginStats::resetPeaks() { - _minValue = std::numeric_limits::max(); - _maxValue = std::numeric_limits::lowest(); + _minValue = std::numeric_limits::max(); + _maxValue = std::numeric_limits::lowest(); _minValueTimestamp = 0; _maxValueTimestamp = 0; } @@ -141,16 +148,16 @@ size_t PluginStats::getNrSamples() const { return _samples->size(); } -float PluginStats::getSampleAvg() const { +ESPEASY_RULES_FLOAT_TYPE PluginStats::getSampleAvg() const { return getSampleAvg(getNrSamples()); } -float PluginStats::getSampleAvg(PluginStatsBuffer_t::index_t lastNrSamples) const +ESPEASY_RULES_FLOAT_TYPE PluginStats::getSampleAvg(PluginStatsBuffer_t::index_t lastNrSamples) const { const size_t nrSamples = getNrSamples(); if (nrSamples == 0) { return _errorValue; } - float sum = 0.0f; + ESPEASY_RULES_FLOAT_TYPE sum{}; PluginStatsBuffer_t::index_t i = 0; @@ -160,7 +167,7 @@ float PluginStats::getSampleAvg(PluginStatsBuffer_t::index_t lastNrSamples) cons PluginStatsBuffer_t::index_t samplesUsed = 0; for (; i < nrSamples; ++i) { - const float sample((*_samples)[i]); + const ESPEASY_RULES_FLOAT_TYPE sample(get(i)); if (usableValue(sample)) { ++samplesUsed; @@ -172,7 +179,7 @@ float PluginStats::getSampleAvg(PluginStatsBuffer_t::index_t lastNrSamples) cons return sum / samplesUsed; } -float PluginStats::getSampleAvg_time(PluginStatsBuffer_t::index_t lastNrSamples, uint64_t& totalDuration_usec) const +ESPEASY_RULES_FLOAT_TYPE PluginStats::getSampleAvg_time(PluginStatsBuffer_t::index_t lastNrSamples, uint64_t& totalDuration_usec) const { const size_t nrSamples = getNrSamples(); @@ -188,13 +195,13 @@ float PluginStats::getSampleAvg_time(PluginStatsBuffer_t::index_t lastNrSamples, i = nrSamples - lastNrSamples; } - int64_t lastTimestamp = 0; - float lastValue = 0.0f; - bool lastValueUsable = false; - float sum = 0.0f; + int64_t lastTimestamp = 0; + ESPEASY_RULES_FLOAT_TYPE lastValue{}; + bool lastValueUsable = false; + ESPEASY_RULES_FLOAT_TYPE sum{}; for (; i < nrSamples; ++i) { - const float sample((*_samples)[i]); + const ESPEASY_RULES_FLOAT_TYPE sample(get(i)); const int64_t curTimestamp = (*_plugin_stats_timestamps)[i]; const bool curValueUsable = usableValue(sample); @@ -203,7 +210,7 @@ float PluginStats::getSampleAvg_time(PluginStatsBuffer_t::index_t lastNrSamples, if (curValueUsable) { // Old and new value usable, take average of this period. - sum += ((lastValue + sample) / 2.0f) * duration_usec; + sum += ((lastValue + sample) / 2) * duration_usec; } else { // New value is not usable, so just add the last value for the duration. sum += lastValue * duration_usec; @@ -220,11 +227,11 @@ float PluginStats::getSampleAvg_time(PluginStatsBuffer_t::index_t lastNrSamples, return sum / totalDuration_usec; } -float PluginStats::getSampleStdDev(PluginStatsBuffer_t::index_t lastNrSamples) const +ESPEASY_RULES_FLOAT_TYPE PluginStats::getSampleStdDev(PluginStatsBuffer_t::index_t lastNrSamples) const { const size_t nrSamples = getNrSamples(); - float variance = 0.0f; - const float average = getSampleAvg(lastNrSamples); + ESPEASY_RULES_FLOAT_TYPE variance{}; + const ESPEASY_RULES_FLOAT_TYPE average = getSampleAvg(lastNrSamples); if (!usableValue(average)) { return 0.0f; } @@ -236,11 +243,11 @@ float PluginStats::getSampleStdDev(PluginStatsBuffer_t::index_t lastNrSamples) c PluginStatsBuffer_t::index_t samplesUsed = 0; for (; i < nrSamples; ++i) { - const float sample((*_samples)[i]); + const ESPEASY_RULES_FLOAT_TYPE sample(get(i)); if (usableValue(sample)) { ++samplesUsed; - const float diff = sample - average; + const ESPEASY_RULES_FLOAT_TYPE diff = sample - average; variance += diff * diff; } } @@ -248,10 +255,14 @@ float PluginStats::getSampleStdDev(PluginStatsBuffer_t::index_t lastNrSamples) c if (samplesUsed < 2) { return 0.0f; } variance /= samplesUsed; +# if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE + return sqrt(variance); +# else // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE return sqrtf(variance); +# endif // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE } -float PluginStats::getSampleExtreme(PluginStatsBuffer_t::index_t lastNrSamples, bool getMax) const +ESPEASY_RULES_FLOAT_TYPE PluginStats::getSampleExtreme(PluginStatsBuffer_t::index_t lastNrSamples, bool getMax) const { const size_t nrSamples = getNrSamples(); @@ -265,10 +276,10 @@ float PluginStats::getSampleExtreme(PluginStatsBuffer_t::index_t lastNrSamples, bool changed = false; - float res = getMax ? INT_MIN : INT_MAX; + ESPEASY_RULES_FLOAT_TYPE res = getMax ? INT_MIN : INT_MAX; for (; i < nrSamples; ++i) { - const float sample((*_samples)[i]); + const ESPEASY_RULES_FLOAT_TYPE sample(get(i)); if (usableValue(sample)) { if ((getMax && (sample > res)) || @@ -284,7 +295,7 @@ float PluginStats::getSampleExtreme(PluginStatsBuffer_t::index_t lastNrSamples, return res; } -float PluginStats::getSample(int lastNrSamples) const +ESPEASY_RULES_FLOAT_TYPE PluginStats::getSample(int lastNrSamples) const { const size_t nrSamples = getNrSamples(); @@ -299,16 +310,28 @@ float PluginStats::getSample(int lastNrSamples) const } if (i < nrSamples) { - return (*_samples)[i]; + return get(i); } return _errorValue; } -float PluginStats::operator[](PluginStatsBuffer_t::index_t index) const +ESPEASY_RULES_FLOAT_TYPE PluginStats::operator[](PluginStatsBuffer_t::index_t index) const +{ + return get(index); +} + +ESPEASY_RULES_FLOAT_TYPE PluginStats::get(PluginStatsBuffer_t::index_t index) const { const size_t nrSamples = getNrSamples(); - if (index < nrSamples) { return (*_samples)[index]; } + if (index < nrSamples) { +# if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE + ESPEASY_RULES_FLOAT_TYPE res = _offset + (*_samples)[index]; + return res; +# else // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE + return (*_samples)[index]; +# endif // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE + } return _errorValue; } diff --git a/src/src/DataStructs/PluginStats.h b/src/src/DataStructs/PluginStats.h index 2a320eb809..38164c04c9 100644 --- a/src/src/DataStructs/PluginStats.h +++ b/src/src/DataStructs/PluginStats.h @@ -35,23 +35,24 @@ class PluginStats { // Add a sample to the _sample buffer // This does not also track peaks as the peaks could be raw sensor data and the samples processed data. - bool push(float value); + bool push(ESPEASY_RULES_FLOAT_TYPE value); // When only updating the timestamp of the last entry, we should look at the last - bool matchesLastTwoEntries(float value) const; + bool matchesLastTwoEntries(ESPEASY_RULES_FLOAT_TYPE value) const; + bool matchesLastTwoEntries(const String& value_str) const; // Keep track of peaks. // Use this for sensors that need to take several samples before actually output a task value. // For example the ADC with oversampling - void trackPeak(float value, int64_t timestamp = 0u); + void trackPeak(ESPEASY_RULES_FLOAT_TYPE value, int64_t timestamp = 0u); // Get lowest recorded value since reset - float getPeakLow() const { + ESPEASY_RULES_FLOAT_TYPE getPeakLow() const { return hasPeaks() ? _minValue : _errorValue; } // Get highest recorded value since reset - float getPeakHigh() const { + ESPEASY_RULES_FLOAT_TYPE getPeakHigh() const { return hasPeaks() ? _maxValue : _errorValue; } @@ -75,41 +76,43 @@ class PluginStats { size_t getNrSamples() const; // Compute average over all stored values - float getSampleAvg() const; + ESPEASY_RULES_FLOAT_TYPE getSampleAvg() const; // Compute average over last N stored values - float getSampleAvg(PluginStatsBuffer_t::index_t lastNrSamples) const; + ESPEASY_RULES_FLOAT_TYPE getSampleAvg(PluginStatsBuffer_t::index_t lastNrSamples) const; // Compute the standard deviation over all stored values - float getSampleStdDev() const { + ESPEASY_RULES_FLOAT_TYPE getSampleStdDev() const { return getSampleStdDev(getNrSamples()); } // Compute average over all stored values, taking timestamp into account. // Returns average per second. - float getSampleAvg_time(uint64_t& totalDuration_usec) const { + ESPEASY_RULES_FLOAT_TYPE getSampleAvg_time(uint64_t& totalDuration_usec) const { return getSampleAvg_time(getNrSamples(), totalDuration_usec); } // Compute average over last N stored values, taking timestamp into account. // Returns average per second. - float getSampleAvg_time(PluginStatsBuffer_t::index_t lastNrSamples, + ESPEASY_RULES_FLOAT_TYPE getSampleAvg_time(PluginStatsBuffer_t::index_t lastNrSamples, uint64_t & totalDuration_usec) const; // Compute the standard deviation over last N stored values - float getSampleStdDev(PluginStatsBuffer_t::index_t lastNrSamples) const; + ESPEASY_RULES_FLOAT_TYPE getSampleStdDev(PluginStatsBuffer_t::index_t lastNrSamples) const; // Compute min/max over last N stored values - float getSampleExtreme(PluginStatsBuffer_t::index_t lastNrSamples, + ESPEASY_RULES_FLOAT_TYPE getSampleExtreme(PluginStatsBuffer_t::index_t lastNrSamples, bool getMax) const; // Compute sample stored values - float getSample(int lastNrSamples) const; + ESPEASY_RULES_FLOAT_TYPE getSample(int lastNrSamples) const; - float operator[](PluginStatsBuffer_t::index_t index) const; + ESPEASY_RULES_FLOAT_TYPE operator[](PluginStatsBuffer_t::index_t index) const; private: + ESPEASY_RULES_FLOAT_TYPE get(PluginStatsBuffer_t::index_t index) const; + static bool matchedCommand(const String & command, const __FlashStringHelper *cmd_match, int & nrSamples); @@ -177,15 +180,19 @@ class PluginStats { private: + // TD-er: Keep this comparing against float type bool usableValue(float value) const; - float _minValue; - float _maxValue; + ESPEASY_RULES_FLOAT_TYPE _minValue; + ESPEASY_RULES_FLOAT_TYPE _maxValue; int64_t _minValueTimestamp; int64_t _maxValueTimestamp; PluginStatsBuffer_t *_samples = nullptr; - float _errorValue; +#if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE + ESPEASY_RULES_FLOAT_TYPE _offset{}; +#endif + float _errorValue; // TD-er: Keep this errorvalue as float type bool _errorValueIsNaN; uint8_t _nrDecimals = 3u; diff --git a/src/src/DataStructs/PluginStats_array.cpp b/src/src/DataStructs/PluginStats_array.cpp index 14a7d4782d..bd9c79c927 100644 --- a/src/src/DataStructs/PluginStats_array.cpp +++ b/src/src/DataStructs/PluginStats_array.cpp @@ -202,9 +202,7 @@ void PluginStats_array::pushPluginStatsValues( while (isSame && i < valueCount) { if (_plugin_stats[i] != nullptr) { - const float value = UserVar.getAsDouble(event->TaskIndex, i, sensorType); - - if (!_plugin_stats[i]->matchesLastTwoEntries(value)) { + if (!_plugin_stats[i]->matchesLastTwoEntries(UserVar.getAsString(event->TaskIndex, i, sensorType))) { isSame = false; } } @@ -223,7 +221,7 @@ void PluginStats_array::pushPluginStatsValues( for (size_t i = 0; i < valueCount; ++i) { if (_plugin_stats[i] != nullptr) { - const float value = UserVar.getAsDouble(event->TaskIndex, i, sensorType); + const ESPEASY_RULES_FLOAT_TYPE value = UserVar.getAsDouble(event->TaskIndex, i, sensorType); _plugin_stats[i]->push(value); if (trackPeaks) { diff --git a/src/src/DataStructs/UserVarStruct.cpp b/src/src/DataStructs/UserVarStruct.cpp index ee579afe34..7738005cc2 100644 --- a/src/src/DataStructs/UserVarStruct.cpp +++ b/src/src/DataStructs/UserVarStruct.cpp @@ -4,15 +4,16 @@ #include "../DataStructs/TimingStats.h" #include "../ESPEasyCore/ESPEasy_Log.h" #include "../Globals/Cache.h" +#include "../Globals/Device.h" #include "../Globals/Plugins.h" #include "../Globals/RulesCalculate.h" #include "../Helpers/_Plugin_SensorTypeHelper.h" #include "../Helpers/CRC_functions.h" +#include "../Helpers/Numerical.h" #include "../Helpers/StringConverter.h" #include "../Helpers/StringParser.h" - void UserVarStruct::clear() { for (size_t i = 0; i < TASKS_MAX; ++i) { @@ -40,7 +41,7 @@ float UserVarStruct::operator[](unsigned int index) const static float errorvalue = NAN; #ifndef LIMIT_BUILD_SIZE addLog(LOG_LEVEL_ERROR, F("UserVar index out of range")); -#endif +#endif // ifndef LIMIT_BUILD_SIZE return errorvalue; } } @@ -253,6 +254,27 @@ ESPEASY_RULES_FLOAT_TYPE UserVarStruct::getAsDouble(taskIndex_t taskIndex, Sensor_VType sensorType, bool raw) const { +#if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE + + if (raw || !Cache.hasFormula(taskIndex, varNr)) { + const deviceIndex_t DeviceIndex = getDeviceIndex_from_TaskIndex(taskIndex); + + if (Device[DeviceIndex].HasFormatUserVar) { + // First try to format using the plugin specific formatting. + String formattedUserVar; + EventStruct tempEvent(taskIndex); + tempEvent.idx = varNr; + + if (PluginCall(PLUGIN_FORMAT_USERVAR, &tempEvent, formattedUserVar)) { + ESPEASY_RULES_FLOAT_TYPE value{}; + + if (validDoubleFromString(formattedUserVar, value)) { + return value; + } + } + } + } +#endif // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE const TaskValues_Data_t *data = getRawOrComputed(taskIndex, varNr, sensorType, raw); if (data != nullptr) { @@ -263,6 +285,20 @@ ESPEASY_RULES_FLOAT_TYPE UserVarStruct::getAsDouble(taskIndex_t taskIndex, String UserVarStruct::getAsString(taskIndex_t taskIndex, taskVarIndex_t varNr, Sensor_VType sensorType, uint8_t nrDecimals, bool raw) const { + if (raw || !Cache.hasFormula(taskIndex, varNr)) { + const deviceIndex_t DeviceIndex = getDeviceIndex_from_TaskIndex(taskIndex); + + if (Device[DeviceIndex].HasFormatUserVar) { + // First try to format using the plugin specific formatting. + String formattedUserVar; + EventStruct tempEvent(taskIndex); + tempEvent.idx = varNr; + + if (PluginCall(PLUGIN_FORMAT_USERVAR, &tempEvent, formattedUserVar)) { + return formattedUserVar; + } + } + } const TaskValues_Data_t *data = getRawOrComputed(taskIndex, varNr, sensorType, raw); if (data != nullptr) { @@ -339,7 +375,7 @@ void UserVarStruct::clear_computed(taskIndex_t taskIndex) const uint16_t key = makeWord(taskIndex, varNr); #ifndef LIMIT_BUILD_SIZE { - auto it = _preprocessedFormula.find(key); + auto it = _preprocessedFormula.find(key); if (it != _preprocessedFormula.end()) { _preprocessedFormula.erase(it); @@ -347,7 +383,7 @@ void UserVarStruct::clear_computed(taskIndex_t taskIndex) } #endif // ifndef LIMIT_BUILD_SIZE { - auto it = _prevValue.find(key); + auto it = _prevValue.find(key); if (it != _prevValue.end()) { _prevValue.erase(it); @@ -359,6 +395,7 @@ void UserVarStruct::clear_computed(taskIndex_t taskIndex) void UserVarStruct::markPluginRead(taskIndex_t taskIndex) { struct EventStruct TempEvent(taskIndex); + for (taskVarIndex_t varNr = 0; validTaskVarIndex(varNr); ++varNr) { if (Cache.hasFormula_with_prevValue(taskIndex, varNr)) { const uint16_t key = makeWord(taskIndex, varNr); @@ -446,14 +483,15 @@ bool UserVarStruct::applyFormula(taskIndex_t taskIndex, if (formula_has_prevvalue) { const String prev_str = getPreviousValue(taskIndex, varNr, sensorType); formula.replace(F("%pvalue%"), prev_str.isEmpty() ? value : prev_str); + /* - addLog(LOG_LEVEL_INFO, - strformat( - F("pvalue: %s, value: %s, formula: %s"), - prev_str.c_str(), + addLog(LOG_LEVEL_INFO, + strformat( + F("pvalue: %s, value: %s, formula: %s"), + prev_str.c_str(), value.c_str(), formula.c_str())); - */ + */ } ESPEASY_RULES_FLOAT_TYPE result{}; @@ -515,7 +553,7 @@ String UserVarStruct::getPreprocessedFormula(taskIndex_t taskIndex, taskVarIndex if (it == _preprocessedFormula.end()) { _preprocessedFormula.emplace( std::make_pair( - key, + key, RulesCalculate_t::preProces(Cache.getTaskDeviceFormula(taskIndex, varNr)) )); } diff --git a/src/src/Helpers/StringConverter.cpp b/src/src/Helpers/StringConverter.cpp index 27311893d1..d3991f2d35 100644 --- a/src/src/Helpers/StringConverter.cpp +++ b/src/src/Helpers/StringConverter.cpp @@ -453,13 +453,12 @@ String doFormatUserVar(struct EventStruct *event, uint8_t rel_index, bool mustCh if (Device[DeviceIndex].HasFormatUserVar) { // First try to format using the plugin specific formatting. - String result; + String formattedUserVar; EventStruct tempEvent; tempEvent.deep_copy(event); tempEvent.idx = rel_index; - PluginCall(PLUGIN_FORMAT_USERVAR, &tempEvent, result); - if (result.length() > 0) { - return result; + if (PluginCall(PLUGIN_FORMAT_USERVAR, &tempEvent, formattedUserVar)) { + return formattedUserVar; } } diff --git a/src/src/PluginStructs/P082_data_struct.cpp b/src/src/PluginStructs/P082_data_struct.cpp index c51b682bf7..f69207c925 100644 --- a/src/src/PluginStructs/P082_data_struct.cpp +++ b/src/src/PluginStructs/P082_data_struct.cpp @@ -89,7 +89,7 @@ void P082_software_pps::setSentenceType( const uint64_t endOfLine_received_usec = getMicros64() - bytesToUsec(bytesAvailableInSerialBuffer); const int64_t sentence_duration = timeDiff64(_cur_start_sentence_usec, endOfLine_received_usec); -// if (usecPassedSince(_cur_start_sentence_usec) < 1000000ll) { + // if (usecPassedSince(_cur_start_sentence_usec) < 1000000ll) { // Assume a NMEA sentence cannot be over 80 bytes // Apply some tolerance, thus check for duration to receive 120 bytes @@ -144,16 +144,16 @@ uint64_t P082_software_pps::bytesToUsec(uint32_t bytes) const return duration_usec; } -#ifndef BUILD_NO_DEBUG +# ifndef BUILD_NO_DEBUG String P082_software_pps::getStats() const { String res; constexpr uint32_t nrelements = NR_ELEMENTS(_second_frac_in_usec); + for (size_t i = 0; i < nrelements; ++i) { uint32_t value{}; _second_frac_in_usec[i].peek(value); { - switch (i) { case TinyGPSPlus::GPS_SENTENCE_GPGGA: res += F("GGA"); break; case TinyGPSPlus::GPS_SENTENCE_GPRMC: res += F("RMC"); break; @@ -162,16 +162,16 @@ String P082_software_pps::getStats() const case TinyGPSPlus::GPS_SENTENCE_GPGLL: res += F("GLL"); break; case TinyGPSPlus::GPS_SENTENCE_GPTXT: res += F("TXT"); break; default: - res += F("---"); - break; + res += F("---"); + break; } res += strformat(F(": %06d (%d)
"), value, _second_frac_in_usec[i].getCount()); } } - return res; + return res; } -#endif +# endif // ifndef BUILD_NO_DEBUG P082_data_struct::P082_data_struct() : gps(nullptr), easySerial(nullptr) { @@ -352,6 +352,7 @@ bool P082_data_struct::loop() { available = easySerial->available(); _softwarePPS.addStartOfSentence(available); } + if (available == 0) { available = easySerial->available(); } @@ -772,12 +773,13 @@ void P082_data_struct::webformLoad_show_position_scatterplot(struct EventStruct # endif // if FEATURE_CHART_JS # endif // if FEATURE_PLUGIN_STATS -#ifndef BUILD_NO_DEBUG +# ifndef BUILD_NO_DEBUG String P082_data_struct::getPPSStats() const { return _softwarePPS.getStats(); } -#endif + +# endif // ifndef BUILD_NO_DEBUG -#endif // ifdef USES_P082 +#endif // ifdef USES_P082 diff --git a/src/src/PluginStructs/P082_data_struct.h b/src/src/PluginStructs/P082_data_struct.h index 8222aaa51b..001f5e04b7 100644 --- a/src/src/PluginStructs/P082_data_struct.h +++ b/src/src/PluginStructs/P082_data_struct.h @@ -47,6 +47,12 @@ # define P082_QUERY3_DFLT P082_query::P082_QUERY_ALT # define P082_QUERY4_DFLT P082_query::P082_QUERY_SPD +#if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE +#define P082_MAX_NR_DECIMALS 9 +#else +#define P082_MAX_NR_DECIMALS 6 +#endif + enum class P082_query : uint8_t { P082_QUERY_LONG = 0, @@ -255,7 +261,7 @@ struct P082_data_struct : public PluginTaskData_base { String _currentSentence; # endif // ifdef P082_SEND_GPS_TO_LOG - float _cache[static_cast(P082_query::P082_NR_OUTPUT_OPTIONS)]{}; + ESPEASY_RULES_FLOAT_TYPE _cache[static_cast(P082_query::P082_NR_OUTPUT_OPTIONS)]{}; OversamplingHelper_oversampling_gps_time_offset_usec; diff --git a/src/src/WebServer/DevicesPage.cpp b/src/src/WebServer/DevicesPage.cpp index 35c3b0435d..f5d430f393 100644 --- a/src/src/WebServer/DevicesPage.cpp +++ b/src/src/WebServer/DevicesPage.cpp @@ -1763,7 +1763,12 @@ void devicePage_show_task_values(taskIndex_t taskIndex, deviceIndex_t DeviceInde { html_TD(); const String id = getPluginCustomArgName(F("TDVD"), varNr); // ="taskdevicevaluedecimals" - addNumericBox(id, Cache.getTaskDeviceValueDecimals(taskIndex, varNr), 0, 6); +#if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE + constexpr int max_nr_decimals = 9; +#else + constexpr int max_nr_decimals = 6; +#endif + addNumericBox(id, Cache.getTaskDeviceValueDecimals(taskIndex, varNr), 0, max_nr_decimals); } # if FEATURE_PLUGIN_STATS