mirror of
https://github.com/letscontrolit/ESPEasy.git
synced 2026-07-27 19:57:38 +00:00
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:
@@ -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(
|
||||
|
||||
@@ -357,7 +357,7 @@ void Caches::updateExtraTaskSettingsCache()
|
||||
}
|
||||
#endif // ifdef ESP32
|
||||
|
||||
extraTaskSettings_cache[TaskIndex] = tmp;
|
||||
extraTaskSettings_cache.emplace(std::make_pair(TaskIndex, std::move(tmp)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -29,7 +29,7 @@ struct TaskValues_Data_cache {
|
||||
}
|
||||
|
||||
TaskValues_Data_t values{};
|
||||
uint8_t values_set_map{};
|
||||
uint32_t values_set_map{};
|
||||
};
|
||||
|
||||
struct UserVarStruct {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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())
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user