Merge pull request #5014 from TD-er/bugfix/MQTT_formula_crash

[MQTT] Fix crash and disconnect sending to MQTT using formula
This commit is contained in:
TD-er
2024-03-29 17:23:12 +01:00
committed by GitHub
11 changed files with 82 additions and 40 deletions
+7 -7
View File
@@ -132,10 +132,10 @@ boolean Plugin_001(uint8_t function, struct EventStruct *event, String& string)
}
{
const __FlashStringHelper *options[2] = { F("Switch"), F("Dimmer") };
int optionValues[2] = { PLUGIN_001_TYPE_SWITCH, PLUGIN_001_TYPE_DIMMER };
const uint8_t switchtype = P001_getSwitchType(event);
addFormSelector(F("Switch Type"), F("type"), 2, options, optionValues, switchtype);
const __FlashStringHelper *options[] = { F("Switch"), F("Dimmer") };
int optionValues[] = { PLUGIN_001_TYPE_SWITCH, PLUGIN_001_TYPE_DIMMER };
const uint8_t switchtype = P001_getSwitchType(event);
addFormSelector(F("Switch Type"), F("type"), NR_ELEMENTS(optionValues), options, optionValues, switchtype);
if (switchtype == PLUGIN_001_TYPE_DIMMER)
{
@@ -145,10 +145,10 @@ boolean Plugin_001(uint8_t function, struct EventStruct *event, String& string)
{
uint8_t choice = PCONFIG(2);
const __FlashStringHelper *buttonOptions[3] = { F("Normal Switch"), F("Push Button Active Low"), F("Push Button Active High") };
int buttonOptionValues[3] =
const __FlashStringHelper *buttonOptions[] = { F("Normal Switch"), F("Push Button Active Low"), F("Push Button Active High") };
int buttonOptionValues[] =
{ PLUGIN_001_BUTTON_TYPE_NORMAL_SWITCH, PLUGIN_001_BUTTON_TYPE_PUSH_ACTIVE_LOW, PLUGIN_001_BUTTON_TYPE_PUSH_ACTIVE_HIGH };
addFormSelector(F("Switch Button Type"), F("button"), 3, buttonOptions, buttonOptionValues, choice);
addFormSelector(F("Switch Button Type"), F("button"), NR_ELEMENTS(buttonOptionValues), buttonOptions, buttonOptionValues, choice);
}
SwitchWebformLoad(
+1 -1
View File
@@ -357,7 +357,7 @@ void Caches::updateExtraTaskSettingsCache()
}
#endif // ifdef ESP32
extraTaskSettings_cache[TaskIndex] = tmp;
extraTaskSettings_cache.emplace(std::make_pair(TaskIndex, std::move(tmp)));
}
}
+36 -15
View File
@@ -329,24 +329,31 @@ uint32_t UserVarStruct::compute_CRC32() const
void UserVarStruct::clear_computed(taskIndex_t taskIndex)
{
if (!Cache.hasFormula(taskIndex)) {
auto it = _computed.find(taskIndex);
auto it = _computed.find(taskIndex);
if (it != _computed.end()) {
_computed.erase(it);
}
if (it != _computed.end()) {
_computed.erase(it);
}
#ifndef LIMIT_BUILD_SIZE
for (taskVarIndex_t varNr = 0; validTaskVarIndex(varNr); ++varNr) {
const uint16_t key = makeWord(taskIndex, varNr);
auto it = _preprocessedFormula.find(key);
#ifndef LIMIT_BUILD_SIZE
{
auto it = _preprocessedFormula.find(key);
if (it != _preprocessedFormula.end()) {
_preprocessedFormula.erase(it);
if (it != _preprocessedFormula.end()) {
_preprocessedFormula.erase(it);
}
}
#endif // ifndef LIMIT_BUILD_SIZE
{
auto it = _prevValue.find(key);
if (it != _prevValue.end()) {
_prevValue.erase(it);
}
}
}
#endif // ifndef LIMIT_BUILD_SIZE
}
void UserVarStruct::markPluginRead(taskIndex_t taskIndex)
@@ -403,7 +410,9 @@ bool UserVarStruct::applyFormula(taskIndex_t taskIndex,
return false;
}
if (!applyNow && !Cache.hasFormula_with_prevValue(taskIndex, varNr)) {
const bool formula_has_prevvalue = Cache.hasFormula_with_prevValue(taskIndex, varNr);
if (!applyNow && !formula_has_prevvalue) {
// Must check whether we can delay calculations until it is read for the first time.
auto it = _computed.find(taskIndex);
@@ -422,15 +431,23 @@ bool UserVarStruct::applyFormula(taskIndex_t taskIndex,
{
START_TIMER;
formula.replace(F("%value%"), value);
// 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
if (formula.indexOf(F("%pvalue%")) != -1) {
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(),
value.c_str(),
formula.c_str()));
*/
}
formula.replace(F("%value%"), value);
ESPEASY_RULES_FLOAT_TYPE result{};
if (!isError(Calculate_preProcessed(parseTemplate(formula), result))) {
@@ -482,7 +499,11 @@ String UserVarStruct::getPreprocessedFormula(taskIndex_t taskIndex, taskVarIndex
auto it = _preprocessedFormula.find(key);
if (it == _preprocessedFormula.end()) {
_preprocessedFormula[key] = RulesCalculate_t::preProces(Cache.getTaskDeviceFormula(taskIndex, varNr));
_preprocessedFormula.emplace(
std::make_pair(
key,
RulesCalculate_t::preProces(Cache.getTaskDeviceFormula(taskIndex, varNr))
));
}
return _preprocessedFormula[key];
#else // ifndef LIMIT_BUILD_SIZE
+1 -1
View File
@@ -29,7 +29,7 @@ struct TaskValues_Data_cache {
}
TaskValues_Data_t values{};
uint8_t values_set_map{};
uint32_t values_set_map{};
};
struct UserVarStruct {
+6 -1
View File
@@ -283,6 +283,7 @@ bool PluginCallForTask(taskIndex_t taskIndex, uint8_t Function, EventStruct *Tem
if (Settings.TaskDeviceDataFeed[taskIndex] == 0) // these calls only to tasks with local feed
{
if (Function == PLUGIN_INIT) {
UserVar.clear_computed(taskIndex);
LoadTaskSettings(taskIndex);
}
TempEvent->setTaskIndex(taskIndex);
@@ -602,6 +603,7 @@ bool PluginCall(uint8_t Function, struct EventStruct *event, String& str)
bool retval = PluginCallForTask(taskIndex, Function, &TempEvent, str, event);
if (Function == PLUGIN_INIT) {
UserVar.clear_computed(taskIndex);
if (!retval && Settings.TaskDeviceDataFeed[taskIndex] == 0) {
// Disable temporarily as PLUGIN_INIT failed
// FIXME TD-er: Should reschedule call to PLUGIN_INIT????
@@ -690,6 +692,9 @@ bool PluginCall(uint8_t Function, struct EventStruct *event, String& str)
if (!Settings.TaskDeviceEnabled[event->TaskIndex]) {
return false;
}
if (Function == PLUGIN_INIT) {
UserVar.clear_computed(event->TaskIndex);
}
}
const deviceIndex_t DeviceIndex = getDeviceIndex_from_TaskIndex(event->TaskIndex);
@@ -818,6 +823,7 @@ bool PluginCall(uint8_t Function, struct EventStruct *event, String& str)
}
}
if (Function == PLUGIN_EXIT) {
UserVar.clear_computed(event->TaskIndex);
clearPluginTaskData(event->TaskIndex);
// initSerial();
queueTaskEvent(F("TaskExit"), event->TaskIndex, retval);
@@ -902,7 +908,6 @@ 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();
+9 -5
View File
@@ -117,11 +117,15 @@ void Dallas_addr_selector_webform_load(taskIndex_t TaskIndex, int8_t gpio_pin_rx
uint64_t tmpAddr_64 = Dallas_addr_to_uint64(tmpAddress);
if (tmpAddr_64 != 0) {
addr_task_map[tmpAddr_64] = strformat(
F(" (task %d [%s#%s])")
, task + 1
, getTaskDeviceName(task).c_str()
, getTaskValueName(task, var_index).c_str());
addr_task_map.emplace(
std::make_pair(
tmpAddr_64,
strformat(
F(" (task %d [%s#%s])")
, task + 1
, getTaskDeviceName(task).c_str()
, getTaskValueName(task, var_index).c_str())
));
}
}
}
+5 -2
View File
@@ -152,7 +152,10 @@ bool fileExists(const String& fname) {
if (res || !isCacheFile(patched_fname))
#endif
{
Cache.fileExistsMap[patched_fname] = res;
Cache.fileExistsMap.emplace(
std::make_pair(
patched_fname,
res));
}
if (Cache.fileCacheClearMoment == 0) {
if (node_time.timeSource == timeSource_t::No_time_source) {
@@ -1103,6 +1106,7 @@ String SaveTaskSettings(taskIndex_t TaskIndex)
err = checkTaskSettings(TaskIndex);
}
#endif
// FIXME TD-er: Is this still needed as it is also cleared on PLUGIN_INIT and PLUGIN_EXIT?
UserVar.clear_computed(ExtraTaskSettings.TaskIndex);
}
#ifndef LIMIT_BUILD_SIZE
@@ -1163,7 +1167,6 @@ String LoadTaskSettings(taskIndex_t TaskIndex)
ExtraTaskSettings.validate();
Cache.updateExtraTaskSettingsCache_afterLoad_Save();
UserVar.clear_computed(ExtraTaskSettings.TaskIndex);
STOP_TIMER(LOAD_TASK_SETTINGS);
return result;
+4 -1
View File
@@ -651,10 +651,13 @@ String RulesCalculate_t::preProces(const String& input)
for (size_t i = 0; i < nrOperators; ++i) {
const UnaryOperator op = operators[i];
#if FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES
if (op == UnaryOperator::ArcSin && preprocessed.indexOf(F("sin")) == -1) i += 3;
else if (op == UnaryOperator::ArcCos && preprocessed.indexOf(F("cos")) == -1) i += 3;
else if (op == UnaryOperator::ArcTan && preprocessed.indexOf(F("tan")) == -1) i += 3;
else {
else
#endif
{
preProcessReplace(preprocessed, op);
}
}
+8 -2
View File
@@ -625,7 +625,10 @@ taskIndex_t findTaskIndexByName(String deviceName, bool allowDisabled)
// Use entered taskDeviceName can have any case, so compare case insensitive.
if (deviceName.equalsIgnoreCase(taskDeviceName))
{
Cache.taskIndexName[deviceName] = taskIndex;
Cache.taskIndexName.emplace(
std::make_pair(
std::move(deviceName),
taskIndex));
return taskIndex;
}
}
@@ -668,7 +671,10 @@ uint8_t findDeviceValueIndexByName(const String& valueName, taskIndex_t taskInde
// Check case insensitive, since the user entered value name can have any case.
if (valueName.equalsIgnoreCase(getTaskValueName(taskIndex, valueNr)))
{
Cache.taskIndexValueName[cache_valueName] = valueNr;
Cache.taskIndexValueName.emplace(
std::make_pair(
std::move(cache_valueName),
valueNr));
return valueNr;
}
}
+1 -1
View File
@@ -169,7 +169,6 @@ 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());
@@ -460,6 +459,7 @@ void handle_devices_CopySubmittedSettings(taskIndex_t taskIndex, pluginID_t task
CPluginCall(ProtocolIndex, CPlugin::Function::CPLUGIN_TASK_CHANGE_NOTIFICATION, &TempEvent, dummy);
}
}
// FIXME TD-er: Is this still needed as it is also cleared on PLUGIN_INIT and PLUGIN_EXIT?
UserVar.clear_computed(taskIndex);
}
+4 -4
View File
@@ -480,7 +480,7 @@ void addFormSelectorI2C(const String& id,
#endif // if FEATURE_TOOLTIPS
);
for (uint8_t x = 0; x < addressCount; x++)
for (int x = 0; x < addressCount; x++)
{
String option = formatToHex_decimal(addresses[x]);
@@ -653,9 +653,9 @@ void addFormSelector_YesNo(const __FlashStringHelper * label,
int selectedIndex,
bool reloadonchange)
{
const __FlashStringHelper *optionsNoYes[2] = { F("No"), F("Yes") };
int optionValuesNoYes[2] = { 0, 1 };
addFormSelector(label, id, 2, optionsNoYes, optionValuesNoYes, selectedIndex, reloadonchange);
const __FlashStringHelper *optionsNoYes[] = { F("No"), F("Yes") };
int optionValuesNoYes[] = { 0, 1 };
addFormSelector(label, id, NR_ELEMENTS(optionValuesNoYes), optionsNoYes, optionValuesNoYes, selectedIndex, reloadonchange);
}