mirror of
https://github.com/letscontrolit/ESPEasy.git
synced 2026-09-14 10:35:30 +00:00
[P180] Add exec subcommand, add valuename support, fix issue updating command-cache
This commit is contained in:
@@ -138,7 +138,7 @@ The commands available can either be used with the full command, or the 1 charac
|
||||
* ``read.<format>[.<len>].<reg>``: ``(r)``: Read data in the requested format from a register in the device.
|
||||
* ``write.<format>.<reg>.<data>[.<data>...]``: ``(w)``: Write data to a register in the device in the specified format.
|
||||
* ``eval``: ``(e)``: Evaluate the previous command, and set as selected data for ``calc`` or ``if`` commands.
|
||||
* ``value.<valueIndex>``: ``(v)``: (1..4) Write the last calculated result, or last read value, to the specified Value field.
|
||||
* ``value.<valueIndex>``: ``(v)``: (1..4 or a value name) Store the last calculated result, or last read value, in the specified Value field.
|
||||
* ``calc.<calculation>``: ``(c)``: Calculate a result, like Rules, extra available vars: ``%value%``, ``%pvalue%``, ``%h%``, ``%b0%..%b<n>%``, ``%bx0%..%bx<n>%``, ``%w0%..%w<n>%``, ``%wx0%..%wx<n>%``
|
||||
* ``if.<calculation>``: ``(i)``: Similar to ``calc`` command, when the calculation-result is 0 execution is cancelled
|
||||
* ``delay.<msec>``: ``(d)``: (range: 0..500) Some devices, after starting a read, require some time to process data. This can be handled by a delay. If the delay is < 10 msec, it will be handled immediately, longer delays are processed asynchronous to avoid blocking the ESP for too long.
|
||||
@@ -180,7 +180,7 @@ The plugin should be configured with these settings:
|
||||
|
||||
Once this setting is saved:
|
||||
|
||||
* **Values**: the names can be changed to Temp or Temperature and Hum or Humidity, and the number of decimals adjusted as desired (usually 1 or 2 decimals is fine for both measurements). Stats can be enabled, best would be to set the Axis to L1 for Temperature, and R1 for Humidity, as the scales for these values don't match in range.
|
||||
* **Values**: the names can be changed to Temp or Temperature and Hum or Humidity, and the number of decimals adjusted as desired (usually 1 or 2 decimals is fine for both measurements). Stats can be enabled, best would be to set the Axis to **L1** for Temperature, and **R1** for Humidity, as the scales for these values don't match in range.
|
||||
|
||||
* **Interval**: can be set to 60 seconds to retrieve a measurement every minute.
|
||||
|
||||
@@ -195,9 +195,9 @@ Command sequence explanation:
|
||||
* ``get.b.7``: Read 7 bytes from the sensor
|
||||
* ``eval``: Use the previous command result for evaluation
|
||||
* ``calc.'0x{substring:4:9:%h%}/10485.76'``: Calculate the humidity value from the data provided. `%h%` is the sequence of bytes read (fmt: `b.7`), prefixed with '0x', and only 5 nibbles are used for the humidity value. This is divided by 10485.75 (2^20 / 100) to get the humidity percentage. Quotes are used because of the decimal point used in this calculation, that's also the argument separator here.
|
||||
* ``value.2``: Assign the last result to Value2 field
|
||||
* ``value.2``: Assign the last result to Value2 field (Hum)
|
||||
* ``calc.'0x{substring:9:14:%h%}/5242.88-50'``: Calculate the temperature value from the data provided. Again 5 nibbles are used, to be divided by 2^20 / 200 and 50 subtracted.
|
||||
* ``value.1``: Assign the last result to Value1 field
|
||||
* ``value.1``: Assign the last result to Value1 field (Temp)
|
||||
|
||||
|
|
||||
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
:widths: 20, 30
|
||||
|
||||
"
|
||||
``genI2C,cmd,<i2c-command-sequence>[,<value-index>][,<cache-name>]``
|
||||
``genI2C,cmd,<i2c-command-sequence>[,<value-index>[,<cache-name>]]``
|
||||
|
||||
``i2c-command-sequence``: A sequence of I2C Commands, documented below. When commas, spaces or quotes are used in the sequence, then the command sequence should be wrapped in quotes that are not yet used in the command sequence.
|
||||
|
||||
``value-index``: The Value field to be used for the result of the command sequence.
|
||||
``value-index``: The Value field (by number or name) to be used for the result of the command sequence.
|
||||
|
||||
``cache-name``: The name of the cache entry to overwrite with this command sequence.
|
||||
|
||||
@@ -18,3 +18,12 @@
|
||||
|
||||
The ``cache-name`` argument can be used to replace an existing command sequence in the cache, that will then be used on the next execution (Interval or TaskRun) of the plugin, when this cache-name is also used by one of the value fields. Should normally not be needed, but can be useful when testing or debugging a command sequence for a device.
|
||||
"
|
||||
"
|
||||
``genI2C,exec,<cache-name>[,<value-index>]``
|
||||
|
||||
``cache-name``: The name of the cache entry to retrieve the command sequence from and execute.
|
||||
|
||||
``value-index``: The Value field (by number or name) to be used for the result of the command sequence.
|
||||
","
|
||||
This command is used to execute a cached I2C Command sequence, and optionally store the result in a task value.
|
||||
"
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
// #######################################################################################################
|
||||
|
||||
/** Changelog:
|
||||
* 2025-04-27 tonhuisman: Add support vor executing a command sequence from cache: getI2C,exec,<cache-name>[,<TaskVarIndex>]
|
||||
* Add support for selecting the Value-index either by number or name
|
||||
* 2025-04-21 tonhuisman: Add preliminary support for MQTT Discovery
|
||||
* 2025-04-13 tonhuisman: Add 'if' command, some optimizations
|
||||
* 2025-04-10 tonhuisman: First version made available. Most plugin features implemented, few todos to resolve.
|
||||
@@ -64,7 +66,8 @@
|
||||
*/
|
||||
|
||||
/** Write commands supported:
|
||||
* geni2c,cmd,<I2C-commands>[,<TaskVarIndex>][,<cache-name>]
|
||||
* geni2c,cmd,<I2C-commands>[,<TaskVarIndex>[,<cache-name>]] : Parse command sequence (opt. into cache), execute and store value in TaskVar
|
||||
* getI2C,exec,<cache-name>[,<TaskVarIndex>] : Execute command sequence from cache and store value in TaskVar
|
||||
*/
|
||||
|
||||
# define PLUGIN_180
|
||||
|
||||
@@ -318,9 +318,15 @@ std::vector<P180_Command_struct>P180_data_struct::parseI2CCommands(const String&
|
||||
break;
|
||||
case P180_Command_e::Value: // value - v.<valueIndex>
|
||||
case P180_Command_e::Delay: // delay - d.<ms>
|
||||
{
|
||||
fmt = P180_DataFormat_e::undefined;
|
||||
validInt64FromString(args[arg - 1], val);
|
||||
const bool isInt = validInt64FromString(args[arg - 1], val);
|
||||
|
||||
if ((P180_Command_e::Value == cmd) && !isInt) {
|
||||
val = findDeviceValueIndexByName(args[arg - 1], _taskIndex);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case P180_Command_e::RegisterRead: // read - r.<format>.<reg>
|
||||
case P180_Command_e::Register16Read: // read16 - s.<format>.<reg16>
|
||||
reg = val;
|
||||
@@ -390,7 +396,7 @@ std::vector<P180_Command_struct>P180_data_struct::parseI2CCommands(const String&
|
||||
}
|
||||
|
||||
if (!key.isEmpty()) {
|
||||
_commandCache.emplace(key, commands);
|
||||
_commandCache[key] = commands;
|
||||
|
||||
if (loglevelActiveFor(LOG_LEVEL_INFO) && _showLog) {
|
||||
addLog(LOG_LEVEL_INFO, strformat(F("P180 : Insert '%s' into cache with %d commands."), name.c_str(), commands.size()));
|
||||
@@ -919,6 +925,7 @@ bool P180_data_struct::plugin_read(struct EventStruct *event) {
|
||||
if ((P180_CommandState_e::Processing == commandState) || (P180_CommandState_e::ConditionalExit == commandState)) {
|
||||
commandState = P180_CommandState_e::Idle;
|
||||
_commands.clear();
|
||||
_valueIsSet = false; // reset afterward
|
||||
} else if (P180_CommandState_e::StartingDelay == commandState) {
|
||||
commandState = P180_CommandState_e::WaitingForDelay;
|
||||
}
|
||||
@@ -936,35 +943,44 @@ bool P180_data_struct::plugin_write(struct EventStruct *event,
|
||||
|
||||
if (equals(cmd, F("geni2c"))) {
|
||||
const String sub = parseString(string, 2);
|
||||
const bool hasPar3 = !parseString(string, 3).isEmpty();
|
||||
const bool hasPar4 = !parseString(string, 4).isEmpty();
|
||||
const String par3 = parseStringKeepCaseNoTrim(string, 3);
|
||||
const String varName = parseString(string, 4);
|
||||
const bool hasPar3 = !par3.isEmpty();
|
||||
const bool hasPar4 = !varName.isEmpty();
|
||||
const bool hasPar5 = !parseString(string, 5).isEmpty();
|
||||
std::vector<P180_Command_struct> cmds;
|
||||
taskVarIndex_t taskVar = INVALID_TASKVAR_INDEX;
|
||||
uint32_t val{};
|
||||
|
||||
if (equals(sub, F("cmd")) && hasPar3) { // genI2c,cmd,<I2Ccommands>[,<TaskValueIndex>[,<name>]]
|
||||
taskVarIndex_t taskVar = INVALID_TASKVAR_INDEX;
|
||||
String name;
|
||||
uint32_t val{};
|
||||
|
||||
if (hasPar4 && validUIntFromString(parseString(string, 4), val) && (val > 0) && (val <= VARS_PER_TASK)) {
|
||||
if (hasPar4) {
|
||||
if (validUIntFromString(varName, val) && (val > 0) && (val <= VARS_PER_TASK)) {
|
||||
taskVar = val - 1;
|
||||
} else {
|
||||
taskVar = findDeviceValueIndexByName(varName, event->TaskIndex);
|
||||
}
|
||||
}
|
||||
|
||||
if (equals(sub, F("cmd")) && hasPar3) { // genI2c,cmd,<I2Ccommands>[,<TaskValueIndex>[,<cache_name>]]
|
||||
String cacheName;
|
||||
|
||||
if (hasPar5) {
|
||||
name = parseString(string, 5);
|
||||
cacheName = parseString(string, 5);
|
||||
}
|
||||
|
||||
std::vector<P180_Command_struct> cmds = parseI2CCommands(name, parseString(string, 3), !name.isEmpty());
|
||||
cmds = parseI2CCommands(cacheName, par3, !cacheName.isEmpty());
|
||||
} else if (equals(sub, F("exec")) && hasPar3) { // genI2c,exec,<cache_name>[,<TaskValueIndex>]
|
||||
cmds = parseI2CCommands(par3, EMPTY_STRING); // Fetch commands from cache by name
|
||||
}
|
||||
|
||||
if (!cmds.empty()) {
|
||||
_commands = cmds;
|
||||
_varIndex = taskVar;
|
||||
_loop = 0;
|
||||
_loopMax = _loop + 1; // Process single entry
|
||||
commandState = P180_CommandState_e::Processing;
|
||||
Scheduler.schedule_task_device_timer(_taskIndex, millis() + 5);
|
||||
if (!cmds.empty() && (P180_CommandState_e::Idle == commandState)) { // Execute commands when not busy
|
||||
_commands = cmds;
|
||||
_varIndex = taskVar;
|
||||
_loop = 0;
|
||||
_loopMax = _loop + 1; // Process single entry
|
||||
commandState = P180_CommandState_e::Processing;
|
||||
Scheduler.schedule_task_device_timer(_taskIndex, millis() + 5);
|
||||
|
||||
success = true;
|
||||
}
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user