mirror of
https://github.com/letscontrolit/ESPEasy.git
synced 2026-09-12 09:36:59 +00:00
[Formula] Apply formula when updating taskvalues
This commit is contained in:
+2
-1
@@ -19,6 +19,7 @@
|
||||
#define PLUGIN_VALUENAME1_152 "Output"
|
||||
|
||||
#define P152_DAC_VALUE UserVar[event->BaseVarIndex]
|
||||
#define P152_SET_DAC_VALUE(x) UserVar.setFloat(event->TaskIndex, 0, x)
|
||||
|
||||
#if !(defined(ESP32_CLASSIC) || defined(ESP32S2))
|
||||
# error P152 ESP32 DAC not supported on this CPU type!
|
||||
@@ -94,7 +95,7 @@ boolean Plugin_152(uint8_t function, struct EventStruct *event, String& string)
|
||||
|
||||
if (getDAC_gpio_info(CONFIG_PIN1, dac) && (dac == event->Par1)) {
|
||||
int value = min(255, max(0, event->Par2)); // Limit value
|
||||
P152_DAC_VALUE = value;
|
||||
P152_SET_DAC_VALUE(value);
|
||||
dacWrite(CONFIG_PIN1, value); // Set output value
|
||||
addLog(LOG_LEVEL_INFO,
|
||||
formatGpioName_DAC(CONFIG_PIN1) +
|
||||
|
||||
@@ -151,6 +151,20 @@ String Caches::getTaskDeviceValueName(taskIndex_t TaskIndex, uint8_t rel_index)
|
||||
return EMPTY_STRING;
|
||||
}
|
||||
|
||||
bool Caches::hasFormula(taskIndex_t TaskIndex, uint8_t rel_index)
|
||||
{
|
||||
if (validTaskIndex(TaskIndex)) {
|
||||
// Just a quick test to see if we do have a formula present.
|
||||
// Task Formula are not used very often, so we will probably almost always have to return an empty string.
|
||||
auto it = getExtraTaskSettings(TaskIndex);
|
||||
|
||||
if (it != extraTaskSettings_cache.end()) {
|
||||
return bitRead(it->second.hasFormula, rel_index);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Caches::hasFormula(taskIndex_t TaskIndex)
|
||||
{
|
||||
if (validTaskIndex(TaskIndex)) {
|
||||
@@ -159,7 +173,7 @@ bool Caches::hasFormula(taskIndex_t TaskIndex)
|
||||
auto it = getExtraTaskSettings(TaskIndex);
|
||||
|
||||
if (it != extraTaskSettings_cache.end()) {
|
||||
return it->second.hasFormula;
|
||||
return it->second.hasFormula != 0;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -167,7 +181,7 @@ bool Caches::hasFormula(taskIndex_t TaskIndex)
|
||||
|
||||
String Caches::getTaskDeviceFormula(taskIndex_t TaskIndex, uint8_t rel_index)
|
||||
{
|
||||
if ((rel_index < VARS_PER_TASK) && hasFormula(TaskIndex)) {
|
||||
if ((rel_index < VARS_PER_TASK) && bitRead(hasFormula(TaskIndex), rel_index)) {
|
||||
#ifdef ESP32
|
||||
auto it = getExtraTaskSettings(TaskIndex);
|
||||
|
||||
@@ -297,7 +311,7 @@ void Caches::updateExtraTaskSettingsCache()
|
||||
#ifdef ESP32
|
||||
move_special(tmp.TaskDeviceFormula[i], String(ExtraTaskSettings.TaskDeviceFormula[i]));
|
||||
#endif
|
||||
tmp.hasFormula = true;
|
||||
bitSet(tmp.hasFormula, i);
|
||||
}
|
||||
tmp.decimals[i] = ExtraTaskSettings.TaskDeviceValueDecimals[i];
|
||||
#if FEATURE_PLUGIN_STATS
|
||||
|
||||
@@ -51,7 +51,7 @@ struct ExtraTaskSettings_cache_t {
|
||||
#if FEATURE_PLUGIN_STATS
|
||||
PluginStats_Config_t pluginStatsConfig[VARS_PER_TASK] = {};
|
||||
#endif // if FEATURE_PLUGIN_STATS
|
||||
bool hasFormula = false;
|
||||
uint8_t hasFormula = 0; // Bitmap which task value has formula
|
||||
};
|
||||
|
||||
typedef std::map<String, taskIndex_t> TaskIndexNameMap;
|
||||
@@ -86,7 +86,8 @@ struct Caches {
|
||||
uint8_t rel_index);
|
||||
|
||||
// Check to see if at least one of the taskvalues has a non-empty formula field.
|
||||
bool hasFormula(taskIndex_t TaskIndex);
|
||||
bool hasFormula(taskIndex_t TaskIndex, uint8_t rel_index);
|
||||
bool hasFormula(taskIndex_t TaskIndex);
|
||||
|
||||
|
||||
String getTaskDeviceFormula(taskIndex_t TaskIndex,
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
#include "../DataStructs/UserVarStruct.h"
|
||||
|
||||
#include "../DataStructs/TimingStats.h"
|
||||
|
||||
#include "../ESPEasyCore/ESPEasy_Log.h"
|
||||
#include "../Globals/Cache.h"
|
||||
#include "../Globals/Plugins.h"
|
||||
#include "../Globals/RulesCalculate.h"
|
||||
#include "../Helpers/_Plugin_SensorTypeHelper.h"
|
||||
#include "../Helpers/CRC_functions.h"
|
||||
#include "../Helpers/StringParser.h"
|
||||
|
||||
|
||||
|
||||
UserVarStruct::UserVarStruct()
|
||||
{
|
||||
@@ -23,38 +30,43 @@ void UserVarStruct::clear()
|
||||
|
||||
// Implementation of [] operator. This function must return a
|
||||
// reference as array element can be put on left side
|
||||
|
||||
/*
|
||||
float& UserVarStruct::operator[](unsigned int index)
|
||||
float& UserVarStruct::operator[](unsigned int index)
|
||||
{
|
||||
const unsigned int taskIndex = index / VARS_PER_TASK;
|
||||
const unsigned int varNr = index % VARS_PER_TASK;
|
||||
|
||||
if (taskIndex >= _data.size()) {
|
||||
static float errorvalue = NAN;
|
||||
addLog(LOG_LEVEL_ERROR, F("UserVar index out of range"));
|
||||
return errorvalue;
|
||||
}
|
||||
return _data.at(taskIndex).floats[varNr];
|
||||
}
|
||||
*/
|
||||
float UserVarStruct::operator[](unsigned int index) const
|
||||
{
|
||||
const unsigned int taskIndex = index / VARS_PER_TASK;
|
||||
const unsigned int varNr = index % VARS_PER_TASK;
|
||||
|
||||
if (taskIndex >= _data.size()) {
|
||||
const TaskValues_Data_t *data = getRawOrComputed(taskIndex, varNr);
|
||||
|
||||
if (data != nullptr) {
|
||||
return data->getFloat(varNr);
|
||||
} else {
|
||||
static float errorvalue = NAN;
|
||||
addLog(LOG_LEVEL_ERROR, F("UserVar index out of range"));
|
||||
return errorvalue;
|
||||
}
|
||||
return _data.at(taskIndex).floats[varNr];
|
||||
}
|
||||
*/
|
||||
|
||||
const float& UserVarStruct::operator[](unsigned int index) const
|
||||
{
|
||||
const unsigned int taskIndex = index / VARS_PER_TASK;
|
||||
const unsigned int varNr = index % VARS_PER_TASK;
|
||||
|
||||
if (taskIndex >= _data.size()) {
|
||||
static float errorvalue = NAN;
|
||||
addLog(LOG_LEVEL_ERROR, F("UserVar index out of range"));
|
||||
return errorvalue;
|
||||
}
|
||||
return _data.at(taskIndex).floats[varNr];
|
||||
}
|
||||
|
||||
unsigned long UserVarStruct::getSensorTypeLong(taskIndex_t taskIndex) const
|
||||
{
|
||||
if (taskIndex < _data.size()) {
|
||||
return _data[taskIndex].getSensorTypeLong();
|
||||
const TaskValues_Data_t *data = getRawOrComputed(taskIndex, 0);
|
||||
|
||||
if (data != nullptr) {
|
||||
return data->getSensorTypeLong();
|
||||
}
|
||||
return 0u;
|
||||
}
|
||||
@@ -62,7 +74,12 @@ unsigned long UserVarStruct::getSensorTypeLong(taskIndex_t taskIndex) const
|
||||
void UserVarStruct::setSensorTypeLong(taskIndex_t taskIndex, unsigned long value)
|
||||
{
|
||||
if (taskIndex < _data.size()) {
|
||||
_data[taskIndex].setSensorTypeLong(value);
|
||||
if (Cache.hasFormula(taskIndex, 0)) {
|
||||
const ESPEASY_RULES_FLOAT_TYPE tmp = value;
|
||||
applyFormula(taskIndex, 0, tmp, Sensor_VType::SENSOR_TYPE_ULONG);
|
||||
} else {
|
||||
_data[taskIndex].setSensorTypeLong(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,8 +88,10 @@ void UserVarStruct::setSensorTypeLong(taskIndex_t taskIndex, unsigned long value
|
||||
int32_t UserVarStruct::getInt32(taskIndex_t taskIndex,
|
||||
uint8_t varNr) const
|
||||
{
|
||||
if (taskIndex < _data.size()) {
|
||||
return _data[taskIndex].getInt32(varNr);
|
||||
const TaskValues_Data_t *data = getRawOrComputed(taskIndex, varNr);
|
||||
|
||||
if (data != nullptr) {
|
||||
return data->getInt32(varNr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -82,7 +101,12 @@ void UserVarStruct::setInt32(taskIndex_t taskIndex,
|
||||
int32_t value)
|
||||
{
|
||||
if (taskIndex < _data.size()) {
|
||||
_data[taskIndex].setInt32(varNr, value);
|
||||
if (Cache.hasFormula(taskIndex, varNr)) {
|
||||
const ESPEASY_RULES_FLOAT_TYPE tmp = value;
|
||||
applyFormula(taskIndex, varNr, tmp, Sensor_VType::SENSOR_TYPE_INT32_QUAD);
|
||||
} else {
|
||||
_data[taskIndex].setInt32(varNr, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,8 +114,10 @@ void UserVarStruct::setInt32(taskIndex_t taskIndex,
|
||||
|
||||
uint32_t UserVarStruct::getUint32(taskIndex_t taskIndex, uint8_t varNr) const
|
||||
{
|
||||
if (taskIndex < _data.size()) {
|
||||
return _data[taskIndex].getUint32(varNr);
|
||||
const TaskValues_Data_t *data = getRawOrComputed(taskIndex, varNr);
|
||||
|
||||
if (data != nullptr) {
|
||||
return data->getUint32(varNr);
|
||||
}
|
||||
return 0u;
|
||||
}
|
||||
@@ -99,7 +125,12 @@ uint32_t UserVarStruct::getUint32(taskIndex_t taskIndex, uint8_t varNr) const
|
||||
void UserVarStruct::setUint32(taskIndex_t taskIndex, uint8_t varNr, uint32_t value)
|
||||
{
|
||||
if (taskIndex < _data.size()) {
|
||||
_data[taskIndex].setUint32(varNr, value);
|
||||
if (Cache.hasFormula(taskIndex, varNr)) {
|
||||
const ESPEASY_RULES_FLOAT_TYPE tmp = value;
|
||||
applyFormula(taskIndex, varNr, tmp, Sensor_VType::SENSOR_TYPE_UINT32_QUAD);
|
||||
} else {
|
||||
_data[taskIndex].setUint32(varNr, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,8 +139,10 @@ void UserVarStruct::setUint32(taskIndex_t taskIndex, uint8_t varNr, uint32_t val
|
||||
int64_t UserVarStruct::getInt64(taskIndex_t taskIndex,
|
||||
uint8_t varNr) const
|
||||
{
|
||||
if (taskIndex < _data.size()) {
|
||||
return _data[taskIndex].getInt64(varNr);
|
||||
const TaskValues_Data_t *data = getRawOrComputed(taskIndex, varNr);
|
||||
|
||||
if (data != nullptr) {
|
||||
return data->getInt64(varNr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -119,15 +152,22 @@ void UserVarStruct::setInt64(taskIndex_t taskIndex,
|
||||
int64_t value)
|
||||
{
|
||||
if (taskIndex < _data.size()) {
|
||||
_data[taskIndex].setInt64(varNr, value);
|
||||
if (Cache.hasFormula(taskIndex, varNr)) {
|
||||
const ESPEASY_RULES_FLOAT_TYPE tmp = value;
|
||||
applyFormula(taskIndex, varNr, tmp, Sensor_VType::SENSOR_TYPE_INT64_DUAL);
|
||||
} else {
|
||||
_data[taskIndex].setInt64(varNr, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t UserVarStruct::getUint64(taskIndex_t taskIndex,
|
||||
uint8_t varNr) const
|
||||
{
|
||||
if (taskIndex < _data.size()) {
|
||||
return _data[taskIndex].getUint64(varNr);
|
||||
const TaskValues_Data_t *data = getRawOrComputed(taskIndex, varNr);
|
||||
|
||||
if (data != nullptr) {
|
||||
return data->getUint64(varNr);
|
||||
}
|
||||
return 0u;
|
||||
}
|
||||
@@ -137,7 +177,12 @@ void UserVarStruct::setUint64(taskIndex_t taskIndex,
|
||||
uint64_t value)
|
||||
{
|
||||
if (taskIndex < _data.size()) {
|
||||
_data[taskIndex].setUint64(varNr, value);
|
||||
if (Cache.hasFormula(taskIndex, varNr)) {
|
||||
const ESPEASY_RULES_FLOAT_TYPE tmp = value;
|
||||
applyFormula(taskIndex, varNr, tmp, Sensor_VType::SENSOR_TYPE_UINT64_DUAL);
|
||||
} else {
|
||||
_data[taskIndex].setUint64(varNr, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,8 +191,10 @@ void UserVarStruct::setUint64(taskIndex_t taskIndex,
|
||||
float UserVarStruct::getFloat(taskIndex_t taskIndex,
|
||||
uint8_t varNr) const
|
||||
{
|
||||
if (taskIndex < _data.size()) {
|
||||
return _data[taskIndex].getFloat(varNr);
|
||||
const TaskValues_Data_t *data = getRawOrComputed(taskIndex, varNr);
|
||||
|
||||
if (data != nullptr) {
|
||||
return data->getFloat(varNr);
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
@@ -157,17 +204,24 @@ void UserVarStruct::setFloat(taskIndex_t taskIndex,
|
||||
float value)
|
||||
{
|
||||
if (taskIndex < _data.size()) {
|
||||
_data[taskIndex].setFloat(varNr, value);
|
||||
if (Cache.hasFormula(taskIndex, varNr)) {
|
||||
const ESPEASY_RULES_FLOAT_TYPE tmp = value;
|
||||
applyFormula(taskIndex, varNr, tmp, Sensor_VType::SENSOR_TYPE_QUAD);
|
||||
} else {
|
||||
_data[taskIndex].setFloat(varNr, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if FEATURE_EXTENDED_TASK_VALUE_TYPES
|
||||
#if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
|
||||
# if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
|
||||
double UserVarStruct::getDouble(taskIndex_t taskIndex,
|
||||
uint8_t varNr) const
|
||||
{
|
||||
if (taskIndex < _data.size()) {
|
||||
return _data[taskIndex].getDouble(varNr);
|
||||
const TaskValues_Data_t *data = getRawOrComputed(taskIndex, varNr);
|
||||
|
||||
if (data != nullptr) {
|
||||
return data->getDouble(varNr);
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
@@ -177,43 +231,52 @@ void UserVarStruct::setDouble(taskIndex_t taskIndex,
|
||||
double value)
|
||||
{
|
||||
if (taskIndex < _data.size()) {
|
||||
_data[taskIndex].setDouble(varNr, value);
|
||||
if (Cache.hasFormula(taskIndex, varNr)) {
|
||||
applyFormula(taskIndex, varNr, value, Sensor_VType::SENSOR_TYPE_DOUBLE_DUAL);
|
||||
} else {
|
||||
_data[taskIndex].setDouble(varNr, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif // if FEATURE_EXTENDED_TASK_VALUE_TYPES
|
||||
|
||||
# endif // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
|
||||
#endif // if FEATURE_EXTENDED_TASK_VALUE_TYPES
|
||||
|
||||
ESPEASY_RULES_FLOAT_TYPE UserVarStruct::getAsDouble(taskIndex_t taskIndex,
|
||||
uint8_t varNr,
|
||||
Sensor_VType sensorType) const
|
||||
uint8_t varNr,
|
||||
Sensor_VType sensorType) const
|
||||
{
|
||||
if (taskIndex < _data.size()) {
|
||||
return _data[taskIndex].getAsDouble(varNr, sensorType);
|
||||
const TaskValues_Data_t *data = getRawOrComputed(taskIndex, varNr);
|
||||
|
||||
if (data != nullptr) {
|
||||
return data->getAsDouble(varNr, sensorType);
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
String UserVarStruct::getAsString(taskIndex_t taskIndex, uint8_t varNr, Sensor_VType sensorType, uint8_t nrDecimals) const
|
||||
{
|
||||
if (taskIndex < _data.size()) {
|
||||
return _data[taskIndex].getAsString(varNr, sensorType, nrDecimals);
|
||||
const TaskValues_Data_t *data = getRawOrComputed(taskIndex, varNr);
|
||||
|
||||
if (data != nullptr) {
|
||||
return data->getAsString(varNr, sensorType, nrDecimals);
|
||||
}
|
||||
return EMPTY_STRING;
|
||||
}
|
||||
|
||||
void UserVarStruct::set(taskIndex_t taskIndex, uint8_t varNr, const ESPEASY_RULES_FLOAT_TYPE& value, Sensor_VType sensorType)
|
||||
{
|
||||
if (taskIndex < _data.size()) {
|
||||
_data[taskIndex].set(varNr, value, sensorType);
|
||||
}
|
||||
applyFormula(taskIndex, varNr, value, sensorType);
|
||||
}
|
||||
|
||||
bool UserVarStruct::isValid(taskIndex_t taskIndex,
|
||||
uint8_t varNr,
|
||||
Sensor_VType sensorType) const
|
||||
{
|
||||
if (taskIndex < _data.size()) {
|
||||
return _data[taskIndex].isValid(varNr, sensorType);
|
||||
const TaskValues_Data_t *data = getRawOrComputed(taskIndex, varNr);
|
||||
|
||||
if (data != nullptr) {
|
||||
return data->isValid(varNr, sensorType);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -247,3 +310,70 @@ uint32_t UserVarStruct::compute_CRC32() const
|
||||
|
||||
return calc_CRC32(buffer, size);
|
||||
}
|
||||
|
||||
void UserVarStruct::clear_computed(taskIndex_t taskIndex)
|
||||
{
|
||||
if (!Cache.hasFormula(taskIndex)) {
|
||||
auto it = _computed.find(taskIndex);
|
||||
|
||||
if (it != _computed.end()) {
|
||||
_computed.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const TaskValues_Data_t * UserVarStruct::getRawOrComputed(taskIndex_t taskIndex, uint8_t varNr) const
|
||||
{
|
||||
if (Cache.hasFormula(taskIndex, varNr)) {
|
||||
auto it = _computed.find(taskIndex);
|
||||
|
||||
if (it != _computed.end()) {
|
||||
return &(it->second);
|
||||
}
|
||||
}
|
||||
return getTaskValues_Data(taskIndex);
|
||||
}
|
||||
|
||||
void UserVarStruct::applyFormula(taskIndex_t taskIndex,
|
||||
uint8_t varNr,
|
||||
const ESPEASY_RULES_FLOAT_TYPE& value,
|
||||
Sensor_VType sensorType)
|
||||
{
|
||||
if ((taskIndex >= _data.size()) || (varNr >= VARS_PER_TASK)) {
|
||||
return;
|
||||
}
|
||||
String formula = Cache.getTaskDeviceFormula(taskIndex, varNr);
|
||||
|
||||
if (!formula.isEmpty())
|
||||
{
|
||||
START_TIMER;
|
||||
|
||||
// TD-er: Should we use the set nr of decimals here, or not round at all?
|
||||
// See: https://github.com/letscontrolit/ESPEasy/issues/3721#issuecomment-889649437
|
||||
const int nrDecimals = Cache.getTaskDeviceValueDecimals(taskIndex, varNr);
|
||||
|
||||
if (formula.indexOf(F("%pvalue%")) != -1) {
|
||||
formula.replace(F("%pvalue%"), getAsString(taskIndex, varNr, sensorType, nrDecimals));
|
||||
}
|
||||
|
||||
if (formula.indexOf(F("%value%")) != -1)
|
||||
{
|
||||
// Use a temporary TaskValues_Data_t object to have uniform formatting
|
||||
TaskValues_Data_t tmp;
|
||||
tmp.set(varNr, value, sensorType);
|
||||
formula.replace(F("%value%"), tmp.getAsString(varNr, sensorType, nrDecimals));
|
||||
}
|
||||
|
||||
ESPEASY_RULES_FLOAT_TYPE result{};
|
||||
|
||||
if (!isError(Calculate(parseTemplate(formula), result))) {
|
||||
_computed[taskIndex].set(varNr, result, sensorType);
|
||||
} else {
|
||||
// FIXME TD-er: What to do now? Just copy the raw value, set error value or don't update?
|
||||
}
|
||||
|
||||
STOP_TIMER(COMPUTE_FORMULA_STATS);
|
||||
}
|
||||
|
||||
_data[taskIndex].set(varNr, value, sensorType);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ struct UserVarStruct {
|
||||
/*
|
||||
float & operator[](unsigned int index);
|
||||
*/
|
||||
const float & operator[](unsigned int index) const;
|
||||
float operator[](unsigned int index) const;
|
||||
|
||||
// Legacy "long" type, which was spread over several floats.
|
||||
unsigned long getSensorTypeLong(taskIndex_t taskIndex) const;
|
||||
@@ -104,8 +104,17 @@ struct UserVarStruct {
|
||||
|
||||
uint32_t compute_CRC32() const;
|
||||
|
||||
void clear_computed(taskIndex_t taskIndex);
|
||||
|
||||
private:
|
||||
|
||||
const TaskValues_Data_t* getRawOrComputed(taskIndex_t taskIndex, uint8_t varNr) const;
|
||||
|
||||
void applyFormula(taskIndex_t taskIndex,
|
||||
uint8_t varNr,
|
||||
const ESPEASY_RULES_FLOAT_TYPE& value,
|
||||
Sensor_VType sensorType);
|
||||
|
||||
// Raw TaskValues data as stored in RTC
|
||||
std::vector<TaskValues_Data_t>_data;
|
||||
|
||||
|
||||
@@ -634,53 +634,8 @@ void SensorSendTask(struct EventStruct *event, unsigned long timestampUnixTime,
|
||||
TempEvent.timestamp = timestampUnixTime;
|
||||
checkDeviceVTypeForTask(&TempEvent);
|
||||
|
||||
|
||||
const uint8_t valueCount = getValueCountForTask(event->TaskIndex);
|
||||
// Store the previous value, in case %pvalue% is used in the formula
|
||||
String preValue[VARS_PER_TASK];
|
||||
const bool processFormula = Device[DeviceIndex].FormulaOption && Cache.hasFormula(event->TaskIndex);
|
||||
if (processFormula) {
|
||||
for (uint8_t varNr = 0; varNr < valueCount; varNr++)
|
||||
{
|
||||
const String formula = Cache.getTaskDeviceFormula(event->TaskIndex, varNr);
|
||||
if (!formula.isEmpty())
|
||||
{
|
||||
if (formula.indexOf(F("%pvalue%")) != -1) {
|
||||
preValue[varNr] = formatUserVarNoCheck(&TempEvent, varNr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
String dummy;
|
||||
success = PluginCall(PLUGIN_READ, &TempEvent, dummy);
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
if (processFormula) {
|
||||
for (uint8_t varNr = 0; varNr < valueCount; varNr++)
|
||||
{
|
||||
String formula = Cache.getTaskDeviceFormula(event->TaskIndex, varNr);
|
||||
if (!formula.isEmpty())
|
||||
{
|
||||
START_TIMER;
|
||||
|
||||
// TD-er: Should we use the set nr of decimals here, or not round at all?
|
||||
// See: https://github.com/letscontrolit/ESPEasy/issues/3721#issuecomment-889649437
|
||||
formula.replace(F("%pvalue%"), preValue[varNr]);
|
||||
formula.replace(F("%value%"), formatUserVarNoCheck(&TempEvent, varNr));
|
||||
ESPEASY_RULES_FLOAT_TYPE result{};
|
||||
|
||||
if (!isError(Calculate(parseTemplate(formula), result))) {
|
||||
UserVar.set(event->TaskIndex, varNr, result, TempEvent.sensorType);
|
||||
}
|
||||
|
||||
STOP_TIMER(COMPUTE_FORMULA_STATS);
|
||||
}
|
||||
}
|
||||
}
|
||||
String dummy;
|
||||
if (PluginCall(PLUGIN_READ, &TempEvent, dummy)) {
|
||||
sendData(&TempEvent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -896,6 +896,7 @@ bool PluginCall(uint8_t Function, struct EventStruct *event, String& str)
|
||||
// Each of these may update ExtraTaskSettings, but it may not have been saved yet.
|
||||
// Thus update the cache just in case something from it is requested from the cache.
|
||||
Cache.updateExtraTaskSettingsCache();
|
||||
UserVar.clear_computed(event->TaskIndex);
|
||||
}
|
||||
if (Function == PLUGIN_SET_DEFAULTS) {
|
||||
saveUserVarToRTC();
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "../Globals/Plugins.h"
|
||||
#include "../Globals/RTC.h"
|
||||
#include "../Globals/ResetFactoryDefaultPref.h"
|
||||
#include "../Globals/RuntimeData.h"
|
||||
#include "../Globals/SecuritySettings.h"
|
||||
#include "../Globals/Settings.h"
|
||||
#include "../Globals/WiFi_AP_Candidates.h"
|
||||
@@ -1093,6 +1094,7 @@ String SaveTaskSettings(taskIndex_t TaskIndex)
|
||||
err = checkTaskSettings(TaskIndex);
|
||||
}
|
||||
#endif
|
||||
UserVar.clear_computed(ExtraTaskSettings.TaskIndex);
|
||||
}
|
||||
#ifndef LIMIT_BUILD_SIZE
|
||||
else {
|
||||
@@ -1152,6 +1154,7 @@ String LoadTaskSettings(taskIndex_t TaskIndex)
|
||||
|
||||
ExtraTaskSettings.validate();
|
||||
Cache.updateExtraTaskSettingsCache_afterLoad_Save();
|
||||
UserVar.clear_computed(ExtraTaskSettings.TaskIndex);
|
||||
STOP_TIMER(LOAD_TASK_SETTINGS);
|
||||
|
||||
return result;
|
||||
|
||||
@@ -293,7 +293,7 @@ void P109_data_struct::saveThermoSettings(struct EventStruct *event) {
|
||||
fs::File f = tryOpenFile(fileName, F("w"));
|
||||
|
||||
if (f) {
|
||||
f.write(reinterpret_cast<const uint8_t *>(&UserVar[event->BaseVarIndex]), 16);
|
||||
f.write(reinterpret_cast<const uint8_t *>(UserVar.getTaskValues_Data(event->TaskIndex)), 16);
|
||||
f.close();
|
||||
flashCount();
|
||||
}
|
||||
|
||||
@@ -169,6 +169,7 @@ void handle_devices() {
|
||||
// N.B. When calling delete, the settings were already saved.
|
||||
if (nosave) {
|
||||
Cache.updateExtraTaskSettingsCache();
|
||||
UserVar.clear_computed(taskIndex);
|
||||
} else {
|
||||
addHtmlError(SaveTaskSettings(taskIndex));
|
||||
addHtmlError(SaveSettings());
|
||||
@@ -457,6 +458,7 @@ void handle_devices_CopySubmittedSettings(taskIndex_t taskIndex, pluginID_t task
|
||||
CPluginCall(ProtocolIndex, CPlugin::Function::CPLUGIN_TASK_CHANGE_NOTIFICATION, &TempEvent, dummy);
|
||||
}
|
||||
}
|
||||
UserVar.clear_computed(taskIndex);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user