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.

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