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.

1027 lines
30 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
providers: relays, lights and buttons refactoring (#2414) - gpio module now tracks the known providers (right now, hardware and mcp expander) - refactored relay struct to use 'Provider' implementing setup,notify,change,boot instead of just BasePin actions - refactored button module to use gpio provider instead of referencing types itself - removed dual & stm code from buttons, migrate both to relay module - added status notify and change callbacks for relayStatus (i.e. 'notify' when relay status was called, but not changed. and 'changed' when it did) - relays runtime configuration keys - relay command now shows configured relays and current & target statuses - refactor the code using relayStatus(0, blah) under LIGHT_PROVIDER check to use lightState instead - remove rfbridge code form relay module. implement through a basic state listener in the rfbridge module, depend on RELAY_SUPPORT - allow to bind rf codes to real relays - drop tuya-specific lights provider, remove tuya code from relays and lights modules - integrate tuya via relay listeners and providers, use lights custom provider - implement channel transitions for tuya. disabled by default, and transition time and step are overridden to 2000 + 100. needs to be set to some value below the total time (i.e. `total transition time / step time == number of steps`, we need to figure out a correct time that serial comms could handle) - lights custom provider (global, not per-pin) and state listeners - remove lights code from relay module. implement through providers & listeners in the lights module, depend on RELAY_SUPPORT - lights per-channel relay provider (unused atm), depend on RELAY_SUPPORT - refactored channel transition - calculate step only once, make sure time + step values are sane, generate quick transitions with very small delay (10ms hardcoded) for transitions during OFF state i.e. we no longer waste 500ms (or whatever transition time is set to) on boot doing nothing - transition time + step parameter for the lightUpdate - report mask parameter for the lightUpdate - minor fixes across the board resolve #2222
3 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
providers: relays, lights and buttons refactoring (#2414) - gpio module now tracks the known providers (right now, hardware and mcp expander) - refactored relay struct to use 'Provider' implementing setup,notify,change,boot instead of just BasePin actions - refactored button module to use gpio provider instead of referencing types itself - removed dual & stm code from buttons, migrate both to relay module - added status notify and change callbacks for relayStatus (i.e. 'notify' when relay status was called, but not changed. and 'changed' when it did) - relays runtime configuration keys - relay command now shows configured relays and current & target statuses - refactor the code using relayStatus(0, blah) under LIGHT_PROVIDER check to use lightState instead - remove rfbridge code form relay module. implement through a basic state listener in the rfbridge module, depend on RELAY_SUPPORT - allow to bind rf codes to real relays - drop tuya-specific lights provider, remove tuya code from relays and lights modules - integrate tuya via relay listeners and providers, use lights custom provider - implement channel transitions for tuya. disabled by default, and transition time and step are overridden to 2000 + 100. needs to be set to some value below the total time (i.e. `total transition time / step time == number of steps`, we need to figure out a correct time that serial comms could handle) - lights custom provider (global, not per-pin) and state listeners - remove lights code from relay module. implement through providers & listeners in the lights module, depend on RELAY_SUPPORT - lights per-channel relay provider (unused atm), depend on RELAY_SUPPORT - refactored channel transition - calculate step only once, make sure time + step values are sane, generate quick transitions with very small delay (10ms hardcoded) for transitions during OFF state i.e. we no longer waste 500ms (or whatever transition time is set to) on boot doing nothing - transition time + step parameter for the lightUpdate - report mask parameter for the lightUpdate - minor fixes across the board resolve #2222
3 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
providers: relays, lights and buttons refactoring (#2414) - gpio module now tracks the known providers (right now, hardware and mcp expander) - refactored relay struct to use 'Provider' implementing setup,notify,change,boot instead of just BasePin actions - refactored button module to use gpio provider instead of referencing types itself - removed dual & stm code from buttons, migrate both to relay module - added status notify and change callbacks for relayStatus (i.e. 'notify' when relay status was called, but not changed. and 'changed' when it did) - relays runtime configuration keys - relay command now shows configured relays and current & target statuses - refactor the code using relayStatus(0, blah) under LIGHT_PROVIDER check to use lightState instead - remove rfbridge code form relay module. implement through a basic state listener in the rfbridge module, depend on RELAY_SUPPORT - allow to bind rf codes to real relays - drop tuya-specific lights provider, remove tuya code from relays and lights modules - integrate tuya via relay listeners and providers, use lights custom provider - implement channel transitions for tuya. disabled by default, and transition time and step are overridden to 2000 + 100. needs to be set to some value below the total time (i.e. `total transition time / step time == number of steps`, we need to figure out a correct time that serial comms could handle) - lights custom provider (global, not per-pin) and state listeners - remove lights code from relay module. implement through providers & listeners in the lights module, depend on RELAY_SUPPORT - lights per-channel relay provider (unused atm), depend on RELAY_SUPPORT - refactored channel transition - calculate step only once, make sure time + step values are sane, generate quick transitions with very small delay (10ms hardcoded) for transitions during OFF state i.e. we no longer waste 500ms (or whatever transition time is set to) on boot doing nothing - transition time + step parameter for the lightUpdate - report mask parameter for the lightUpdate - minor fixes across the board resolve #2222
3 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
  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 "ntp_timelib.h"
  13. #include "relay.h"
  14. #include "rfbridge.h"
  15. #include "rpc.h"
  16. #include "rtcmem.h"
  17. #include "sensor.h"
  18. #include "terminal.h"
  19. #include "wifi.h"
  20. #include "ws.h"
  21. #include <list>
  22. #include <type_traits>
  23. #include <vector>
  24. // -----------------------------------------------------------------------------
  25. // Custom commands
  26. // -----------------------------------------------------------------------------
  27. rpn_context _rpn_ctxt;
  28. bool _rpn_run = false;
  29. unsigned long _rpn_delay = RPN_DELAY;
  30. unsigned long _rpn_last = 0;
  31. struct RpnRunner {
  32. enum class Policy {
  33. OneShot,
  34. Periodic
  35. };
  36. RpnRunner(Policy policy_, uint32_t period_) :
  37. policy(policy_),
  38. period(period_),
  39. last(millis())
  40. {}
  41. Policy policy { Policy::Periodic };
  42. uint32_t period { 0ul };
  43. uint32_t last { 0ul };
  44. bool expired { false };
  45. };
  46. std::vector<RpnRunner> _rpn_runners;
  47. rpn_operator_error _rpnRunnerHandler(rpn_context & ctxt, RpnRunner::Policy policy, uint32_t time) {
  48. for (auto& runner : _rpn_runners) {
  49. if ((policy == runner.policy) && (time == runner.period)) {
  50. return runner.expired
  51. ? rpn_operator_error::Ok
  52. : rpn_operator_error::CannotContinue;
  53. }
  54. }
  55. _rpn_runners.emplace_back(policy, time);
  56. return rpn_operator_error::CannotContinue;
  57. }
  58. // -----------------------------------------------------------------------------
  59. bool _rpnWebSocketOnKeyCheck(const char * key, JsonVariant& value) {
  60. return (strncmp(key, "rpn", 3) == 0);
  61. }
  62. void _rpnWebSocketOnConnected(JsonObject& root) {
  63. root["rpnSticky"] = getSetting("rpnSticky", 1 == RPN_STICKY);
  64. root["rpnDelay"] = getSetting("rpnDelay", RPN_DELAY);
  65. JsonArray& rules = root.createNestedArray("rpnRules");
  66. unsigned char i = 0;
  67. String rule = getSetting({"rpnRule", i});
  68. while (rule.length()) {
  69. rules.add(rule);
  70. rule = getSetting({"rpnRule", ++i});
  71. }
  72. #if MQTT_SUPPORT
  73. i=0;
  74. JsonArray& topics = root.createNestedArray("rpnTopics");
  75. JsonArray& names = root.createNestedArray("rpnNames");
  76. String rpn_topic = getSetting({"rpnTopic", i});
  77. while (rpn_topic.length() > 0) {
  78. String rpn_name = getSetting({"rpnName", i});
  79. topics.add(rpn_topic);
  80. names.add(rpn_name);
  81. rpn_topic = getSetting({"rpnTopic", ++i});
  82. }
  83. #endif
  84. }
  85. #if MQTT_SUPPORT
  86. void _rpnMQTTSubscribe() {
  87. unsigned char i = 0;
  88. String rpn_topic = getSetting({"rpnTopic", i});
  89. while (rpn_topic.length()) {
  90. mqttSubscribeRaw(rpn_topic.c_str());
  91. rpn_topic = getSetting({"rpnTopic", ++i});
  92. }
  93. }
  94. void _rpnMQTTCallback(unsigned int type, const char * topic, const char * payload) {
  95. if (type == MQTT_CONNECT_EVENT) {
  96. _rpnMQTTSubscribe();
  97. }
  98. if (type == MQTT_MESSAGE_EVENT) {
  99. unsigned char i = 0;
  100. String rpn_topic = getSetting({"rpnTopic", i});
  101. while (rpn_topic.length()) {
  102. if (rpn_topic.equals(topic)) {
  103. String rpn_name = getSetting({"rpnName", i});
  104. if (rpn_name.length()) {
  105. rpn_value value { atof(payload) };
  106. rpn_variable_set(_rpn_ctxt, rpn_name, value);
  107. _rpn_run = true;
  108. break;
  109. }
  110. }
  111. rpn_topic = getSetting({"rpnTopic", ++i});
  112. }
  113. }
  114. }
  115. #endif // MQTT_SUPPORT
  116. void _rpnConfigure() {
  117. #if MQTT_SUPPORT
  118. if (mqttConnected()) _rpnMQTTSubscribe();
  119. #endif
  120. _rpn_delay = getSetting("rpnDelay", RPN_DELAY);
  121. }
  122. void _rpnBrokerCallback(const String& topic, unsigned char id, double value, const char*) {
  123. char name[32] = {0};
  124. snprintf(name, sizeof(name), "%s%u", topic.c_str(), id);
  125. if (topic == MQTT_TOPIC_RELAY) {
  126. rpn_variable_set(_rpn_ctxt, name, rpn_value(static_cast<bool>(value)));
  127. } else {
  128. rpn_variable_set(_rpn_ctxt, name, rpn_value(value));
  129. }
  130. _rpn_run = true;
  131. }
  132. void _rpnBrokerStatus(const String& topic, unsigned char id, unsigned int value) {
  133. _rpnBrokerCallback(topic, id, double(value), nullptr);
  134. }
  135. #if NTP_SUPPORT
  136. namespace {
  137. constexpr bool time_t_is_32bit { sizeof(time_t) == 4 };
  138. constexpr bool time_t_is_64bit { sizeof(time_t) == 8 };
  139. static_assert(time_t_is_32bit || time_t_is_64bit, "");
  140. template <typename T>
  141. using split_t = std::integral_constant<bool, sizeof(T) == 8>;
  142. using RpnNtpFunc = rpn_int(*)(time_t);
  143. rpn_error _rpnNtpPopTimestampPair(rpn_context& ctxt, RpnNtpFunc func) {
  144. rpn_value rhs = rpn_stack_pop(ctxt);
  145. rpn_value lhs = rpn_stack_pop(ctxt);
  146. auto timestamp = (static_cast<long long>(lhs.toInt()) << 32ll)
  147. | (static_cast<long long>(rhs.toInt()));
  148. rpn_value value(func(timestamp));
  149. rpn_stack_push(ctxt, value);
  150. return 0;
  151. }
  152. rpn_error _rpnNtpPopTimestampSingle(rpn_context& ctxt, RpnNtpFunc func) {
  153. rpn_value input = rpn_stack_pop(ctxt);
  154. rpn_value result(func(input.toInt()));
  155. rpn_stack_push(ctxt, result);
  156. return 0;
  157. }
  158. void _rpnNtpPushTimestampPair(rpn_context& ctxt, time_t timestamp) {
  159. rpn_value lhs(static_cast<rpn_int>((static_cast<long long>(timestamp) >> 32ll) & 0xffffffffll));
  160. rpn_value rhs(static_cast<rpn_int>(static_cast<long long>(timestamp) & 0xffffffffll));
  161. rpn_stack_push(ctxt, lhs);
  162. rpn_stack_push(ctxt, rhs);
  163. }
  164. void _rpnNtpPushTimestampSingle(rpn_context& ctxt, time_t timestamp) {
  165. rpn_value result(static_cast<rpn_int>(timestamp));
  166. rpn_stack_push(ctxt, result);
  167. }
  168. inline rpn_error _rpnNtpPopTimestamp(const std::true_type&, rpn_context& ctxt, RpnNtpFunc func) {
  169. return _rpnNtpPopTimestampPair(ctxt, func);
  170. }
  171. inline rpn_error _rpnNtpPopTimestamp(const std::false_type&, rpn_context& ctxt, RpnNtpFunc func) {
  172. return _rpnNtpPopTimestampSingle(ctxt, func);
  173. }
  174. rpn_error _rpnNtpPopTimestamp(rpn_context& ctxt, RpnNtpFunc func) {
  175. return _rpnNtpPopTimestamp(split_t<time_t>{}, ctxt, func);
  176. }
  177. inline void _rpnNtpPushTimestamp(const std::true_type&, rpn_context& ctxt, time_t timestamp) {
  178. _rpnNtpPushTimestampPair(ctxt, timestamp);
  179. }
  180. inline void _rpnNtpPushTimestamp(const std::false_type&, rpn_context& ctxt, time_t timestamp) {
  181. _rpnNtpPushTimestampSingle(ctxt, timestamp);
  182. }
  183. void _rpnNtpPushTimestamp(rpn_context& ctxt, time_t timestamp) {
  184. _rpnNtpPushTimestamp(split_t<time_t>{}, ctxt, timestamp);
  185. }
  186. rpn_error _rpnNtpNow(rpn_context & ctxt) {
  187. if (ntpSynced()) {
  188. _rpnNtpPushTimestamp(ctxt, now());
  189. return 0;
  190. }
  191. return rpn_operator_error::CannotContinue;
  192. }
  193. rpn_error _rpnNtpFunc(rpn_context & ctxt, RpnNtpFunc func) {
  194. return _rpnNtpPopTimestamp(ctxt, func);
  195. }
  196. bool _rpn_ntp_tick_minute { false };
  197. bool _rpn_ntp_tick_hour { false };
  198. rpn_error _rpnNtpTickMinute(rpn_context& ctxt) {
  199. if (_rpn_ntp_tick_minute) {
  200. _rpn_ntp_tick_minute = false;
  201. return 0;
  202. }
  203. return rpn_operator_error::CannotContinue;
  204. }
  205. rpn_error _rpnNtpTickHour(rpn_context& ctxt) {
  206. if (_rpn_ntp_tick_hour) {
  207. _rpn_ntp_tick_hour = false;
  208. return 0;
  209. }
  210. return rpn_operator_error::CannotContinue;
  211. }
  212. } // namespace
  213. #endif // NTP_SUPPORT
  214. String _rpnValueToString(const rpn_value& value) {
  215. String out;
  216. if (value.isString()) {
  217. out = value.toString();
  218. } else if (value.isFloat()) {
  219. out = String(value.toFloat(), 10);
  220. } else if (value.isInt()) {
  221. out = String(value.toInt(), 10);
  222. } else if (value.isUint()) {
  223. out = String(value.toUint(), 10);
  224. } else if (value.isBoolean()) {
  225. out = String(value.toBoolean() ? "true" : "false");
  226. } else if (value.isNull()) {
  227. out = F("(null)");
  228. }
  229. return out;
  230. }
  231. char _rpnStackTypeTag(rpn_stack_value::Type type) {
  232. switch (type) {
  233. case rpn_stack_value::Type::None:
  234. return 'N';
  235. case rpn_stack_value::Type::Variable:
  236. return '$';
  237. case rpn_stack_value::Type::Array:
  238. return 'A';
  239. case rpn_stack_value::Type::Value:
  240. default:
  241. return ' ';
  242. }
  243. }
  244. #if RELAY_SUPPORT
  245. rpn_error _rpnRelayStatus(rpn_context & ctxt, bool force) {
  246. rpn_value id;
  247. rpn_value status;
  248. rpn_stack_pop(ctxt, id);
  249. rpn_stack_pop(ctxt, status);
  250. rpn_uint value = status.toUint();
  251. if (value == 2) {
  252. relayToggle(id.toUint());
  253. } else if (relayStatusTarget(id.toUint()) != (value == 1)) {
  254. relayStatus(id.toUint(), value == 1);
  255. }
  256. return 0;
  257. }
  258. #endif // RELAY_SUPPORT
  259. #if RFB_SUPPORT
  260. struct rpn_rfbridge_code {
  261. unsigned char protocol;
  262. String raw;
  263. size_t count;
  264. decltype(millis()) last;
  265. };
  266. // TODO: in theory, we could do with forward_list. however, this would require a more complicated removal process,
  267. // as we would no longer know the previous element and would need to track 2 elements at a time
  268. static std::list<rpn_rfbridge_code> _rfb_codes;
  269. static uint32_t _rfb_code_repeat_window;
  270. static uint32_t _rfb_code_stale_delay;
  271. static uint32_t _rfb_code_match_window;
  272. struct rpn_rfbridge_match {
  273. unsigned char protocol;
  274. String raw;
  275. };
  276. rpn_error _rpnRfbSequence(rpn_context& ctxt) {
  277. auto raw_second = rpn_stack_pop(ctxt);
  278. auto proto_second = rpn_stack_pop(ctxt);
  279. auto raw_first = rpn_stack_pop(ctxt);
  280. auto proto_first = rpn_stack_pop(ctxt);
  281. // find 2 codes in the same order and save pointers
  282. rpn_rfbridge_match match[2] {
  283. {static_cast<unsigned char>(proto_first.toUint()), raw_first.toString()},
  284. {static_cast<unsigned char>(proto_second.toUint()), raw_second.toString()}
  285. };
  286. rpn_rfbridge_code* refs[2] {nullptr, nullptr};
  287. for (auto& recent : _rfb_codes) {
  288. if ((refs[0] != nullptr) && (refs[1] != nullptr)) {
  289. break;
  290. }
  291. for (int index = 0; index < 2; ++index) {
  292. if ((refs[index] == nullptr)
  293. && (match[index].protocol == recent.protocol)
  294. && (match[index].raw == recent.raw)) {
  295. refs[index] = &recent;
  296. }
  297. }
  298. }
  299. if ((refs[0] == nullptr) || (refs[1] == nullptr)) {
  300. return rpn_operator_error::CannotContinue;
  301. }
  302. // purge codes to avoid matching again on the next rules run
  303. if ((millis() - refs[0]->last) > (millis() - refs[1]->last)) {
  304. _rfb_codes.remove_if([&refs](rpn_rfbridge_code& code) {
  305. return (refs[0] == &code) || (refs[1] == &code);
  306. });
  307. return rpn_operator_error::Ok;
  308. }
  309. return rpn_operator_error::CannotContinue;
  310. }
  311. decltype(_rfb_codes)::iterator _rpnRfbFindCode(unsigned char protocol, const String& match) {
  312. return std::find_if(_rfb_codes.begin(), _rfb_codes.end(), [protocol, &match](const rpn_rfbridge_code& code) {
  313. return (code.protocol == protocol) && (code.raw == match);
  314. });
  315. }
  316. rpn_error _rpnRfbPop(rpn_context& ctxt) {
  317. auto code = rpn_stack_pop(ctxt);
  318. auto proto = rpn_stack_pop(ctxt);
  319. auto result = _rpnRfbFindCode(proto.toUint(), code.toString());
  320. if (result == _rfb_codes.end()) {
  321. return rpn_operator_error::CannotContinue;
  322. }
  323. _rfb_codes.erase(result);
  324. return rpn_operator_error::Ok;
  325. }
  326. rpn_error _rpnRfbInfo(rpn_context& ctxt) {
  327. auto code = rpn_stack_pop(ctxt);
  328. auto proto = rpn_stack_pop(ctxt);
  329. auto result = _rpnRfbFindCode(proto.toUint(), code.toString());
  330. if (result == _rfb_codes.end()) {
  331. return rpn_operator_error::CannotContinue;
  332. }
  333. rpn_stack_push(ctxt, rpn_value(
  334. static_cast<rpn_uint>((*result).count)));
  335. rpn_stack_push(ctxt, rpn_value(
  336. static_cast<rpn_uint>((*result).last)));
  337. return rpn_operator_error::Ok;
  338. }
  339. rpn_error _rpnRfbWaitMatch(rpn_context& ctxt) {
  340. auto code = rpn_stack_pop(ctxt);
  341. auto proto = rpn_stack_pop(ctxt);
  342. auto count = rpn_stack_pop(ctxt);
  343. auto time = rpn_stack_pop(ctxt);
  344. auto result = _rpnRfbFindCode(proto.toUint(), code.toString());
  345. if (result == _rfb_codes.end()) {
  346. return rpn_operator_error::CannotContinue;
  347. }
  348. if ((*result).count < count.toUint()) {
  349. return rpn_operator_error::CannotContinue;
  350. }
  351. // purge code to avoid matching again on the next rules run
  352. if (rpn_operator_error::Ok == _rpnRunnerHandler(ctxt, RpnRunner::Policy::OneShot, time.toUint())) {
  353. _rfb_codes.erase(result);
  354. return rpn_operator_error::Ok;
  355. }
  356. return rpn_operator_error::CannotContinue;
  357. }
  358. rpn_error _rpnRfbMatcher(rpn_context& ctxt) {
  359. auto code = rpn_stack_pop(ctxt);
  360. auto proto = rpn_stack_pop(ctxt);
  361. auto count = rpn_stack_pop(ctxt);
  362. auto result = _rpnRfbFindCode(proto.toUint(), code.toString());
  363. if (result == _rfb_codes.end()) {
  364. return rpn_operator_error::CannotContinue;
  365. }
  366. // only process recent codes, ignore when rule is processing outside of this small window
  367. if (millis() - (*result).last >= _rfb_code_match_window) {
  368. return rpn_operator_error::CannotContinue;
  369. }
  370. // purge code to avoid matching again on the next rules run
  371. if ((*result).count == count.toUint()) {
  372. _rfb_codes.erase(result);
  373. return rpn_operator_error::Ok;
  374. }
  375. return rpn_operator_error::CannotContinue;
  376. }
  377. void _rpnBrokerRfbridgeCallback(unsigned char protocol, const char* raw_code) {
  378. // remove really old codes that we have not seen in a while to avoid memory exhaustion
  379. auto ts = millis();
  380. auto old = std::remove_if(_rfb_codes.begin(), _rfb_codes.end(), [ts](rpn_rfbridge_code& code) {
  381. return (ts - code.last) >= _rfb_code_stale_delay;
  382. });
  383. if (old != _rfb_codes.end()) {
  384. _rfb_codes.erase(old, _rfb_codes.end());
  385. }
  386. auto result = _rpnRfbFindCode(protocol, raw_code);
  387. if (result != _rfb_codes.end()) {
  388. // we also need to reset the counter at a certain point to allow next batch of repeats to go through
  389. if (millis() - (*result).last >= _rfb_code_repeat_window) {
  390. (*result).count = 0;
  391. }
  392. (*result).last = millis();
  393. (*result).count += 1u;
  394. } else {
  395. _rfb_codes.push_back({protocol, raw_code, 1u, millis()});
  396. }
  397. _rpn_run = true;
  398. }
  399. void _rpnRfbSetup() {
  400. // - Repeat window is an arbitrary time, just about 3-4 more times it takes for
  401. // a code to be sent again when holding a generic remote button
  402. // Code counter is reset to 0 when outside of the window.
  403. // - Stale delay allows broker callback to remove really old codes.
  404. // (TODO: can this happen in loop() cb instead?)
  405. _rfb_code_repeat_window = getSetting("rfbRepeatWindow", 2000ul);
  406. _rfb_code_match_window = getSetting("rfbMatchWindow", 2000ul);
  407. _rfb_code_stale_delay = getSetting("rfbStaleDelay", 10000ul);
  408. #if TERMINAL_SUPPORT
  409. terminalRegisterCommand(F("RFB.CODES"), [](const terminal::CommandContext& ctx) {
  410. for (auto& code : _rfb_codes) {
  411. char buffer[128] = {0};
  412. snprintf_P(buffer, sizeof(buffer),
  413. PSTR("proto=%u raw=\"%s\" count=%u last=%u"),
  414. code.protocol,
  415. code.raw.c_str(),
  416. code.count,
  417. code.last
  418. );
  419. ctx.output.println(buffer);
  420. }
  421. });
  422. #endif
  423. // Main bulk of the processing goes on in here
  424. RfbridgeBroker::Register(_rpnBrokerRfbridgeCallback);
  425. }
  426. #endif // RFB_SUPPORT
  427. void _rpnShowStack(Print& print) {
  428. print.println(F("Stack:"));
  429. auto index = rpn_stack_size(_rpn_ctxt);
  430. if (!index) {
  431. print.println(F(" (empty)"));
  432. return;
  433. }
  434. rpn_stack_foreach(_rpn_ctxt, [&index, &print](rpn_stack_value::Type type, const rpn_value& value) {
  435. print.printf("%c %02u: %s\n",
  436. _rpnStackTypeTag(type), index--,
  437. _rpnValueToString(value).c_str()
  438. );
  439. });
  440. }
  441. void _rpnInit() {
  442. // Init context
  443. rpn_init(_rpn_ctxt);
  444. // Time functions need NTP support
  445. // TODO: since 1.15.0, timelib+ntpclientlib are no longer used with latest Cores
  446. // `now` is always in UTC, `utc_...` functions to be used instead to convert time
  447. #if NTP_SUPPORT && !NTP_LEGACY_SUPPORT
  448. {
  449. constexpr size_t time_t_argc { split_t<time_t>{} ? 2 : 1 };
  450. rpn_operator_set(_rpn_ctxt, "tick_1h", 0, _rpnNtpTickHour);
  451. rpn_operator_set(_rpn_ctxt, "tick_1m", 0, _rpnNtpTickMinute);
  452. rpn_operator_set(_rpn_ctxt, "utc", 0, _rpnNtpNow);
  453. rpn_operator_set(_rpn_ctxt, "now", 0, _rpnNtpNow);
  454. rpn_operator_set(_rpn_ctxt, "utc_month", time_t_argc, [](rpn_context & ctxt) {
  455. return _rpnNtpFunc(ctxt, utc_month);
  456. });
  457. rpn_operator_set(_rpn_ctxt, "month", time_t_argc, [](rpn_context & ctxt) {
  458. return _rpnNtpFunc(ctxt, month);
  459. });
  460. rpn_operator_set(_rpn_ctxt, "utc_day", time_t_argc, [](rpn_context & ctxt) {
  461. return _rpnNtpFunc(ctxt, utc_day);
  462. });
  463. rpn_operator_set(_rpn_ctxt, "day", time_t_argc, [](rpn_context & ctxt) {
  464. return _rpnNtpFunc(ctxt, day);
  465. });
  466. rpn_operator_set(_rpn_ctxt, "utc_dow", time_t_argc, [](rpn_context & ctxt) {
  467. return _rpnNtpFunc(ctxt, utc_weekday);
  468. });
  469. rpn_operator_set(_rpn_ctxt, "dow", time_t_argc, [](rpn_context & ctxt) {
  470. return _rpnNtpFunc(ctxt, weekday);
  471. });
  472. rpn_operator_set(_rpn_ctxt, "utc_hour", time_t_argc, [](rpn_context & ctxt) {
  473. return _rpnNtpFunc(ctxt, utc_hour);
  474. });
  475. rpn_operator_set(_rpn_ctxt, "hour", time_t_argc, [](rpn_context & ctxt) {
  476. return _rpnNtpFunc(ctxt, hour);
  477. });
  478. rpn_operator_set(_rpn_ctxt, "utc_minute", time_t_argc, [](rpn_context & ctxt) {
  479. return _rpnNtpFunc(ctxt, utc_minute);
  480. });
  481. rpn_operator_set(_rpn_ctxt, "minute", time_t_argc, [](rpn_context & ctxt) {
  482. return _rpnNtpFunc(ctxt, minute);
  483. });
  484. }
  485. #endif
  486. // TODO: 1.14.0 weekday(...) conversion seemed to have 0..6 range with Monday as 0
  487. // using classic Sunday as first, but instead of 0 it is 1
  488. // Implementation above also uses 1 for Sunday, staying compatible with TimeLib
  489. #if NTP_SUPPORT && NTP_LEGACY_SUPPORT
  490. rpn_operator_set(_rpn_ctxt, "utc", 0, [](rpn_context & ctxt) -> rpn_error {
  491. if (!ntpSynced()) return rpn_operator_error::CannotContinue;
  492. rpn_value ts { static_cast<rpn_int>(ntpLocal2UTC(now())) };
  493. rpn_stack_push(ctxt, ts);
  494. return 0;
  495. });
  496. rpn_operator_set(_rpn_ctxt, "now", 0, _rpnNtpNow);
  497. rpn_operator_set(_rpn_ctxt, "month", 1, [](rpn_context & ctxt) {
  498. return _rpnNtpFunc(ctxt, month);
  499. });
  500. rpn_operator_set(_rpn_ctxt, "day", 1, [](rpn_context & ctxt) {
  501. return _rpnNtpFunc(ctxt, day);
  502. });
  503. rpn_operator_set(_rpn_ctxt, "dow", 1, [](rpn_context & ctxt) {
  504. return _rpnNtpFunc(ctxt, weekday);
  505. });
  506. rpn_operator_set(_rpn_ctxt, "hour", 1, [](rpn_context & ctxt) {
  507. return _rpnNtpFunc(ctxt, hour);
  508. });
  509. rpn_operator_set(_rpn_ctxt, "minute", 1, [](rpn_context & ctxt) {
  510. return _rpnNtpFunc(ctxt, minute);
  511. });
  512. #endif
  513. // Accept relay number and numeric API status value (0, 1 and 2)
  514. #if RELAY_SUPPORT
  515. // apply status and reset timers when called
  516. rpn_operator_set(_rpn_ctxt, "relay_reset", 2, [](rpn_context & ctxt) {
  517. return _rpnRelayStatus(ctxt, true);
  518. });
  519. // only update status when target status differs, keep running timers
  520. rpn_operator_set(_rpn_ctxt, "relay", 2, [](rpn_context & ctxt) {
  521. return _rpnRelayStatus(ctxt, false);
  522. });
  523. #endif // RELAY_SUPPORT == 1
  524. // Channel operators
  525. #if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
  526. rpn_operator_set(_rpn_ctxt, "update", 0, [](rpn_context & ctxt) -> rpn_error {
  527. lightUpdate();
  528. return 0;
  529. });
  530. rpn_operator_set(_rpn_ctxt, "black", 0, [](rpn_context & ctxt) -> rpn_error {
  531. lightColor(0ul);
  532. return 0;
  533. });
  534. rpn_operator_set(_rpn_ctxt, "channel", 2, [](rpn_context & ctxt) -> rpn_error {
  535. rpn_value value;
  536. rpn_value id;
  537. rpn_stack_pop(ctxt, id);
  538. rpn_stack_pop(ctxt, value);
  539. lightChannel(id.toUint(), id.toInt());
  540. return 0;
  541. });
  542. #endif
  543. #if RFB_SUPPORT
  544. rpn_operator_set(_rpn_ctxt, "rfb_pop", 2, _rpnRfbPop);
  545. rpn_operator_set(_rpn_ctxt, "rfb_info", 2, _rpnRfbInfo);
  546. rpn_operator_set(_rpn_ctxt, "rfb_sequence", 4, _rpnRfbSequence);
  547. rpn_operator_set(_rpn_ctxt, "rfb_match", 3, _rpnRfbMatcher);
  548. rpn_operator_set(_rpn_ctxt, "rfb_match_wait", 4, _rpnRfbWaitMatch);
  549. #endif
  550. #if MQTT_SUPPORT
  551. rpn_operator_set(_rpn_ctxt, "mqtt_send", 2, [](rpn_context & ctxt) -> rpn_error {
  552. rpn_value message;
  553. rpn_stack_pop(ctxt, message);
  554. rpn_value topic;
  555. rpn_stack_pop(ctxt, topic);
  556. return mqttSendRaw(topic.toString().c_str(), message.toString().c_str())
  557. ? rpn_operator_error::Ok
  558. : rpn_operator_error::CannotContinue;
  559. });
  560. #endif
  561. // Some debugging. Dump stack contents
  562. #if TERMINAL_SUPPORT
  563. rpn_operator_set(_rpn_ctxt, "showstack", 0, [](rpn_context & ctxt) -> rpn_error {
  564. _rpnShowStack(terminalDefaultStream());
  565. return 0;
  566. });
  567. #endif
  568. // And, simple string logging
  569. #if DEBUG_SUPPORT
  570. rpn_operator_set(_rpn_ctxt, "dbgmsg", 1, [](rpn_context & ctxt) -> rpn_error {
  571. rpn_value message;
  572. rpn_stack_pop(ctxt, message);
  573. DEBUG_MSG_P(PSTR("[RPN] %s\n"), message.toString().c_str());
  574. return 0;
  575. });
  576. #endif
  577. rpn_operator_set(_rpn_ctxt, "mem?", 0, [](rpn_context & ctxt) -> rpn_error {
  578. rpn_stack_push(ctxt, rpn_value(rtcmemStatus()));
  579. return 0;
  580. });
  581. rpn_operator_set(_rpn_ctxt, "mem_write", 2, [](rpn_context & ctxt) -> rpn_error {
  582. auto addr = rpn_stack_pop(ctxt).toUint();
  583. auto value = rpn_stack_pop(ctxt).toUint();
  584. if (addr < RTCMEM_BLOCKS) {
  585. auto* rtcmem = reinterpret_cast<volatile uint32_t*>(RTCMEM_ADDR);
  586. *(rtcmem + addr) = value;
  587. return 0;
  588. }
  589. return rpn_operator_error::InvalidArgument;
  590. });
  591. rpn_operator_set(_rpn_ctxt, "mem_read", 1, [](rpn_context & ctxt) -> rpn_error {
  592. auto addr = rpn_stack_pop(ctxt).toUint();
  593. if (addr < RTCMEM_BLOCKS) {
  594. auto* rtcmem = reinterpret_cast<volatile uint32_t*>(RTCMEM_ADDR);
  595. rpn_uint result = *(rtcmem + addr);
  596. rpn_stack_push(ctxt, rpn_value(result));
  597. return 0;
  598. }
  599. return rpn_operator_error::InvalidArgument;
  600. });
  601. rpn_operator_set(_rpn_ctxt, "sleep", 2, [](rpn_context & ctxt) -> rpn_error {
  602. static bool once { false };
  603. if (once) return rpn_operator_error::CannotContinue;
  604. auto value = rpn_stack_pop(ctxt).checkedToUint();
  605. if (!value.ok()) {
  606. return value.error();
  607. }
  608. uint64_t duration = value.value();
  609. if (!duration) {
  610. return rpn_operator_error::CannotContinue;
  611. }
  612. auto mode = rpn_stack_pop(ctxt).toUint();
  613. once = true;
  614. schedule_function([duration, mode]() {
  615. wifiTurnOff();
  616. ESP.deepSleep(duration * 1000000ull, static_cast<RFMode>(mode));
  617. });
  618. return 0;
  619. });
  620. rpn_operator_set(_rpn_ctxt, "stations", 0, [](rpn_context & ctxt) -> rpn_error {
  621. if (!(WiFi.getMode() & WIFI_AP)) return rpn_operator_error::CannotContinue;
  622. rpn_stack_push(ctxt, rpn_value(static_cast<rpn_uint>(WiFi.softAPgetStationNum())));
  623. return 0;
  624. });
  625. rpn_operator_set(_rpn_ctxt, "disconnect", 0, [](rpn_context & ctxt) -> rpn_error {
  626. wifiDisconnect();
  627. yield();
  628. return 0;
  629. });
  630. rpn_operator_set(_rpn_ctxt, "rssi", 0, [](rpn_context & ctxt) -> rpn_error {
  631. if (!wifiConnected()) return rpn_operator_error::CannotContinue;
  632. rpn_stack_push(ctxt, rpn_value(static_cast<rpn_int>(WiFi.RSSI())));
  633. return 0;
  634. });
  635. rpn_operator_set(_rpn_ctxt, "delay", 1, [](rpn_context & ctxt) -> rpn_error {
  636. auto ms = rpn_stack_pop(ctxt);
  637. delay(ms.toUint());
  638. return 0;
  639. });
  640. rpn_operator_set(_rpn_ctxt, "yield", 0, [](rpn_context & ctxt) -> rpn_error {
  641. yield();
  642. return 0;
  643. });
  644. rpn_operator_set(_rpn_ctxt, "reset", 0, [](rpn_context & ctxt) -> rpn_error {
  645. static bool once = ([]() {
  646. deferredReset(100, CustomResetReason::Rule);
  647. return true;
  648. })();
  649. return once
  650. ? rpn_operator_error::CannotContinue
  651. : rpn_operator_error::Ok;
  652. });
  653. rpn_operator_set(_rpn_ctxt, "millis", 0, [](rpn_context & ctxt) -> rpn_error {
  654. rpn_stack_push(ctxt, rpn_value(static_cast<uint32_t>(millis())));
  655. return 0;
  656. });
  657. rpn_operator_set(_rpn_ctxt, "oneshot_ms", 1, [](rpn_context & ctxt) -> rpn_error {
  658. auto every = rpn_stack_pop(ctxt);
  659. return _rpnRunnerHandler(ctxt, RpnRunner::Policy::OneShot, every.toUint());
  660. });
  661. rpn_operator_set(_rpn_ctxt, "every_ms", 1, [](rpn_context & ctxt) -> rpn_error {
  662. auto every = rpn_stack_pop(ctxt);
  663. return _rpnRunnerHandler(ctxt, RpnRunner::Policy::Periodic, every.toUint());
  664. });
  665. // XXX: workaround for the vector 2x growth on push. will need to fix this in the rpnlib
  666. _rpn_ctxt.operators.shrink_to_fit();
  667. DEBUG_MSG_P(PSTR("[RPN] Registered %u operators\n"), _rpn_ctxt.operators.size());
  668. }
  669. #if TERMINAL_SUPPORT
  670. void _rpnInitCommands() {
  671. terminalRegisterCommand(F("RPN.RUNNERS"), [](const terminal::CommandContext& ctx) {
  672. if (!_rpn_runners.size()) {
  673. terminalError(ctx, F("No active runners"));
  674. return;
  675. }
  676. for (auto& runner : _rpn_runners) {
  677. char buffer[128] = {0};
  678. snprintf_P(buffer, sizeof(buffer), PSTR("%p %s %u ms, last %u ms"),
  679. &runner, (RpnRunner::Policy::Periodic == runner.policy) ? "every" : "one-shot",
  680. runner.period, runner.last
  681. );
  682. ctx.output.println(buffer);
  683. }
  684. terminalOK(ctx);
  685. });
  686. terminalRegisterCommand(F("RPN.VARS"), [](const terminal::CommandContext& ctx) {
  687. rpn_variables_foreach(_rpn_ctxt, [&ctx](const String& name, const rpn_value& value) {
  688. char buffer[256] = {0};
  689. snprintf_P(buffer, sizeof(buffer), PSTR(" %s: %s"), name.c_str(), _rpnValueToString(value).c_str());
  690. ctx.output.println(buffer);
  691. });
  692. terminalOK(ctx);
  693. });
  694. terminalRegisterCommand(F("RPN.OPS"), [](const terminal::CommandContext& ctx) {
  695. rpn_operators_foreach(_rpn_ctxt, [&ctx](const String& name, size_t argc, rpn_operator::callback_type) {
  696. char buffer[128] = {0};
  697. snprintf_P(buffer, sizeof(buffer), PSTR(" %s (%d)"), name.c_str(), argc);
  698. ctx.output.println(buffer);
  699. });
  700. terminalOK(ctx);
  701. });
  702. terminalRegisterCommand(F("RPN.TEST"), [](const terminal::CommandContext& ctx) {
  703. if (ctx.argc != 2) {
  704. terminalError(F("Wrong arguments"));
  705. return;
  706. }
  707. ctx.output.print(F("Running RPN expression: "));
  708. ctx.output.println(ctx.argv[1].c_str());
  709. if (!rpn_process(_rpn_ctxt, ctx.argv[1].c_str())) {
  710. rpn_stack_clear(_rpn_ctxt);
  711. char buffer[64] = {0};
  712. snprintf_P(buffer, sizeof(buffer), PSTR("position=%u category=%d code=%d"),
  713. _rpn_ctxt.error.position, static_cast<int>(_rpn_ctxt.error.category), _rpn_ctxt.error.code);
  714. terminalError(ctx, buffer);
  715. return;
  716. }
  717. _rpnShowStack(ctx.output);
  718. rpn_stack_clear(_rpn_ctxt);
  719. terminalOK(ctx);
  720. });
  721. }
  722. #endif
  723. // enables us to use rules without any events firing
  724. // notice: requires rpnRun to trigger at least once so that we can install runners
  725. void _rpnRunnersCheck() {
  726. auto ts = millis();
  727. for (auto& runner : _rpn_runners) {
  728. if (ts - runner.last >= runner.period) {
  729. runner.expired = true;
  730. runner.last = ts;
  731. _rpn_run = true;
  732. }
  733. }
  734. }
  735. void _rpnRunnersReset() {
  736. auto old = std::remove_if(_rpn_runners.begin(), _rpn_runners.end(), [](RpnRunner& runner) {
  737. return (RpnRunner::Policy::OneShot == runner.policy) && runner.expired;
  738. });
  739. if (old != _rpn_runners.end()) {
  740. _rpn_runners.erase(old, _rpn_runners.end());
  741. }
  742. for (auto& runner : _rpn_runners) {
  743. runner.expired = false;
  744. }
  745. }
  746. void _rpnRun() {
  747. if (!_rpn_run) {
  748. return;
  749. }
  750. if (millis() - _rpn_last <= _rpn_delay) {
  751. return;
  752. }
  753. _rpn_last = millis();
  754. _rpn_run = false;
  755. String rule;
  756. unsigned char i = 0;
  757. while ((rule = getSetting({"rpnRule", i++})).length()) {
  758. rpn_process(_rpn_ctxt, rule.c_str());
  759. rpn_stack_clear(_rpn_ctxt);
  760. }
  761. if (!getSetting("rpnSticky", 1 == RPN_STICKY)) {
  762. rpn_variables_clear(_rpn_ctxt);
  763. }
  764. }
  765. void _rpnLoop() {
  766. _rpnRunnersCheck();
  767. _rpnRun();
  768. _rpnRunnersReset();
  769. }
  770. void rpnSetup() {
  771. // Init context
  772. _rpnInit();
  773. // Load & cache settings
  774. _rpnConfigure();
  775. // Terminal commands
  776. #if TERMINAL_SUPPORT
  777. _rpnInitCommands();
  778. #endif
  779. // Websockets
  780. #if WEB_SUPPORT
  781. wsRegister()
  782. .onVisible([](JsonObject& root) { root["rpnVisible"] = 1; })
  783. .onConnected(_rpnWebSocketOnConnected)
  784. .onKeyCheck(_rpnWebSocketOnKeyCheck);
  785. #endif
  786. // MQTT
  787. #if MQTT_SUPPORT
  788. mqttRegister(_rpnMQTTCallback);
  789. #endif
  790. #if NTP_SUPPORT
  791. NtpBroker::Register([](NtpTick tick, time_t, const String&) {
  792. switch (tick) {
  793. case NtpTick::EveryMinute:
  794. _rpn_ntp_tick_minute = true;
  795. break;
  796. case NtpTick::EveryHour:
  797. _rpn_ntp_tick_hour = true;
  798. break;
  799. }
  800. _rpn_run = true;
  801. });
  802. #endif
  803. StatusBroker::Register(_rpnBrokerStatus);
  804. #if RFB_SUPPORT
  805. _rpnRfbSetup();
  806. #endif
  807. #if SENSOR_SUPPORT
  808. SensorReadBroker::Register(_rpnBrokerCallback);
  809. #endif
  810. espurnaRegisterReload(_rpnConfigure);
  811. espurnaRegisterLoop(_rpnLoop);
  812. _rpn_last = millis();
  813. _rpn_run = true;
  814. }
  815. #endif // RPN_RULES_SUPPORT