Fork of the espurna firmware for `mhsw` switches
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

934 lines
28 KiB

Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Terminal: change command-line parser (#2247) Change the underlying command line handling: - switch to a custom parser, inspired by redis / sds - update terminalRegisterCommand signature, pass only bare minimum - clean-up `help` & `commands`. update settings `set`, `get` and `del` - allow our custom test suite to run command-line tests - clean-up Stream IO to allow us to print large things into debug stream (for example, `eeprom.dump`) - send parsing errors to the debug log As a proof of concept, introduce `TERMINAL_MQTT_SUPPORT` and `TERMINAL_WEB_API_SUPPORT` - MQTT subscribes to the `<root>/cmd/set` and sends response to the `<root>/cmd`. We can't output too much, as we don't have any large-send API. - Web API listens to the `/api/cmd?apikey=...&line=...` (or PUT, params inside the body). This one is intended as a possible replacement of the `API_SUPPORT`. Internals introduce a 'task' around the AsyncWebServerRequest object that will simulate what WiFiClient does and push data into it continuously, switching between CONT and SYS. Both are experimental. We only accept a single command and not every command is updated to use Print `ctx.output` object. We are also somewhat limited by the Print / Stream overall, perhaps I am overestimating the usefulness of Arduino compatibility to such an extent :) Web API handler can also sometimes show only part of the result, whenever the command tries to yield() by itself waiting for something. Perhaps we would need to create a custom request handler for that specific use-case.
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
Update rpnlib to 0.23.x (#2274) ## [0.23.0] 2020-07-26 ### Added - `p` operator to print the top of the stack via debug function - `&var` syntax to create variable reference in expression - `=` operator for variable assignment in expression - `exists` operator to check for variable existance (only for references) - `deref` operator to convert variable reference into a value (only for references) - Allow to use either float or double as floating type, parse numbers in expressions as specified type - Add boolean type, parse `true` and `false` in expressions - Add null type, parse `null` in expressions - Add string type, parse double-quoted `"string"` in expressions - Add integer and unsigned integer type, used in operators - Allow to configure underlying types from rpnlib\_config.h and -D... flags - Return `rpn_error` from operators, split error types into categories - Create a new stack by using `[` keyword. Move stack contents into the previous stack + size by using `]`. ### Changed - Stack structure no longer holds raw `float`, but internal `rpn_value` type - rpn\_... setter and getter methods use `rpn_value` type - Operator functions return `rpn_error` type, allowing to return both value and operator errors - Variables in expressions are no longer required to exist when using `&var` Expression will automatically create the variable, set it to `null` and push it's reference on the stack - It is possible to create 'reference' stack values - Improve precision of `e` and `pi` ### Fixed - Proper value for `e` constant - Allow to use multiple contexts simultaniously, replace `rpn_error` and `rpn_debug_callback` with the current `rpn_context` members `error` and `debug_callback` respectively
4 years ago
  1. /*
  2. RPN RULES MODULE
  3. Use RPNLib library (https://github.com/xoseperez/rpnlib)
  4. Copyright (C) 2019 by Xose Pérez <xose dot perez at gmail dot com>
  5. */
  6. #include "rpnrules.h"
  7. #if RPN_RULES_SUPPORT
  8. #include "broker.h"
  9. #include "light.h"
  10. #include "mqtt.h"
  11. #include "ntp.h"
  12. #include "relay.h"
  13. #include "rfbridge.h"
  14. #include "rpc.h"
  15. #include "rtcmem.h"
  16. #include "sensor.h"
  17. #include "terminal.h"
  18. #include "wifi.h"
  19. #include "ws.h"
  20. #include <list>
  21. #include <vector>
  22. // -----------------------------------------------------------------------------
  23. // Custom commands
  24. // -----------------------------------------------------------------------------
  25. rpn_context _rpn_ctxt;
  26. bool _rpn_run = false;
  27. unsigned long _rpn_delay = RPN_DELAY;
  28. unsigned long _rpn_last = 0;
  29. struct RpnRunner {
  30. enum class Policy {
  31. OneShot,
  32. Periodic
  33. };
  34. RpnRunner(Policy policy_, uint32_t period_) :
  35. policy(policy_),
  36. period(period_),
  37. last(millis())
  38. {}
  39. Policy policy { Policy::Periodic };
  40. uint32_t period { 0ul };
  41. uint32_t last { 0ul };
  42. bool expired { false };
  43. };
  44. std::vector<RpnRunner> _rpn_runners;
  45. rpn_operator_error _rpnRunnerHandler(rpn_context & ctxt, RpnRunner::Policy policy, uint32_t time) {
  46. for (auto& runner : _rpn_runners) {
  47. if ((policy == runner.policy) && (time == runner.period)) {
  48. return runner.expired
  49. ? rpn_operator_error::Ok
  50. : rpn_operator_error::CannotContinue;
  51. }
  52. }
  53. _rpn_runners.emplace_back(policy, time);
  54. return rpn_operator_error::CannotContinue;
  55. }
  56. // -----------------------------------------------------------------------------
  57. bool _rpnWebSocketOnKeyCheck(const char * key, JsonVariant& value) {
  58. return (strncmp(key, "rpn", 3) == 0);
  59. }
  60. void _rpnWebSocketOnConnected(JsonObject& root) {
  61. root["rpnSticky"] = getSetting("rpnSticky", 1 == RPN_STICKY);
  62. root["rpnDelay"] = getSetting("rpnDelay", RPN_DELAY);
  63. JsonArray& rules = root.createNestedArray("rpnRules");
  64. unsigned char i = 0;
  65. String rule = getSetting({"rpnRule", i});
  66. while (rule.length()) {
  67. rules.add(rule);
  68. rule = getSetting({"rpnRule", ++i});
  69. }
  70. #if MQTT_SUPPORT
  71. i=0;
  72. JsonArray& topics = root.createNestedArray("rpnTopics");
  73. JsonArray& names = root.createNestedArray("rpnNames");
  74. String rpn_topic = getSetting({"rpnTopic", i});
  75. while (rpn_topic.length() > 0) {
  76. String rpn_name = getSetting({"rpnName", i});
  77. topics.add(rpn_topic);
  78. names.add(rpn_name);
  79. rpn_topic = getSetting({"rpnTopic", ++i});
  80. }
  81. #endif
  82. }
  83. #if MQTT_SUPPORT
  84. void _rpnMQTTSubscribe() {
  85. unsigned char i = 0;
  86. String rpn_topic = getSetting({"rpnTopic", i});
  87. while (rpn_topic.length()) {
  88. mqttSubscribeRaw(rpn_topic.c_str());
  89. rpn_topic = getSetting({"rpnTopic", ++i});
  90. }
  91. }
  92. void _rpnMQTTCallback(unsigned int type, const char * topic, const char * payload) {
  93. if (type == MQTT_CONNECT_EVENT) {
  94. _rpnMQTTSubscribe();
  95. }
  96. if (type == MQTT_MESSAGE_EVENT) {
  97. unsigned char i = 0;
  98. String rpn_topic = getSetting({"rpnTopic", i});
  99. while (rpn_topic.length()) {
  100. if (rpn_topic.equals(topic)) {
  101. String rpn_name = getSetting({"rpnName", i});
  102. if (rpn_name.length()) {
  103. rpn_value value { atof(payload) };
  104. rpn_variable_set(_rpn_ctxt, rpn_name, value);
  105. _rpn_run = true;
  106. break;
  107. }
  108. }
  109. rpn_topic = getSetting({"rpnTopic", ++i});
  110. }
  111. }
  112. }
  113. #endif // MQTT_SUPPORT
  114. void _rpnConfigure() {
  115. #if MQTT_SUPPORT
  116. if (mqttConnected()) _rpnMQTTSubscribe();
  117. #endif
  118. _rpn_delay = getSetting("rpnDelay", RPN_DELAY);
  119. }
  120. void _rpnBrokerCallback(const String& topic, unsigned char id, double value, const char*) {
  121. char name[32] = {0};
  122. snprintf(name, sizeof(name), "%s%u", topic.c_str(), id);
  123. if (topic == MQTT_TOPIC_RELAY) {
  124. rpn_variable_set(_rpn_ctxt, name, rpn_value(static_cast<bool>(value)));
  125. } else {
  126. rpn_variable_set(_rpn_ctxt, name, rpn_value(value));
  127. }
  128. _rpn_run = true;
  129. }
  130. void _rpnBrokerStatus(const String& topic, unsigned char id, unsigned int value) {
  131. _rpnBrokerCallback(topic, id, double(value), nullptr);
  132. }
  133. #if NTP_SUPPORT
  134. rpn_error _rpnNtpNow(rpn_context & ctxt) {
  135. if (!ntpSynced()) return rpn_operator_error::CannotContinue;
  136. rpn_value ts { static_cast<rpn_int>(now()) };
  137. rpn_stack_push(ctxt, ts);
  138. return 0;
  139. }
  140. rpn_error _rpnNtpFunc(rpn_context & ctxt, rpn_int (*func)(time_t)) {
  141. rpn_value value;
  142. rpn_stack_pop(ctxt, value);
  143. value = rpn_value(func(value.toInt()));
  144. rpn_stack_push(ctxt, value);
  145. return 0;
  146. }
  147. #endif // NTP_SUPPORT
  148. String _rpnValueToString(const rpn_value& value) {
  149. String out;
  150. if (value.isString()) {
  151. out = value.toString();
  152. } else if (value.isFloat()) {
  153. out = String(value.toFloat(), 10);
  154. } else if (value.isInt()) {
  155. out = String(value.toInt(), 10);
  156. } else if (value.isUint()) {
  157. out = String(value.toUint(), 10);
  158. } else if (value.isBoolean()) {
  159. out = String(value.toBoolean() ? "true" : "false");
  160. } else if (value.isNull()) {
  161. out = F("(null)");
  162. }
  163. return out;
  164. }
  165. char _rpnStackTypeTag(rpn_stack_value::Type type) {
  166. switch (type) {
  167. case rpn_stack_value::Type::None:
  168. return 'N';
  169. case rpn_stack_value::Type::Variable:
  170. return '$';
  171. case rpn_stack_value::Type::Array:
  172. return 'A';
  173. case rpn_stack_value::Type::Value:
  174. default:
  175. return ' ';
  176. }
  177. }
  178. #if RELAY_SUPPORT
  179. rpn_error _rpnRelayStatus(rpn_context & ctxt, bool force) {
  180. rpn_value id;
  181. rpn_value status;
  182. rpn_stack_pop(ctxt, id);
  183. rpn_stack_pop(ctxt, status);
  184. rpn_uint value = status.toUint();
  185. if (value == 2) {
  186. relayToggle(id.toUint());
  187. } else if (relayStatusTarget(id.toUint()) != (value == 1)) {
  188. relayStatus(id.toUint(), value == 1);
  189. }
  190. return 0;
  191. }
  192. #endif // RELAY_SUPPORT
  193. #if RFB_SUPPORT
  194. struct rpn_rfbridge_code {
  195. unsigned char protocol;
  196. String raw;
  197. size_t count;
  198. decltype(millis()) last;
  199. };
  200. // TODO: in theory, we could do with forward_list. however, this would require a more complicated removal process,
  201. // as we would no longer know the previous element and would need to track 2 elements at a time
  202. static std::list<rpn_rfbridge_code> _rfb_codes;
  203. static uint32_t _rfb_code_repeat_window;
  204. static uint32_t _rfb_code_stale_delay;
  205. static uint32_t _rfb_code_match_window;
  206. struct rpn_rfbridge_match {
  207. unsigned char protocol;
  208. String raw;
  209. };
  210. rpn_error _rpnRfbSequence(rpn_context& ctxt) {
  211. auto raw_second = rpn_stack_pop(ctxt);
  212. auto proto_second = rpn_stack_pop(ctxt);
  213. auto raw_first = rpn_stack_pop(ctxt);
  214. auto proto_first = rpn_stack_pop(ctxt);
  215. // find 2 codes in the same order and save pointers
  216. rpn_rfbridge_match match[2] {
  217. {static_cast<unsigned char>(proto_first.toUint()), raw_first.toString()},
  218. {static_cast<unsigned char>(proto_second.toUint()), raw_second.toString()}
  219. };
  220. rpn_rfbridge_code* refs[2] {nullptr, nullptr};
  221. for (auto& recent : _rfb_codes) {
  222. if ((refs[0] != nullptr) && (refs[1] != nullptr)) {
  223. break;
  224. }
  225. for (int index = 0; index < 2; ++index) {
  226. if ((refs[index] == nullptr)
  227. && (match[index].protocol == recent.protocol)
  228. && (match[index].raw == recent.raw)) {
  229. refs[index] = &recent;
  230. }
  231. }
  232. }
  233. if ((refs[0] == nullptr) || (refs[1] == nullptr)) {
  234. return rpn_operator_error::CannotContinue;
  235. }
  236. // purge codes to avoid matching again on the next rules run
  237. if ((millis() - refs[0]->last) > (millis() - refs[1]->last)) {
  238. _rfb_codes.remove_if([&refs](rpn_rfbridge_code& code) {
  239. return (refs[0] == &code) || (refs[1] == &code);
  240. });
  241. return rpn_operator_error::Ok;
  242. }
  243. return rpn_operator_error::CannotContinue;
  244. }
  245. decltype(_rfb_codes)::iterator _rpnRfbFindCode(unsigned char protocol, const String& match) {
  246. return std::find_if(_rfb_codes.begin(), _rfb_codes.end(), [protocol, &match](const rpn_rfbridge_code& code) {
  247. return (code.protocol == protocol) && (code.raw == match);
  248. });
  249. }
  250. rpn_error _rpnRfbPop(rpn_context& ctxt) {
  251. auto code = rpn_stack_pop(ctxt);
  252. auto proto = rpn_stack_pop(ctxt);
  253. auto result = _rpnRfbFindCode(proto.toUint(), code.toString());
  254. if (result == _rfb_codes.end()) {
  255. return rpn_operator_error::CannotContinue;
  256. }
  257. _rfb_codes.erase(result);
  258. return rpn_operator_error::Ok;
  259. }
  260. rpn_error _rpnRfbInfo(rpn_context& ctxt) {
  261. auto code = rpn_stack_pop(ctxt);
  262. auto proto = rpn_stack_pop(ctxt);
  263. auto result = _rpnRfbFindCode(proto.toUint(), code.toString());
  264. if (result == _rfb_codes.end()) {
  265. return rpn_operator_error::CannotContinue;
  266. }
  267. rpn_stack_push(ctxt, rpn_value(
  268. static_cast<rpn_uint>((*result).count)));
  269. rpn_stack_push(ctxt, rpn_value(
  270. static_cast<rpn_uint>((*result).last)));
  271. return rpn_operator_error::Ok;
  272. }
  273. rpn_error _rpnRfbWaitMatch(rpn_context& ctxt) {
  274. auto code = rpn_stack_pop(ctxt);
  275. auto proto = rpn_stack_pop(ctxt);
  276. auto count = rpn_stack_pop(ctxt);
  277. auto time = rpn_stack_pop(ctxt);
  278. auto result = _rpnRfbFindCode(proto.toUint(), code.toString());
  279. if (result == _rfb_codes.end()) {
  280. return rpn_operator_error::CannotContinue;
  281. }
  282. if ((*result).count < count.toUint()) {
  283. return rpn_operator_error::CannotContinue;
  284. }
  285. // purge code to avoid matching again on the next rules run
  286. if (rpn_operator_error::Ok == _rpnRunnerHandler(ctxt, RpnRunner::Policy::OneShot, time.toUint())) {
  287. _rfb_codes.erase(result);
  288. return rpn_operator_error::Ok;
  289. }
  290. return rpn_operator_error::CannotContinue;
  291. }
  292. rpn_error _rpnRfbMatcher(rpn_context& ctxt) {
  293. auto code = rpn_stack_pop(ctxt);
  294. auto proto = rpn_stack_pop(ctxt);
  295. auto count = rpn_stack_pop(ctxt);
  296. auto result = _rpnRfbFindCode(proto.toUint(), code.toString());
  297. if (result == _rfb_codes.end()) {
  298. return rpn_operator_error::CannotContinue;
  299. }
  300. // only process recent codes, ignore when rule is processing outside of this small window
  301. if (millis() - (*result).last >= _rfb_code_match_window) {
  302. return rpn_operator_error::CannotContinue;
  303. }
  304. // purge code to avoid matching again on the next rules run
  305. if ((*result).count == count.toUint()) {
  306. _rfb_codes.erase(result);
  307. return rpn_operator_error::Ok;
  308. }
  309. return rpn_operator_error::CannotContinue;
  310. }
  311. void _rpnBrokerRfbridgeCallback(unsigned char protocol, const char* raw_code) {
  312. // remove really old codes that we have not seen in a while to avoid memory exhaustion
  313. auto ts = millis();
  314. auto old = std::remove_if(_rfb_codes.begin(), _rfb_codes.end(), [ts](rpn_rfbridge_code& code) {
  315. return (ts - code.last) >= _rfb_code_stale_delay;
  316. });
  317. if (old != _rfb_codes.end()) {
  318. _rfb_codes.erase(old, _rfb_codes.end());
  319. }
  320. auto result = _rpnRfbFindCode(protocol, raw_code);
  321. if (result != _rfb_codes.end()) {
  322. // we also need to reset the counter at a certain point to allow next batch of repeats to go through
  323. if (millis() - (*result).last >= _rfb_code_repeat_window) {
  324. (*result).count = 0;
  325. }
  326. (*result).last = millis();
  327. (*result).count += 1u;
  328. } else {
  329. _rfb_codes.push_back({protocol, raw_code, 1u, millis()});
  330. }
  331. _rpn_run = true;
  332. }
  333. void _rpnRfbSetup() {
  334. // - Repeat window is an arbitrary time, just about 3-4 more times it takes for
  335. // a code to be sent again when holding a generic remote button
  336. // Code counter is reset to 0 when outside of the window.
  337. // - Stale delay allows broker callback to remove really old codes.
  338. // (TODO: can this happen in loop() cb instead?)
  339. _rfb_code_repeat_window = getSetting("rfbRepeatWindow", 2000ul);
  340. _rfb_code_match_window = getSetting("rfbMatchWindow", 2000ul);
  341. _rfb_code_stale_delay = getSetting("rfbStaleDelay", 10000ul);
  342. #if TERMINAL_SUPPORT
  343. terminalRegisterCommand(F("RFB.CODES"), [](const terminal::CommandContext& ctx) {
  344. for (auto& code : _rfb_codes) {
  345. char buffer[128] = {0};
  346. snprintf_P(buffer, sizeof(buffer),
  347. PSTR("proto=%u raw=\"%s\" count=%u last=%u"),
  348. code.protocol,
  349. code.raw.c_str(),
  350. code.count,
  351. code.last
  352. );
  353. ctx.output.println(buffer);
  354. }
  355. });
  356. #endif
  357. // Main bulk of the processing goes on in here
  358. RfbridgeBroker::Register(_rpnBrokerRfbridgeCallback);
  359. }
  360. #endif // RFB_SUPPORT
  361. void _rpnShowStack(Print& print) {
  362. print.println(F("Stack:"));
  363. auto index = rpn_stack_size(_rpn_ctxt);
  364. if (!index) {
  365. print.println(F(" (empty)"));
  366. return;
  367. }
  368. rpn_stack_foreach(_rpn_ctxt, [&index, &print](rpn_stack_value::Type type, const rpn_value& value) {
  369. print.printf("%c %02u: %s\n",
  370. _rpnStackTypeTag(type), index--,
  371. _rpnValueToString(value).c_str()
  372. );
  373. });
  374. }
  375. void _rpnInit() {
  376. // Init context
  377. rpn_init(_rpn_ctxt);
  378. // Time functions need NTP support
  379. // TODO: since 1.15.0, timelib+ntpclientlib are no longer used with latest Cores
  380. // `now` is always in UTC, `utc_...` functions to be used instead to convert time
  381. #if NTP_SUPPORT && !NTP_LEGACY_SUPPORT
  382. rpn_operator_set(_rpn_ctxt, "utc", 0, _rpnNtpNow);
  383. rpn_operator_set(_rpn_ctxt, "now", 0, _rpnNtpNow);
  384. rpn_operator_set(_rpn_ctxt, "utc_month", 1, [](rpn_context & ctxt) {
  385. return _rpnNtpFunc(ctxt, utc_month);
  386. });
  387. rpn_operator_set(_rpn_ctxt, "month", 1, [](rpn_context & ctxt) {
  388. return _rpnNtpFunc(ctxt, month);
  389. });
  390. rpn_operator_set(_rpn_ctxt, "utc_day", 1, [](rpn_context & ctxt) {
  391. return _rpnNtpFunc(ctxt, utc_day);
  392. });
  393. rpn_operator_set(_rpn_ctxt, "day", 1, [](rpn_context & ctxt) {
  394. return _rpnNtpFunc(ctxt, day);
  395. });
  396. rpn_operator_set(_rpn_ctxt, "utc_dow", 1, [](rpn_context & ctxt) {
  397. return _rpnNtpFunc(ctxt, utc_weekday);
  398. });
  399. rpn_operator_set(_rpn_ctxt, "dow", 1, [](rpn_context & ctxt) {
  400. return _rpnNtpFunc(ctxt, weekday);
  401. });
  402. rpn_operator_set(_rpn_ctxt, "utc_hour", 1, [](rpn_context & ctxt) {
  403. return _rpnNtpFunc(ctxt, utc_hour);
  404. });
  405. rpn_operator_set(_rpn_ctxt, "hour", 1, [](rpn_context & ctxt) {
  406. return _rpnNtpFunc(ctxt, hour);
  407. });
  408. rpn_operator_set(_rpn_ctxt, "utc_minute", 1, [](rpn_context & ctxt) {
  409. return _rpnNtpFunc(ctxt, utc_minute);
  410. });
  411. rpn_operator_set(_rpn_ctxt, "minute", 1, [](rpn_context & ctxt) {
  412. return _rpnNtpFunc(ctxt, minute);
  413. });
  414. #endif
  415. // TODO: 1.14.0 weekday(...) conversion seemed to have 0..6 range with Monday as 0
  416. // using classic Sunday as first, but instead of 0 it is 1
  417. // Implementation above also uses 1 for Sunday, staying compatible with TimeLib
  418. #if NTP_SUPPORT && NTP_LEGACY_SUPPORT
  419. rpn_operator_set(_rpn_ctxt, "utc", 0, [](rpn_context & ctxt) -> rpn_error {
  420. if (!ntpSynced()) return rpn_operator_error::CannotContinue;
  421. rpn_value ts { static_cast<rpn_int>(ntpLocal2UTC(now())) };
  422. rpn_stack_push(ctxt, ts);
  423. return 0;
  424. });
  425. rpn_operator_set(_rpn_ctxt, "now", 0, _rpnNtpNow);
  426. rpn_operator_set(_rpn_ctxt, "month", 1, [](rpn_context & ctxt) {
  427. return _rpnNtpFunc(ctxt, month);
  428. });
  429. rpn_operator_set(_rpn_ctxt, "day", 1, [](rpn_context & ctxt) {
  430. return _rpnNtpFunc(ctxt, day);
  431. });
  432. rpn_operator_set(_rpn_ctxt, "dow", 1, [](rpn_context & ctxt) {
  433. return _rpnNtpFunc(ctxt, weekday);
  434. });
  435. rpn_operator_set(_rpn_ctxt, "hour", 1, [](rpn_context & ctxt) {
  436. return _rpnNtpFunc(ctxt, hour);
  437. });
  438. rpn_operator_set(_rpn_ctxt, "minute", 1, [](rpn_context & ctxt) {
  439. return _rpnNtpFunc(ctxt, minute);
  440. });
  441. #endif
  442. // Accept relay number and numeric API status value (0, 1 and 2)
  443. #if RELAY_SUPPORT
  444. // apply status and reset timers when called
  445. rpn_operator_set(_rpn_ctxt, "relay_reset", 2, [](rpn_context & ctxt) {
  446. return _rpnRelayStatus(ctxt, true);
  447. });
  448. // only update status when target status differs, keep running timers
  449. rpn_operator_set(_rpn_ctxt, "relay", 2, [](rpn_context & ctxt) {
  450. return _rpnRelayStatus(ctxt, false);
  451. });
  452. #endif // RELAY_SUPPORT == 1
  453. // Channel operators
  454. #if RELAY_PROVIDER == RELAY_PROVIDER_LIGHT
  455. rpn_operator_set(_rpn_ctxt, "update", 0, [](rpn_context & ctxt) -> rpn_error {
  456. lightUpdate(true, true);
  457. return 0;
  458. });
  459. rpn_operator_set(_rpn_ctxt, "black", 0, [](rpn_context & ctxt) -> rpn_error {
  460. lightColor((unsigned long) 0);
  461. return 0;
  462. });
  463. rpn_operator_set(_rpn_ctxt, "channel", 2, [](rpn_context & ctxt) -> rpn_error {
  464. rpn_value value;
  465. rpn_value id;
  466. rpn_stack_pop(ctxt, id);
  467. rpn_stack_pop(ctxt, value);
  468. lightChannel(id.toUint(), id.toInt());
  469. return 0;
  470. });
  471. #endif
  472. #if RFB_SUPPORT
  473. rpn_operator_set(_rpn_ctxt, "rfb_pop", 2, _rpnRfbPop);
  474. rpn_operator_set(_rpn_ctxt, "rfb_info", 2, _rpnRfbInfo);
  475. rpn_operator_set(_rpn_ctxt, "rfb_sequence", 4, _rpnRfbSequence);
  476. rpn_operator_set(_rpn_ctxt, "rfb_match", 3, _rpnRfbMatcher);
  477. rpn_operator_set(_rpn_ctxt, "rfb_match_wait", 4, _rpnRfbWaitMatch);
  478. #endif
  479. #if MQTT_SUPPORT
  480. rpn_operator_set(_rpn_ctxt, "mqtt_send", 2, [](rpn_context & ctxt) -> rpn_error {
  481. rpn_value message;
  482. rpn_stack_pop(ctxt, message);
  483. rpn_value topic;
  484. rpn_stack_pop(ctxt, topic);
  485. return mqttSendRaw(topic.toString().c_str(), message.toString().c_str())
  486. ? rpn_operator_error::Ok
  487. : rpn_operator_error::CannotContinue;
  488. });
  489. #endif
  490. // Some debugging. Dump stack contents
  491. #if TERMINAL_SUPPORT
  492. rpn_operator_set(_rpn_ctxt, "showstack", 0, [](rpn_context & ctxt) -> rpn_error {
  493. _rpnShowStack(terminalDefaultStream());
  494. return 0;
  495. });
  496. #endif
  497. // And, simple string logging
  498. #if DEBUG_SUPPORT
  499. rpn_operator_set(_rpn_ctxt, "dbgmsg", 1, [](rpn_context & ctxt) -> rpn_error {
  500. rpn_value message;
  501. rpn_stack_pop(ctxt, message);
  502. DEBUG_MSG_P(PSTR("[RPN] %s\n"), message.toString().c_str());
  503. return 0;
  504. });
  505. #endif
  506. rpn_operator_set(_rpn_ctxt, "mem?", 0, [](rpn_context & ctxt) -> rpn_error {
  507. rpn_stack_push(ctxt, rpn_value(rtcmemStatus()));
  508. return 0;
  509. });
  510. rpn_operator_set(_rpn_ctxt, "mem_write", 2, [](rpn_context & ctxt) -> rpn_error {
  511. auto addr = rpn_stack_pop(ctxt).toUint();
  512. auto value = rpn_stack_pop(ctxt).toUint();
  513. if (addr < RTCMEM_BLOCKS) {
  514. auto* rtcmem = reinterpret_cast<volatile uint32_t*>(RTCMEM_ADDR);
  515. *(rtcmem + addr) = value;
  516. return 0;
  517. }
  518. return rpn_operator_error::InvalidArgument;
  519. });
  520. rpn_operator_set(_rpn_ctxt, "mem_read", 1, [](rpn_context & ctxt) -> rpn_error {
  521. auto addr = rpn_stack_pop(ctxt).toUint();
  522. if (addr < RTCMEM_BLOCKS) {
  523. auto* rtcmem = reinterpret_cast<volatile uint32_t*>(RTCMEM_ADDR);
  524. rpn_uint result = *(rtcmem + addr);
  525. rpn_stack_push(ctxt, rpn_value(result));
  526. return 0;
  527. }
  528. return rpn_operator_error::InvalidArgument;
  529. });
  530. rpn_operator_set(_rpn_ctxt, "sleep", 2, [](rpn_context & ctxt) -> rpn_error {
  531. static bool once { false };
  532. if (once) return rpn_operator_error::CannotContinue;
  533. auto value = rpn_stack_pop(ctxt).checkedToUint();
  534. if (!value.ok()) {
  535. return value.error();
  536. }
  537. uint64_t duration = value.value();
  538. if (!duration) {
  539. return rpn_operator_error::CannotContinue;
  540. }
  541. auto mode = rpn_stack_pop(ctxt).toUint();
  542. once = true;
  543. schedule_function([duration, mode]() {
  544. wifiTurnOff();
  545. ESP.deepSleep(duration * 1000000ull, static_cast<RFMode>(mode));
  546. });
  547. return 0;
  548. });
  549. rpn_operator_set(_rpn_ctxt, "stations", 0, [](rpn_context & ctxt) -> rpn_error {
  550. if (!(WiFi.getMode() & WIFI_AP)) return rpn_operator_error::CannotContinue;
  551. rpn_stack_push(ctxt, rpn_value(static_cast<rpn_uint>(WiFi.softAPgetStationNum())));
  552. return 0;
  553. });
  554. rpn_operator_set(_rpn_ctxt, "disconnect", 0, [](rpn_context & ctxt) -> rpn_error {
  555. wifiDisconnect();
  556. yield();
  557. return 0;
  558. });
  559. rpn_operator_set(_rpn_ctxt, "rssi", 0, [](rpn_context & ctxt) -> rpn_error {
  560. if (!wifiConnected()) return rpn_operator_error::CannotContinue;
  561. rpn_stack_push(ctxt, rpn_value(static_cast<rpn_int>(WiFi.RSSI())));
  562. return 0;
  563. });
  564. rpn_operator_set(_rpn_ctxt, "delay", 1, [](rpn_context & ctxt) -> rpn_error {
  565. auto ms = rpn_stack_pop(ctxt);
  566. delay(ms.toUint());
  567. return 0;
  568. });
  569. rpn_operator_set(_rpn_ctxt, "yield", 0, [](rpn_context & ctxt) -> rpn_error {
  570. yield();
  571. return 0;
  572. });
  573. rpn_operator_set(_rpn_ctxt, "reset", 0, [](rpn_context & ctxt) -> rpn_error {
  574. static bool once = ([]() {
  575. deferredReset(100, CUSTOM_RESET_TERMINAL);
  576. return true;
  577. })();
  578. return once
  579. ? rpn_operator_error::CannotContinue
  580. : rpn_operator_error::Ok;
  581. });
  582. rpn_operator_set(_rpn_ctxt, "millis", 0, [](rpn_context & ctxt) -> rpn_error {
  583. rpn_stack_push(ctxt, rpn_value(static_cast<uint32_t>(millis())));
  584. return 0;
  585. });
  586. rpn_operator_set(_rpn_ctxt, "oneshot_ms", 1, [](rpn_context & ctxt) -> rpn_error {
  587. auto every = rpn_stack_pop(ctxt);
  588. return _rpnRunnerHandler(ctxt, RpnRunner::Policy::OneShot, every.toUint());
  589. });
  590. rpn_operator_set(_rpn_ctxt, "every_ms", 1, [](rpn_context & ctxt) -> rpn_error {
  591. auto every = rpn_stack_pop(ctxt);
  592. return _rpnRunnerHandler(ctxt, RpnRunner::Policy::Periodic, every.toUint());
  593. });
  594. // XXX: workaround for the vector 2x growth on push. will need to fix this in the rpnlib
  595. _rpn_ctxt.operators.shrink_to_fit();
  596. DEBUG_MSG_P(PSTR("[RPN] Registered %u operators\n"), _rpn_ctxt.operators.size());
  597. }
  598. #if TERMINAL_SUPPORT
  599. void _rpnInitCommands() {
  600. terminalRegisterCommand(F("RPN.RUNNERS"), [](const terminal::CommandContext& ctx) {
  601. if (!_rpn_runners.size()) {
  602. terminalError(ctx, F("No active runners"));
  603. return;
  604. }
  605. for (auto& runner : _rpn_runners) {
  606. char buffer[128] = {0};
  607. snprintf_P(buffer, sizeof(buffer), PSTR("%p %s %u ms, last %u ms"),
  608. &runner, (RpnRunner::Policy::Periodic == runner.policy) ? "every" : "one-shot",
  609. runner.period, runner.last
  610. );
  611. ctx.output.println(buffer);
  612. }
  613. terminalOK(ctx);
  614. });
  615. terminalRegisterCommand(F("RPN.VARS"), [](const terminal::CommandContext& ctx) {
  616. rpn_variables_foreach(_rpn_ctxt, [&ctx](const String& name, const rpn_value& value) {
  617. char buffer[256] = {0};
  618. snprintf_P(buffer, sizeof(buffer), PSTR(" %s: %s"), name.c_str(), _rpnValueToString(value).c_str());
  619. ctx.output.println(buffer);
  620. });
  621. terminalOK(ctx);
  622. });
  623. terminalRegisterCommand(F("RPN.OPS"), [](const terminal::CommandContext& ctx) {
  624. rpn_operators_foreach(_rpn_ctxt, [&ctx](const String& name, size_t argc, rpn_operator::callback_type) {
  625. char buffer[128] = {0};
  626. snprintf_P(buffer, sizeof(buffer), PSTR(" %s (%d)"), name.c_str(), argc);
  627. ctx.output.println(buffer);
  628. });
  629. terminalOK(ctx);
  630. });
  631. terminalRegisterCommand(F("RPN.TEST"), [](const terminal::CommandContext& ctx) {
  632. if (ctx.argc != 2) {
  633. terminalError(F("Wrong arguments"));
  634. return;
  635. }
  636. ctx.output.print(F("Running RPN expression: "));
  637. ctx.output.println(ctx.argv[1].c_str());
  638. if (!rpn_process(_rpn_ctxt, ctx.argv[1].c_str())) {
  639. rpn_stack_clear(_rpn_ctxt);
  640. char buffer[64] = {0};
  641. snprintf_P(buffer, sizeof(buffer), PSTR("position=%u category=%d code=%d"),
  642. _rpn_ctxt.error.position, static_cast<int>(_rpn_ctxt.error.category), _rpn_ctxt.error.code);
  643. terminalError(ctx, buffer);
  644. return;
  645. }
  646. _rpnShowStack(ctx.output);
  647. rpn_stack_clear(_rpn_ctxt);
  648. terminalOK(ctx);
  649. });
  650. }
  651. #endif
  652. // enables us to use rules without any events firing
  653. // notice: requires rpnRun to trigger at least once so that we can install runners
  654. void _rpnRunnersCheck() {
  655. auto ts = millis();
  656. for (auto& runner : _rpn_runners) {
  657. if (ts - runner.last >= runner.period) {
  658. runner.expired = true;
  659. runner.last = ts;
  660. _rpn_run = true;
  661. }
  662. }
  663. }
  664. void _rpnRunnersReset() {
  665. auto old = std::remove_if(_rpn_runners.begin(), _rpn_runners.end(), [](RpnRunner& runner) {
  666. return (RpnRunner::Policy::OneShot == runner.policy) && runner.expired;
  667. });
  668. if (old != _rpn_runners.end()) {
  669. _rpn_runners.erase(old, _rpn_runners.end());
  670. }
  671. for (auto& runner : _rpn_runners) {
  672. runner.expired = false;
  673. }
  674. }
  675. void _rpnRun() {
  676. if (!_rpn_run) {
  677. return;
  678. }
  679. if (millis() - _rpn_last <= _rpn_delay) {
  680. return;
  681. }
  682. _rpn_last = millis();
  683. _rpn_run = false;
  684. String rule;
  685. unsigned char i = 0;
  686. while ((rule = getSetting({"rpnRule", i++})).length()) {
  687. rpn_process(_rpn_ctxt, rule.c_str());
  688. rpn_stack_clear(_rpn_ctxt);
  689. }
  690. if (!getSetting("rpnSticky", 1 == RPN_STICKY)) {
  691. rpn_variables_clear(_rpn_ctxt);
  692. }
  693. }
  694. void _rpnLoop() {
  695. _rpnRunnersCheck();
  696. _rpnRun();
  697. _rpnRunnersReset();
  698. }
  699. void rpnSetup() {
  700. // Init context
  701. _rpnInit();
  702. // Load & cache settings
  703. _rpnConfigure();
  704. // Terminal commands
  705. #if TERMINAL_SUPPORT
  706. _rpnInitCommands();
  707. #endif
  708. // Websockets
  709. #if WEB_SUPPORT
  710. wsRegister()
  711. .onVisible([](JsonObject& root) { root["rpnVisible"] = 1; })
  712. .onConnected(_rpnWebSocketOnConnected)
  713. .onKeyCheck(_rpnWebSocketOnKeyCheck);
  714. #endif
  715. // MQTT
  716. #if MQTT_SUPPORT
  717. mqttRegister(_rpnMQTTCallback);
  718. #endif
  719. #if NTP_SUPPORT
  720. NtpBroker::Register([](const NtpTick tick, time_t timestamp, const String& datetime) {
  721. static const String tick_every_hour(F("tick1h"));
  722. static const String tick_every_minute(F("tick1m"));
  723. const char* ptr =
  724. (tick == NtpTick::EveryMinute) ? tick_every_minute.c_str() :
  725. (tick == NtpTick::EveryHour) ? tick_every_hour.c_str() : nullptr;
  726. if (ptr != nullptr) {
  727. rpn_value value { static_cast<rpn_int>(timestamp) };
  728. rpn_variable_set(_rpn_ctxt, ptr, value);
  729. _rpn_run = true;
  730. }
  731. });
  732. #endif
  733. StatusBroker::Register(_rpnBrokerStatus);
  734. #if RFB_SUPPORT
  735. _rpnRfbSetup();
  736. #endif
  737. #if SENSOR_SUPPORT
  738. SensorReadBroker::Register(_rpnBrokerCallback);
  739. #endif
  740. espurnaRegisterReload(_rpnConfigure);
  741. espurnaRegisterLoop(_rpnLoop);
  742. _rpn_last = millis();
  743. _rpn_run = true;
  744. }
  745. #endif // RPN_RULES_SUPPORT