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

934 lines
28 KiB

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