From 09732c9f2d116885ec3c748867e14f72820df947 Mon Sep 17 00:00:00 2001 From: Laurent Dong Date: Tue, 5 Feb 2019 09:34:17 -0500 Subject: [PATCH] Add new compare operators ("==", "!=" ,">=" and "<=") for rule Introduce new compare operators for rules and did some optimization as well. The new "==" operator act as a real number comparison instead of the previous "=" operator which is doing string comparison which result in FALSE for "1 + 1 = 2". For example: rule1 on event#test do backlog var1 1;add1 1; event CompareWith2=2 endon on event#CompareWith2=%var1% do ledpower on endon ledpower off rule1 on event test --- .gitignore | 1 + sonoff/xdrv_10_rules.ino | 82 ++++++++++++++++++++++++---------------- 2 files changed, 50 insertions(+), 33 deletions(-) diff --git a/.gitignore b/.gitignore index 028a76667..7e89f6cd2 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ build .vscode/.browse.c_cpp.db* .vscode/c_cpp_properties.json .vscode/launch.json +*.bak diff --git a/sonoff/xdrv_10_rules.ino b/sonoff/xdrv_10_rules.ino index 0ea47c369..d1f7c43b2 100644 --- a/sonoff/xdrv_10_rules.ino +++ b/sonoff/xdrv_10_rules.ino @@ -78,6 +78,27 @@ #define D_JSON_INITIATED "Initiated" +#define COMPARE_OPERATOR_NONE -1 +#define COMPARE_OPERATOR_EQUAL 0 +#define COMPARE_OPERATOR_BIGGER 1 +#define COMPARE_OPERATOR_SMALLER 2 +#define COMPARE_OPERATOR_EXACT_DIVISION 3 +#define COMPARE_OPERATOR_NUMBER_EQUAL 4 +#define COMPARE_OPERATOR_NOT_EQUAL 5 +#define COMPARE_OPERATOR_BIGGER_EQUAL 6 +#define COMPARE_OPERATOR_SMALLER_EQUAL 7 +#define MAXIMUM_COMPARE_OPERATOR COMPARE_OPERATOR_SMALLER_EQUAL +char* compare_operators[] = { + "=", + ">", + "<", + "|", + "==", + "!=", + ">=", + "<=" +}; + enum RulesCommands { CMND_RULE, CMND_RULETIMER, CMND_EVENT, CMND_VAR, CMND_MEM, CMND_ADD, CMND_SUB, CMND_MULT, CMND_SCALE, CMND_CALC_RESOLUTION }; const char kRulesCommands[] PROGMEM = D_CMND_RULE "|" D_CMND_RULETIMER "|" D_CMND_EVENT "|" D_CMND_VAR "|" D_CMND_MEM "|" D_CMND_ADD "|" D_CMND_SUB "|" D_CMND_MULT "|" D_CMND_SCALE "|" D_CMND_CALC_RESOLUTION ; @@ -128,31 +149,18 @@ bool RulesRuleMatch(uint8_t rule_set, String &event, String &rule) String rule_name = rule.substring(pos +1); // "CURRENT>0.100" or "BOOT" or "%var1%" or "MINUTE|5" - char compare = ' '; - pos = rule_name.indexOf(">"); - if (pos > 0) { - compare = '>'; - } else { - pos = rule_name.indexOf("<"); - if (pos > 0) { - compare = '<'; - } else { - pos = rule_name.indexOf("="); - if (pos > 0) { - compare = '='; - } else { - pos = rule_name.indexOf("|"); // Modulo, cannot use % easily as it is used for variable detection - if (pos > 0) { - compare = '%'; - } - } + int8_t compare = COMPARE_OPERATOR_NONE; + for (int8_t i=MAXIMUM_COMPARE_OPERATOR; i>=0; i--) { + if ((pos = rule_name.indexOf(compare_operators[i])) > 0) { + compare = i; + break; } } char rule_svalue[CMDSZ] = { 0 }; double rule_value = 0; - if (pos > 0) { - String rule_param = rule_name.substring(pos + 1); + if (compare != COMPARE_OPERATOR_NONE) { + String rule_param = rule_name.substring(pos + strlen(compare_operators[compare])); for (uint8_t i = 0; i < MAX_RULE_VARS; i++) { snprintf_P(stemp, sizeof(stemp), PSTR("%%VAR%d%%"), i +1); if (rule_param.startsWith(stemp)) { @@ -224,24 +232,32 @@ bool RulesRuleMatch(uint8_t rule_set, String &event, String &rule) int int_value = int(value); int int_rule_value = int(rule_value); switch (compare) { - case '%': - if ((int_value > 0) && (int_rule_value > 0)) { - if ((int_value % int_rule_value) == 0) { match = true; } - } + case COMPARE_OPERATOR_EXACT_DIVISION: + match = (int_rule_value && (int_value % int_rule_value) == 0); break; - case '>': - if (value > rule_value) { match = true; } + case COMPARE_OPERATOR_EQUAL: + match = (!strcasecmp(str_value, rule_svalue)); // Compare strings - this also works for hexadecimals break; - case '<': - if (value < rule_value) { match = true; } + case COMPARE_OPERATOR_BIGGER: + match = (value > rule_value); break; - case '=': -// if (value == rule_value) { match = true; } // Compare values - only decimals or partly hexadecimals - if (!strcasecmp(str_value, rule_svalue)) { match = true; } // Compare strings - this also works for hexadecimals + case COMPARE_OPERATOR_SMALLER: + match = (value < rule_value); break; - case ' ': - match = true; // Json value but not needed + case COMPARE_OPERATOR_NUMBER_EQUAL: + match = (value == rule_value); break; + case COMPARE_OPERATOR_NOT_EQUAL: + match = (value != rule_value); + break; + case COMPARE_OPERATOR_BIGGER_EQUAL: + match = (value >= rule_value); + break; + case COMPARE_OPERATOR_SMALLER_EQUAL: + match = (value <= rule_value); + break; + default: + match = true; } } else match = true;