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
This commit is contained in:
Laurent Dong 2019-02-05 09:34:17 -05:00
parent c998760deb
commit 09732c9f2d
2 changed files with 50 additions and 33 deletions

1
.gitignore vendored
View File

@ -15,3 +15,4 @@ build
.vscode/.browse.c_cpp.db* .vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json .vscode/c_cpp_properties.json
.vscode/launch.json .vscode/launch.json
*.bak

View File

@ -78,6 +78,27 @@
#define D_JSON_INITIATED "Initiated" #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 }; 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 ; 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" String rule_name = rule.substring(pos +1); // "CURRENT>0.100" or "BOOT" or "%var1%" or "MINUTE|5"
char compare = ' '; int8_t compare = COMPARE_OPERATOR_NONE;
pos = rule_name.indexOf(">"); for (int8_t i=MAXIMUM_COMPARE_OPERATOR; i>=0; i--) {
if (pos > 0) { if ((pos = rule_name.indexOf(compare_operators[i])) > 0) {
compare = '>'; compare = i;
} else { break;
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 = '%';
}
}
} }
} }
char rule_svalue[CMDSZ] = { 0 }; char rule_svalue[CMDSZ] = { 0 };
double rule_value = 0; double rule_value = 0;
if (pos > 0) { if (compare != COMPARE_OPERATOR_NONE) {
String rule_param = rule_name.substring(pos + 1); String rule_param = rule_name.substring(pos + strlen(compare_operators[compare]));
for (uint8_t i = 0; i < MAX_RULE_VARS; i++) { for (uint8_t i = 0; i < MAX_RULE_VARS; i++) {
snprintf_P(stemp, sizeof(stemp), PSTR("%%VAR%d%%"), i +1); snprintf_P(stemp, sizeof(stemp), PSTR("%%VAR%d%%"), i +1);
if (rule_param.startsWith(stemp)) { 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_value = int(value);
int int_rule_value = int(rule_value); int int_rule_value = int(rule_value);
switch (compare) { switch (compare) {
case '%': case COMPARE_OPERATOR_EXACT_DIVISION:
if ((int_value > 0) && (int_rule_value > 0)) { match = (int_rule_value && (int_value % int_rule_value) == 0);
if ((int_value % int_rule_value) == 0) { match = true; }
}
break; break;
case '>': case COMPARE_OPERATOR_EQUAL:
if (value > rule_value) { match = true; } match = (!strcasecmp(str_value, rule_svalue)); // Compare strings - this also works for hexadecimals
break; break;
case '<': case COMPARE_OPERATOR_BIGGER:
if (value < rule_value) { match = true; } match = (value > rule_value);
break; break;
case '=': case COMPARE_OPERATOR_SMALLER:
// if (value == rule_value) { match = true; } // Compare values - only decimals or partly hexadecimals match = (value < rule_value);
if (!strcasecmp(str_value, rule_svalue)) { match = true; } // Compare strings - this also works for hexadecimals
break; break;
case ' ': case COMPARE_OPERATOR_NUMBER_EQUAL:
match = true; // Json value but not needed match = (value == rule_value);
break; 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; } else match = true;