Merge pull request #5178 from tonhuisman/feature/Improvements-and-fixes-dec-2024

Improvements and fixes Dec. 2024
This commit is contained in:
TD-er
2024-12-21 12:28:58 +01:00
committed by GitHub
10 changed files with 146 additions and 127 deletions
+1 -2
View File
@@ -88,8 +88,6 @@ bool CPlugin_005(CPlugin::Function function, struct EventStruct *event, String&
const bool contains_valname = pubname.indexOf(F("%valname%")) != -1;
bool mqtt_retainFlag = CPlugin_005_mqtt_retainFlag;
parseControllerVariables(pubname, event, false);
uint8_t valueCount = getValueCountForTask(event->TaskIndex);
for (uint8_t x = 0; x < valueCount; x++)
@@ -104,6 +102,7 @@ bool CPlugin_005(CPlugin::Function function, struct EventStruct *event, String&
if (contains_valname) {
parseSingleControllerVariable(tmppubname, event, x, false);
}
parseControllerVariables(tmppubname, event, false);
String value;
if (event->sensorType == Sensor_VType::SENSOR_TYPE_STRING) {
+1 -1
View File
@@ -121,7 +121,6 @@ bool CPlugin_006(CPlugin::Function function, struct EventStruct *event, String&
statusLED(true);
//LoadTaskSettings(event->TaskIndex); // FIXME TD-er: This can probably be removed
parseControllerVariables(pubname, event, false);
const uint8_t valueCount = getValueCountForTask(event->TaskIndex);
@@ -131,6 +130,7 @@ bool CPlugin_006(CPlugin::Function function, struct EventStruct *event, String&
if (contains_valname) {
parseSingleControllerVariable(tmppubname, event, x, false);
}
parseControllerVariables(tmppubname, event, false);
// Small optimization so we don't try to copy potentially large strings
if (event->sensorType == Sensor_VType::SENSOR_TYPE_STRING) {
+1 -1
View File
@@ -90,7 +90,6 @@ bool CPlugin_008(CPlugin::Function function, struct EventStruct *event, String&
// Collect the values at the same run, to make sure all are from the same sample
//LoadTaskSettings(event->TaskIndex); // FIXME TD-er: This can probably be removed
parseControllerVariables(pubname, event, true);
for (uint8_t x = 0; x < valueCount; x++)
{
@@ -105,6 +104,7 @@ bool CPlugin_008(CPlugin::Function function, struct EventStruct *event, String&
if (contains_valname) {
parseSingleControllerVariable(txt, event, x, true);
}
parseControllerVariables(txt, event, true);
# ifndef BUILD_NO_DEBUG
if (loglevelActiveFor(LOG_LEVEL_DEBUG)) {
+1 -1
View File
@@ -83,7 +83,6 @@ bool CPlugin_010(CPlugin::Function function, struct EventStruct *event, String&
LoadControllerSettings(event->ControllerIndex, *ControllerSettings);
pubname = ControllerSettings->Publish;
}
parseControllerVariables(pubname, event, false);
const bool contains_valname = pubname.indexOf(F("%valname%")) != -1;
for (uint8_t x = 0; x < valueCount; x++)
@@ -97,6 +96,7 @@ bool CPlugin_010(CPlugin::Function function, struct EventStruct *event, String&
if (contains_valname) {
parseSingleControllerVariable(txt, event, x, false);
}
parseControllerVariables(txt, event, false);
txt.replace(F("%value%"), formattedValue);
move_special(element->txt[x], std::move(txt));
#ifndef BUILD_NO_DEBUG
+1 -1
View File
@@ -886,7 +886,6 @@ bool CPlugin_014(CPlugin::Function function, struct EventStruct *event, String&
statusLED(true);
parseControllerVariables(pubname, event, false);
LoadTaskSettings(event->TaskIndex);
uint8_t valueCount = getValueCountForTask(event->TaskIndex);
@@ -898,6 +897,7 @@ bool CPlugin_014(CPlugin::Function function, struct EventStruct *event, String&
if (contains_valname) {
parseSingleControllerVariable(tmppubname, event, x, false);
}
parseControllerVariables(tmppubname, event, false);
// Small optimization so we don't try to copy potentially large strings
if (event->getSensorType() == Sensor_VType::SENSOR_TYPE_STRING) {
+26 -120
View File
@@ -9,6 +9,9 @@
// Extended by timer based state control to support pumps with additional requirements (floor heating ciculation pump)
// Changelog:
// 2024-12-14, tonhuisman: Move most defines to .h file to avoid compiler warnings, as Arduino doesn't support #ifdef in .ino files
// Format source using Uncrustify
// Remove unneeded includes
// 2024-07-07, flashmark: Reworked to support floor heating pump (added state machine control)
// 2023-03-13, tonhuisman: Add setting to invert the Output state
// 2022-08-22, tonhuisman: Add setting to auto-save a changed setting after x minutes, size optimizations, add PCONFIG defines
@@ -29,28 +32,9 @@
// Minimum build size is expected to be true when extras >=1
//////////////////////////////////////////////////////////////////////////////////////////////////////////
# include "src/Helpers/ESPEasy_math.h"
# include "src/Globals/RulesCalculate.h"
# include "src/WebServer/ESPEasy_WebServer.h"
//// #define LIMIT_BUILD_SIZE
# define PLUGIN_021_DEBUG
// For additional debugging information use PLUGIN_021_DEBUG (see note)
# ifdef BUILD_NO_DEBUG
# undef PLUGIN_021_DEBUG
# else // ifdef BUILD_NO_DEBUG
////# define PLUGIN_021_DEBUG
# endif // ifndef/else BUILD_NO_DEBUG
// See note at top of file
# ifdef LIMIT_BUILD_SIZE
# define FEATURE_P021_EXTRAS 0
# define P021_MIN_BUILD_SIZE
# undef PLUGIN_021_DEBUG
# else // ifdef LIMIT_BUILD_SIZE
# define FEATURE_P021_EXTRAS 1
# endif // ifdef LIMIT_BUILD_SIZE
# include "src/PluginStructs/P021_data_struct.h"
# define PLUGIN_021
# define PLUGIN_ID_021 21
@@ -58,86 +42,6 @@
# define PLUGIN_VALUENAME1_021 "Output"
# define PLUGIN_VALUENAME2_021 "State"
# define P021_GPIO_RELAY CONFIG_PIN1
// Define the configuration options using ESPeasy standard structures
// For unique identification on the HTML form use P021_GUID_<option>
// ------------------------------------------------------------------
// Input signal is read from another task (plugin) by accessing its TASK & VALUE
# define P021_CHECK_TASK PCONFIG(0)
# define P021_GUID_CHECK_TASK "f0"
# define P021_CHECK_VALUE PCONFIG(1)
# define P021_GUID_CHECK_VALUE "f1"
// Flag to prevent excessive writing. Backwards compatible with previous version
# define P021_DONT_ALWAYS_SAVE PCONFIG(2)
# define P021_GUID_DONT_ALWAYS_SAVE "f2"
// Set of individual bits packed in a single PCONFIG(3)
// Use bitRead() and bitWrite() to access the individual bits
// For backwards compatibility first bit shall be equal original P021_INVERT_OUTPUT
# define P021_FLAGS PCONFIG(3)
# define P021_INV_OUTPUT 0 // Invert output signal
# define P021_GUID_INV_OUTPUT "b0"
# define P021_EXT_FUNCT 1 // Extended functionality on setup screen
# define P021_GUID_EXT_FUNCT "b1"
# define P021_INV_INPUT 2 // Invert input comparator
# define P021_GUID_INV_INPUT "b2"
# define P021_SYM_HYSTERESIS 3 // Use symetrical hysteresis
# define P021_GUID_SYM_HYSTERESIS "b3"
# define P021_SLOW_EVAL 4 // 1Hz evaluation i.s.o. 10Hz
# define P021_GUID_SLOW_EVAL "b4"
# define P021_STATE_OUTP 5 // Add state as additional output value
# define P021_GUID_STATE_OUTP "b5"
# define P021_EXTEND_END 6 // Extend state timed from start
# define P021_GUID_EXTEND_END "b6"
# define P021_LONG_TIMER_UNIT 7 // Use longer timer units on setup screen
# define P021_GUID_LONG_TIMER_UNIT "b7"
// Operation mode [enum]
# define P021_OPMODE PCONFIG(4)
# define P021_GUID_OPMODE "f4"
// Setpoint (set level)
# define P021_SETPOINT PCONFIG_FLOAT(0)
# define P021_GUID_SETPOINT "f5"
// Hysteresis
# define P021_HYSTERESIS PCONFIG_FLOAT(1)
# define P021_GUID_HYSTERESIS "f6"
// SETP_LAST_STORED is not available on form. Used as storage for autosave function
# define P021_SETP_LAST_STORED PCONFIG_FLOAT(2)
# define P021_GUID_SETP_LAST_STORED "f7"
// Auto save time interval to update remotely changed setpoints to flash
# define P021_AUTOSAVE_TIMER PCONFIG_ULONG(0)
# define P021_GUID_AUTOSAVE_TIMER "f8"
// Minimum time output shall be active [sec]/[min]
# define P021_MIN_TIME PCONFIG_ULONG(1)
# define P021_GUID_MIN_TIME "f9"
// Maximum time output may be idle [sec]/[hour]
# define P021_INTERVAL_TIME PCONFIG_ULONG(2)
# define P021_GUID_INTERVAL_TIME "f10"
// Duration for forced circulation [sec]/[min]
# define P021_FORCE_TIME PCONFIG_ULONG(3)
# define P021_GUID_FORCE_TIME "f11"
// Positions in userVar array for the output values of this plugin
// For now we only advertise output & state. Autosave bookkeeping is hidden and used as static storage
#define P021_VALUE_OUTPUT 0 // Switch output, logical state [inactive/active]
#define P021_VALUE_STATE 1 // Control state, see P021_control_state
#define P021_VALUE_AUTOSAVE_FLAG 2 // Autosave bookkeeping
#define P021_VALUE_AUTOSAVE_TIME 3 // Autosave bookkeeping
// Simple conversion from parameter settings in hours/minutes to seconds (administration unit)
// And from seconds to the millis domain used for the actual control
// Note that these simple conversion may lose precision due to rough rounding
# if FEATURE_P021_EXTRAS >= 1
int millis2seconds(int32_t x) {
return (uint)(x / 1000);
@@ -322,11 +226,11 @@ boolean Plugin_021(uint8_t function, struct EventStruct *event, String& string)
if (extFunc)
{
# ifndef P021_MIN_BUILD_SIZE
# ifndef P021_MIN_BUILD_SIZE
// Selection of timer units. Will reload the page.
addFormSelector_YesNo(F("Long time span"), F(P021_GUID_LONG_TIMER_UNIT), bitRead(flags, P021_LONG_TIMER_UNIT), true);
# endif // ifndef P021_MIN_BUILD_SIZE
# endif // ifndef P021_MIN_BUILD_SIZE
// FormSelector with all operation mode options
const __FlashStringHelper *options[] = { F("Classic"), F("Off"), F("Standby"), F("On"), F("Local"), F("Remote") };
@@ -337,7 +241,7 @@ boolean Plugin_021(uint8_t function, struct EventStruct *event, String& string)
// Add timer values depending on build size
// - minimum build size: units are always in seconds; drop the units on the form
// - standard build size: units are either seconds or minutes/hours
# ifdef P021_MIN_BUILD_SIZE
# ifdef P021_MIN_BUILD_SIZE
// Minimum on time
addFormNumericBox(F("Minimum running time"), F(P021_GUID_MIN_TIME), P021_MIN_TIME, 0);
@@ -348,7 +252,7 @@ boolean Plugin_021(uint8_t function, struct EventStruct *event, String& string)
// Interval circulation time (forced circulation)
addFormNumericBox(F("Forced circulation time"), F(P021_GUID_FORCE_TIME), P021_FORCE_TIME, 1);
# else // ifdef P021_MIN_BUILD_SIZE
# else // ifdef P021_MIN_BUILD_SIZE
uint32_t min_time = P021_MIN_TIME; // Value to display for minimum timer
uint32_t interval_time = P021_INTERVAL_TIME; // Value to display for max idling time
uint32_t force_time = P021_FORCE_TIME; // Value for forces run
@@ -376,7 +280,7 @@ boolean Plugin_021(uint8_t function, struct EventStruct *event, String& string)
// Interval circulation time (forced circulation)
addFormNumericBox(F("Forced circulation time"), F(P021_GUID_FORCE_TIME), force_time, 1);
addUnit(unit1);
#endif // ifdef P021_MIN_BUILD_SIZE - else
# endif // ifdef P021_MIN_BUILD_SIZE - else
// Symetrical/asymetrical hysteresis [checkbox]
@@ -394,7 +298,7 @@ boolean Plugin_021(uint8_t function, struct EventStruct *event, String& string)
// Provide the controller state as second sensor output value [checkbox]
addFormCheckBox(F("State as output value"), F(P021_GUID_STATE_OUTP), bitRead(flags, P021_STATE_OUTP));
}
#endif // FEATURE_P021_EXTRAS >= 1
# endif // FEATURE_P021_EXTRAS >= 1
success = true;
break;
@@ -420,7 +324,7 @@ boolean Plugin_021(uint8_t function, struct EventStruct *event, String& string)
if (newExtFunct && (bitRead(flags, P021_EXT_FUNCT)))
{
P021_OPMODE = getFormItemInt(F(P021_GUID_OPMODE));
# ifndef P021_MIN_BUILD_SIZE
# ifndef P021_MIN_BUILD_SIZE
const bool new_units = getFormItemInt(F(P021_GUID_LONG_TIMER_UNIT)) != 0;
const bool old_units = bitRead(flags, P021_LONG_TIMER_UNIT) != 0;
@@ -441,11 +345,11 @@ boolean Plugin_021(uint8_t function, struct EventStruct *event, String& string)
}
}
bitWrite(flags, P021_LONG_TIMER_UNIT, new_units);
# else // ifndef P021_MIN_BUILD_SIZE
# else // ifndef P021_MIN_BUILD_SIZE
P021_MIN_TIME = getFormItemInt(F(P021_GUID_MIN_TIME));
P021_INTERVAL_TIME = getFormItemInt(F(P021_GUID_INTERVAL_TIME));
P021_FORCE_TIME = getFormItemInt(F(P021_GUID_FORCE_TIME));
# endif // ifndef P021_MIN_BUILD_SIZE
# endif // ifndef P021_MIN_BUILD_SIZE
bitWrite(flags, P021_INV_INPUT, isFormItemChecked(F(P021_GUID_INV_INPUT)));
bitWrite(flags, P021_EXTEND_END, isFormItemChecked(F(P021_GUID_EXTEND_END)));
@@ -466,7 +370,7 @@ boolean Plugin_021(uint8_t function, struct EventStruct *event, String& string)
}
bitWrite(flags, P021_EXT_FUNCT, newExtFunct);
#endif //if FEATURE_P021_EXTRAS >= 1
# endif // if FEATURE_P021_EXTRAS >= 1
P021_FLAGS = flags; // Don't forget to write back the new flags
success = true;
@@ -487,7 +391,7 @@ boolean Plugin_021(uint8_t function, struct EventStruct *event, String& string)
if (isRemote) {
P021_remote[event->TaskIndex] = !essentiallyZero(result);
}
#endif // ifndef P021_MIN_BUILD_SIZE
# endif // ifndef P021_MIN_BUILD_SIZE
if (isSetLevel || isHysteresis) {
if (!isError(Calculate(value, result))) {
@@ -588,17 +492,17 @@ boolean Plugin_021(uint8_t function, struct EventStruct *event, String& string)
if (event->Par2 == 1)
{
P021_remote[event->TaskIndex] = true;
# ifndef P021_MIN_BUILD_SIZE
# ifndef P021_MIN_BUILD_SIZE
addLogMove(LOG_LEVEL_INFO, F("P021 write: levelcontrol remote=on"));
# endif // ifndef P021_MIN_BUILD_SIZE
# endif // ifndef P021_MIN_BUILD_SIZE
success = true;
}
else if (event->Par2 == 0)
{
P021_remote[event->TaskIndex] = false;
# ifndef P021_MIN_BUILD_SIZE
# ifndef P021_MIN_BUILD_SIZE
addLogMove(LOG_LEVEL_INFO, F("P021 write: levelcontrol remote=off"));
# endif // ifndef P021_MIN_BUILD_SIZE
# endif // ifndef P021_MIN_BUILD_SIZE
success = true;
}
}
@@ -787,6 +691,7 @@ void P021_evaluate(struct EventStruct *event)
new_control_state = P021_STATE_FORCE;
}
}
// Note any other state implies the output is active
else if (!beyond_force)
{
@@ -912,7 +817,7 @@ void P021_evaluate(struct EventStruct *event)
digitalWrite(P021_GPIO_RELAY, relay_output ? HIGH : LOW);
}
# ifdef PLUGIN_021_DEBUG
# ifdef PLUGIN_021_DEBUG
if (loglevelActiveFor(LOG_LEVEL_DEBUG))
{
@@ -925,7 +830,7 @@ void P021_evaluate(struct EventStruct *event)
value,
remote_state));
}
# endif // ifdef PLUGIN_021_DEBUG
# endif // ifdef PLUGIN_021_DEBUG
// Write back updated persistant control data:
// - The logical state of the output signal [on,OFF]
@@ -996,12 +901,13 @@ void P021_evaluate(struct EventStruct *event)
// Actuate the output pin taking output invert flag into account
relay_output ^= bitRead(P021_FLAGS, P021_INV_OUTPUT); // Invert when selected
if (validGpio(P021_GPIO_RELAY))
{
digitalWrite(P021_GPIO_RELAY, relay_output ? HIGH : LOW);
}
# ifdef PLUGIN_021_DEBUG
# ifdef PLUGIN_021_DEBUG
if (loglevelActiveFor(LOG_LEVEL_DEBUG))
{
@@ -1011,12 +917,12 @@ void P021_evaluate(struct EventStruct *event)
relay_output,
value));
}
# endif // ifdef PLUGIN_021_DEBUG
# endif // ifdef PLUGIN_021_DEBUG
// Write back updated persistant control data:
// - The physical state of the output signal [on,OFF]
// - The state of the internal state machine
UserVar.setFloat(event->TaskIndex, P021_VALUE_OUTPUT, relay_output ? 1.0f : 0.0f );
UserVar.setFloat(event->TaskIndex, P021_VALUE_OUTPUT, relay_output ? 1.0f : 0.0f);
UserVar.setFloat(event->TaskIndex, P021_VALUE_STATE, (float)new_control_state);
if (new_control_state != old_control_state)
+9
View File
@@ -8,6 +8,11 @@
// ESPEasy Plugin to control a 16x8 LED matrix or 8 7-segment displays with chip HT16K33
// written by Jochen Krapf (jk@nerd2nerd.org)
/** Changelog:
* 2024-12-14 tonhuisman: Fix mprint command to skip the colon segment when printing a non-colon character in that position.
* 2024-12 tonhuisman: Start changelog.
*/
// List of commands:
// (1) M,<param>,<param>,<param>, ... with decimal values
// (2) MX,<param>,<param>,<param>, ... with hexadecimal values
@@ -194,6 +199,10 @@ boolean Plugin_057(uint8_t function, struct EventStruct *event, String& string)
{
setDot = (txt < text.length() - 1 && text[txt + 1] == '.');
char c = text[txt];
if ((':' != c) && (PCONFIG(6) > -1) && (seg == PCONFIG(6))) { // skip the colon segment when not putting a colon there
seg++;
}
P057_data->ledMatrix.SetDigit(seg, c, setDot);
seg++;
txt++;
@@ -61,6 +61,9 @@ void ResetFactory(bool formatFS)
mustApplySafebootDefaults = true;
}
#endif // ifdef ESP32
#ifdef ESP8266 // Apply defaults on clean setup
mustApplySafebootDefaults = 0 == Settings.ResetFactoryDefaultPreference;
#endif // ifdef ESP8266
if (ResetFactoryDefaultPreference.getPreference() == 0)
{
+1 -1
View File
@@ -1311,8 +1311,8 @@ void parseSpecialCharacters(String& s, bool useURLencode)
replace other system variables like %sysname%, %systime%, %ip%
\*********************************************************************************************/
void parseControllerVariables(String& s, struct EventStruct *event, bool useURLencode) {
s = parseTemplate(s, useURLencode);
parseEventVariables(s, event, useURLencode);
s = parseTemplate(s, useURLencode);
}
// FIXME TD-er: These macros really increase build size.
+102
View File
@@ -0,0 +1,102 @@
#ifndef PLUGINSTRUCTS_P021_DATA_STRUCT_H
#define PLUGINSTRUCTS_P021_DATA_STRUCT_H
// Moved here from _P021_Level.ino as the Arduino compiler doesn't (properly) support #ifdef in .ino files
#define PLUGIN_021_DEBUG
// For additional debugging information use PLUGIN_021_DEBUG (see note)
#ifdef BUILD_NO_DEBUG
# undef PLUGIN_021_DEBUG
#endif // ifndef/else BUILD_NO_DEBUG
// See note at top of file
#ifdef LIMIT_BUILD_SIZE
# define FEATURE_P021_EXTRAS 0
# define P021_MIN_BUILD_SIZE
# undef PLUGIN_021_DEBUG
#else // ifdef LIMIT_BUILD_SIZE
# define FEATURE_P021_EXTRAS 1
#endif // ifdef LIMIT_BUILD_SIZE
# define P021_GPIO_RELAY CONFIG_PIN1
// Define the configuration options using ESPeasy standard structures
// For unique identification on the HTML form use P021_GUID_<option>
// ------------------------------------------------------------------
// Input signal is read from another task (plugin) by accessing its TASK & VALUE
# define P021_CHECK_TASK PCONFIG(0)
# define P021_GUID_CHECK_TASK "f0"
# define P021_CHECK_VALUE PCONFIG(1)
# define P021_GUID_CHECK_VALUE "f1"
// Flag to prevent excessive writing. Backwards compatible with previous version
# define P021_DONT_ALWAYS_SAVE PCONFIG(2)
# define P021_GUID_DONT_ALWAYS_SAVE "f2"
// Set of individual bits packed in a single PCONFIG(3)
// Use bitRead() and bitWrite() to access the individual bits
// For backwards compatibility first bit shall be equal original P021_INVERT_OUTPUT
# define P021_FLAGS PCONFIG(3)
# define P021_INV_OUTPUT 0 // Invert output signal
# define P021_GUID_INV_OUTPUT "b0"
# define P021_EXT_FUNCT 1 // Extended functionality on setup screen
# define P021_GUID_EXT_FUNCT "b1"
# define P021_INV_INPUT 2 // Invert input comparator
# define P021_GUID_INV_INPUT "b2"
# define P021_SYM_HYSTERESIS 3 // Use symetrical hysteresis
# define P021_GUID_SYM_HYSTERESIS "b3"
# define P021_SLOW_EVAL 4 // 1Hz evaluation i.s.o. 10Hz
# define P021_GUID_SLOW_EVAL "b4"
# define P021_STATE_OUTP 5 // Add state as additional output value
# define P021_GUID_STATE_OUTP "b5"
# define P021_EXTEND_END 6 // Extend state timed from start
# define P021_GUID_EXTEND_END "b6"
# define P021_LONG_TIMER_UNIT 7 // Use longer timer units on setup screen
# define P021_GUID_LONG_TIMER_UNIT "b7"
// Operation mode [enum]
# define P021_OPMODE PCONFIG(4)
# define P021_GUID_OPMODE "f4"
// Setpoint (set level)
# define P021_SETPOINT PCONFIG_FLOAT(0)
# define P021_GUID_SETPOINT "f5"
// Hysteresis
# define P021_HYSTERESIS PCONFIG_FLOAT(1)
# define P021_GUID_HYSTERESIS "f6"
// SETP_LAST_STORED is not available on form. Used as storage for autosave function
# define P021_SETP_LAST_STORED PCONFIG_FLOAT(2)
# define P021_GUID_SETP_LAST_STORED "f7"
// Auto save time interval to update remotely changed setpoints to flash
# define P021_AUTOSAVE_TIMER PCONFIG_ULONG(0)
# define P021_GUID_AUTOSAVE_TIMER "f8"
// Minimum time output shall be active [sec]/[min]
# define P021_MIN_TIME PCONFIG_ULONG(1)
# define P021_GUID_MIN_TIME "f9"
// Maximum time output may be idle [sec]/[hour]
# define P021_INTERVAL_TIME PCONFIG_ULONG(2)
# define P021_GUID_INTERVAL_TIME "f10"
// Duration for forced circulation [sec]/[min]
# define P021_FORCE_TIME PCONFIG_ULONG(3)
# define P021_GUID_FORCE_TIME "f11"
// Positions in userVar array for the output values of this plugin
// For now we only advertise output & state. Autosave bookkeeping is hidden and used as static storage
# define P021_VALUE_OUTPUT 0 // Switch output, logical state [inactive/active]
# define P021_VALUE_STATE 1 // Control state, see P021_control_state
# define P021_VALUE_AUTOSAVE_FLAG 2 // Autosave bookkeeping
# define P021_VALUE_AUTOSAVE_TIME 3 // Autosave bookkeeping
// Simple conversion from parameter settings in hours/minutes to seconds (administration unit)
// And from seconds to the millis domain used for the actual control
// Note that these simple conversion may lose precision due to rough rounding
#endif // ifndef PLUGINSTRUCTS_P021_DATA_STRUCT_H