diff --git a/README.md b/README.md index e73523234..79254bda8 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ ```ini lib_deps = - SignalK/SensESP @ >=3.0.0-beta.1,<4 + SignalK/SensESP @ >=3.0.0-beta.2,<4 # https://github.com/SignalK/SensESP.git # Use this line to use the latest git version # symlink:///Users/mairas/src/SignalK/SensESP # Use this line to use a local copy ``` @@ -95,10 +95,29 @@ - The `reactesp` namespace is no longer imported. If you have any references to classes in this namespace, you will need to update them to use the namespace - explicitly. For example, `ReactESP` class should be referred to as - `reactesp::ReactESP`. In particular, this change probably needs to be made + explicitly. + + Additionally, ReactESP classes have been renamed: + + - `ReactESP` -> `reactesp::EventLoop` + - `*Reaction` -> `reactesp::*Event` + + For example, `ReactESP` class should be referred to as + `reactesp::EventLoop`. In particular, this change probably needs to be made in your project's `main.cpp` file. +- `ReactESP` is no longer a singleton. Earlier, you could refer to the singleton + instance of `ReactESP` using `ReactESP::app`. Now, the object pointer is + maintained by the `SensESPBaseApp` class, and you can refer to it using + `sensesp_app->get_event_loop()`. For example: + + ```cpp + SensESPBaseApp::get_event_loop()->onRepeat( + 1000, + []() { Serial.println("Hello, world!"); } + ); + ``` + ### Development The frontend project is in the `frontend` directory tree. To build the frontend, diff --git a/docs/pages/concepts/index.md b/docs/pages/concepts/index.md index 4dff434c5..2068c22a3 100644 --- a/docs/pages/concepts/index.md +++ b/docs/pages/concepts/index.md @@ -36,7 +36,7 @@ void setup() { // initialize the GPIO pin pinMode(kGpioPin, OUTPUT); - // create the repeat reaction + // create the repeat event app.onRepeat(interval, toggle_gpio); // setup continues @@ -47,18 +47,18 @@ void setup() { What happens in the above example? We define a callback function `toggle_gpio()`. Then, we set the pin mode to OUTPUT. -And finally, we create a repeat reaction with the interval `interval`. +And finally, we create a repeat event with the interval `interval`. -Once the program is running, the repeat reaction is triggered automatically every 350 milliseconds. +Once the program is running, the repeat event is triggered automatically every 350 milliseconds. The interval is calculated from the previous trigger time - if the callback function takes 4 milliseconds to complete, the actual interval still remains 350 ms instead of 354 ms. -Another commonly used and useful time-based reaction is `DelayReaction`. +Another commonly used and useful time-based event is `DelayEvent`. It triggers after a certain amount of time has passed but does not repeat. Example use cases for that would be sensor devices in which you trigger the read operation and then come back to get the value after a certain amount of time. For example, the 1-Wire DS18B20 sensor can take up to 750 ms before the conversion is ready. In that case, you would first trigger the call and then have something like `app.onDelay(750, read_sensor);` to come back later to read the value. -You can also use `app.onDelay(...)` with a zero delay to trigger the reaction as soon as possible, without blocking the main event loop. +You can also use `app.onDelay(...)` with a zero delay to trigger the event as soon as possible, without blocking the main event loop. ### Lambdas @@ -77,7 +77,7 @@ void setup() { // initialize the GPIO pin pinMode(kGpioPin, OUTPUT); - // create the repeat reaction + // create the repeat event app.onRepeat( interval, []() { @@ -97,25 +97,25 @@ The brackets `[]` define the start of the lambda expression. They may also contain definitions for variable capture. To learn more about that topic, see the [cppreference.com discussion and examples](https://en.cppreference.com/w/cpp/language/lambda). -### Reaction Types +### Event Types -ReactESP is not limited to just delays or repeating reactions. +ReactESP is not limited to just delays or repeating events. It also supports the following: -- `StreamReaction`: a reaction that triggers when data is available on a stream, for example on a serial port -- `ISRReaction`: a reaction that is called when an interrupt is triggered (for example, when a GPIO pin is toggled) -- `TickReaction`: a reaction that is called every time the main event loop is executed +- `StreamEvent`: an event that triggers when data is available on a stream, for example on a serial port +- `ISREvent`: an event that is called when an interrupt is triggered (for example, when a GPIO pin is toggled) +- `TickEvent`: an event that is called every time the main event loop is executed -### Removing Reactions +### Removing Events -All of the `app.onXXX()` calls return a `Reaction` object. -If this object is stored, it can be used to access and manipulate the reaction later. -In practice, you can disable the reaction by calling `reaction->remove()`. -The same reaction can be re-added later by calling `reaction->add()`. +All of the `app.onXXX()` calls return a `Event` object. +If this object is stored, it can be used to access and manipulate the event later. +In practice, you can disable the event by calling `event->remove()`. +The same event can be re-added later by calling `event->add()`. -Some attention needs to be paid with `DelayReaction` objects, though. -Since they are by nature one-off operations, the corresponding object is deleted after the reaction is triggered. -You must ensure that you don't try to call the methods of an object that has been deleted, for example by setting a flag in the callback function and checking the flag value before trying to remove the reaction. +Some attention needs to be paid with `DelayEvent` objects, though. +Since they are by nature one-off operations, the corresponding object is deleted after the event is triggered. +You must ensure that you don't try to call the methods of an object that has been deleted, for example by setting a flag in the callback function and checking the flag value before trying to remove the event. ## Sensors diff --git a/docs/pages/tutorials/arduino_style/index.md b/docs/pages/tutorials/arduino_style/index.md index 414817e3a..8640e3f8c 100644 --- a/docs/pages/tutorials/arduino_style/index.md +++ b/docs/pages/tutorials/arduino_style/index.md @@ -6,7 +6,7 @@ parent: Tutorials # Mix and Match SensESP with Arduino Style Code -While the ReactESP and SensESP features such as the reactions and the producers, consumers and transforms are very powerful, they are not for everyone. This tutorial shows how to use SensESP to only deal with the Signal K networking, and use Arduino-style code to handle the rest. +While the ReactESP and SensESP features such as the events and the producers, consumers and transforms are very powerful, they are not for everyone. This tutorial shows how to use SensESP to only deal with the Signal K networking, and use Arduino-style code to handle the rest. After reading this tutorial, you should be able to use SensESP together with existing Arduino style code examples. SensESP will take care of initializing the WiFi and the Signal K connection, and you can use the Arduino style code to read sensors and send data to Signal K. @@ -176,12 +176,10 @@ First, let's add the required header file include statements to the `src/main.cp The `sensesp_app_builder.h` file contains the `SensESPAppBuilder` class, which we'll use to build the SensESP app. The `signalk_output.h` file contains the `SKOutput` class, which we'll use to create the Signal K output objects. -We'll also need to add a namespace definition and create the ReactESP app that SensESP uses to run the code. Add the following lines after the `#define` statements: +We also need to add a namespace definition. Add the following lines after the `#include` statements: ```cpp using namespace sensesp; - -reactesp::ReactESP app; ``` Next, we'll create the SensESP application using the builder class. Add the following lines to the `setup()` function, right before the `Wire.begin()` line: @@ -195,7 +193,7 @@ Next, we'll create the SensESP application using the builder class. Add the foll This will create a SensESP app with the hostname `sensesp-bme280`. You can change this to whatever you want, but make sure it's unique on your network. The builder class also allows you to set the WiFi SSID and password and other settings, if needed. See the [SensESPAppBuilder](/generated/docs/classsensesp_1_1_sens_e_s_p_app_builder.html) documentation for more information. -One more thing to do is to add the `app.tick();` command to the end of the `loop()` function. This call triggers execution of any ReactESP reactions that have been scheduled. +One more thing to do is to add the `app.tick();` command to the end of the `loop()` function. This call triggers execution of any ReactESP events that have been scheduled. Now, let's start our program. Add the line `sensesp_app->start();` at the very end of the `setup()` function. This will start the SensESP app and connect to the WiFi network. @@ -214,7 +212,7 @@ Every time it is run, after printing the values, the software will sleep for `de A major, fundamental rule in asynchronous programming (of which ReactESP is a simple example) is that you should never block the main loop. If you do, you'll block all the other tasks as well. So, let's remove the `delay(delayTime);` line from the `loop()` function. -Normally, we'd add an `onRepeat` reaction to call the `printValues()` function every second, but since I promised to minimise the use of ReactESP and SensESP constructs, we'll implement a simple timer using the Arduino `millis()` function. Replace the `loop()` function with the following code: +Normally, we'd add an `onRepeat` event to call the `printValues()` function every second, but since I promised to minimise the use of ReactESP and SensESP constructs, we'll implement a simple timer using the Arduino `millis()` function. Replace the `loop()` function with the following code: ```cpp void loop() { @@ -304,8 +302,6 @@ Here's the complete code for the `src/main.cpp` file: using namespace sensesp; -reactesp::ReactESP app; - Adafruit_BME280 bme; unsigned long delayTime = 1000; diff --git a/examples/analog_input.cpp b/examples/analog_input.cpp index 7c362af4d..ee8720d4d 100644 --- a/examples/analog_input.cpp +++ b/examples/analog_input.cpp @@ -10,10 +10,6 @@ using namespace sensesp; -// SensESP builds upon the ReactESP framework. Every ReactESP application -// must instantiate the "app" object. -reactesp::ReactESP app; - // The setup function performs one-time application initialization. void setup() { // Some initialization boilerplate when in debug mode... @@ -91,6 +87,9 @@ void setup() { new SKMetadata("ratio", "Indoor light"))); } -// The loop function is called in an endless loop during program execution. -// It simply calls `app.tick()` which will then execute all reactions as needed. -void loop() { app.tick(); } +void loop() { + // We're storing the event loop in a static variable so that it's only + // acquired once. Saves a few function calls per loop iteration. + static auto event_loop = SensESPBaseApp::get_event_loop(); + event_loop->tick(); +} diff --git a/examples/async_repeat_sensor.cpp b/examples/async_repeat_sensor.cpp index 4e6e81347..070ad07f2 100644 --- a/examples/async_repeat_sensor.cpp +++ b/examples/async_repeat_sensor.cpp @@ -13,8 +13,6 @@ using namespace sensesp; -reactesp::ReactESP app; - // The setup function performs one-time application initialization. void setup() { SetupLogging(); @@ -35,7 +33,7 @@ void setup() { auto digital_read_callback = [](RepeatSensor* sensor) { ESP_LOGI("Example", "Pretend to trigger an asynchronous measurement operation here."); - app.onDelay(1000, + SensESPBaseApp::get_event_loop()->onDelay(1000, [sensor]() { sensor->emit(digitalRead(kDigitalInputPin)); }); }; @@ -56,6 +54,9 @@ void setup() { digital->connect_to(new SKOutputFloat(sk_path, "")); } -// The loop function is called in an endless loop during program execution. -// It simply calls `app.tick()` which will then execute all reactions as needed. -void loop() { app.tick(); } +void loop() { + // We're storing the event loop in a static variable so that it's only + // acquired once. Saves a few function calls per loop iteration. + static auto event_loop = SensESPBaseApp::get_event_loop(); + event_loop->tick(); +} diff --git a/examples/chain_counter.cpp b/examples/chain_counter.cpp index dbf6b3c35..f84b02839 100644 --- a/examples/chain_counter.cpp +++ b/examples/chain_counter.cpp @@ -22,8 +22,6 @@ using namespace sensesp; * A bi-directional chain counter is possible, but this is not one. */ -reactesp::ReactESP app; - void setup() { SetupLogging(); @@ -147,5 +145,10 @@ void setup() { } // The loop function is called in an endless loop during program execution. -// It simply calls `app.tick()` which will then execute all reactions as needed. -void loop() { app.tick(); } +// It simply calls `app.tick()` which will then execute all events needed. +void loop() { + // We're storing the event loop in a static variable so that it's only + // acquired once. Saves a few function calls per loop iteration. + static auto event_loop = SensESPBaseApp::get_event_loop(); + event_loop->tick(); +} diff --git a/examples/constant_sensor.cpp b/examples/constant_sensor.cpp index 77e26e313..336c3d3f7 100644 --- a/examples/constant_sensor.cpp +++ b/examples/constant_sensor.cpp @@ -17,8 +17,6 @@ using namespace sensesp; -reactesp::ReactESP app; - void setup() { SetupLogging(); @@ -37,4 +35,9 @@ void setup() { new SKMetadata("m3", "Fresh Water Tank Capacity"))); } -void loop() { app.tick(); } +void loop() { + // We're storing the event loop in a static variable so that it's only + // acquired once. Saves a few function calls per loop iteration. + static auto event_loop = SensESPBaseApp::get_event_loop(); + event_loop->tick(); +} diff --git a/examples/dual_thermocouple_sensors/max6675_signalk.cpp b/examples/dual_thermocouple_sensors/max6675_signalk.cpp index be7a1c6b1..4a8ab8f27 100644 --- a/examples/dual_thermocouple_sensors/max6675_signalk.cpp +++ b/examples/dual_thermocouple_sensors/max6675_signalk.cpp @@ -16,8 +16,6 @@ using namespace sensesp; -reactesp::ReactESP app; - MAX6675 thermocouple0(thermoCLK, thermo1CS, thermoDO); MAX6675 thermocouple1(thermoCLK, thermo2CS, thermoDO); @@ -57,4 +55,9 @@ void setup() { } -void loop() { app.tick(); } +void loop() { + // We're storing the event loop in a static variable so that it's only + // acquired once. Saves a few function calls per loop iteration. + static auto event_loop = SensESPBaseApp::get_event_loop(); + event_loop->tick(); +} diff --git a/examples/dual_thermocouple_sensors/max6675_signalk_n2k.cpp b/examples/dual_thermocouple_sensors/max6675_signalk_n2k.cpp index dfa3df6a6..79959c0d9 100644 --- a/examples/dual_thermocouple_sensors/max6675_signalk_n2k.cpp +++ b/examples/dual_thermocouple_sensors/max6675_signalk_n2k.cpp @@ -26,8 +26,6 @@ using namespace sensesp; tNMEA2000* nmea2000; -reactesp::ReactESP app; - // MAX6675 setup MAX6675 thermocouple0(thermoCLK, thermo1CS, thermoDO); MAX6675 thermocouple1(thermoCLK, thermo2CS, thermoDO); @@ -145,4 +143,9 @@ void setup() { } // main program loop -void loop() { app.tick(); } +void loop() { + // We're storing the event loop in a static variable so that it's only + // acquired once. Saves a few function calls per loop iteration. + static auto event_loop = SensESPBaseApp::get_event_loop(); + event_loop->tick(); +} diff --git a/examples/freertos_tasks.cpp b/examples/freertos_tasks.cpp index 7d3eab5b1..e94d84b54 100644 --- a/examples/freertos_tasks.cpp +++ b/examples/freertos_tasks.cpp @@ -24,8 +24,6 @@ const int kTestOutputInterval = 410; const uint8_t kDigitalInputPin = 15; -reactesp::ReactESP app; - void ToggleTestOutputPin(void *parameter) { while (true) { digitalWrite(kTestOutputPin, !digitalRead(kTestOutputPin)); @@ -90,10 +88,13 @@ void setup() { [](float input) { ESP_LOGD("Example", "Heading: %f", input); })); // print out free heap - app.onRepeat( + SensESPBaseApp::get_event_loop()->onRepeat( 2000, []() { ESP_LOGD("Example", "Free heap: %d", ESP.getFreeHeap()); }); } -// The loop function is called in an endless loop during program execution. -// It simply calls `app.tick()` which will then execute all reactions as needed. -void loop() { app.tick(); } +void loop() { + // We're storing the event loop in a static variable so that it's only + // acquired once. Saves a few function calls per loop iteration. + static auto event_loop = SensESPBaseApp::get_event_loop(); + event_loop->tick(); +} diff --git a/examples/fuel_level_sensor/fuel_level_sensor_example.cpp b/examples/fuel_level_sensor/fuel_level_sensor_example.cpp index 68b7266e0..beabd17cf 100644 --- a/examples/fuel_level_sensor/fuel_level_sensor_example.cpp +++ b/examples/fuel_level_sensor/fuel_level_sensor_example.cpp @@ -7,8 +7,6 @@ using namespace sensesp; -reactesp::ReactESP app; - void setup() { SetupLogging(); @@ -37,6 +35,9 @@ void setup() { new SKOutputFloat("tanks.fuel.0.currentLevel")); } -// The loop function is called in an endless loop during program execution. -// It simply calls `app.tick()` which will then execute all reactions as needed. -void loop() { app.tick(); } +void loop() { + // We're storing the event loop in a static variable so that it's only + // acquired once. Saves a few function calls per loop iteration. + static auto event_loop = SensESPBaseApp::get_event_loop(); + event_loop->tick(); +} diff --git a/examples/hysteresis.cpp b/examples/hysteresis.cpp index 89fec6b21..7f6040e30 100644 --- a/examples/hysteresis.cpp +++ b/examples/hysteresis.cpp @@ -9,8 +9,6 @@ using namespace sensesp; -reactesp::ReactESP app; - void setup() { SetupLogging(); @@ -47,6 +45,9 @@ void setup() { ->connect_to(new SKOutputBool(sk_path)); } -// The loop function is called in an endless loop during program execution. -// It simply calls `app.tick()` which will then execute all reactions as needed. -void loop() { app.tick(); } +void loop() { + // We're storing the event loop in a static variable so that it's only + // acquired once. Saves a few function calls per loop iteration. + static auto event_loop = SensESPBaseApp::get_event_loop(); + event_loop->tick(); +} diff --git a/examples/join_and_zip.cpp b/examples/join_and_zip.cpp index db0f49442..640cde834 100644 --- a/examples/join_and_zip.cpp +++ b/examples/join_and_zip.cpp @@ -24,8 +24,6 @@ using namespace sensesp; -reactesp::ReactESP app; - SensESPMinimalApp* sensesp_app; void setup() { @@ -149,4 +147,9 @@ void setup() { })); } -void loop() { app.tick(); } +void loop() { + // We're storing the event loop in a static variable so that it's only + // acquired once. Saves a few function calls per loop iteration. + static auto event_loop = SensESPBaseApp::get_event_loop(); + event_loop->tick(); +} diff --git a/examples/lambda_transform.cpp b/examples/lambda_transform.cpp index 0d5b2ce87..023c5de92 100644 --- a/examples/lambda_transform.cpp +++ b/examples/lambda_transform.cpp @@ -8,8 +8,6 @@ using namespace sensesp; -reactesp::ReactESP app; - void setup() { SetupLogging(); @@ -92,6 +90,9 @@ void setup() { ->connect_to(new SKOutputFloat(sk_path)); } -// The loop function is called in an endless loop during program execution. -// It simply calls `app.tick()` which will then execute all reactions as needed. -void loop() { app.tick(); } +void loop() { + // We're storing the event loop in a static variable so that it's only + // acquired once. Saves a few function calls per loop iteration. + static auto event_loop = SensESPBaseApp::get_event_loop(); + event_loop->tick(); +} diff --git a/examples/manual_networking.cpp b/examples/manual_networking.cpp index e1be7d227..081217e68 100644 --- a/examples/manual_networking.cpp +++ b/examples/manual_networking.cpp @@ -21,8 +21,6 @@ const uint8_t input_pin1 = 0; // The program reacts to changes on GPIO pin 0 and prints the value to the // serial console. -reactesp::ReactESP app; - void setup() { SetupLogging(); @@ -61,6 +59,9 @@ void setup() { digin->connect_to(new SKOutputBool("electrical.switches.0.state", "/digin/state")); } -// The loop function is called in an endless loop during program execution. -// It simply calls `app.tick()` which will then execute all reactions as needed. -void loop() { app.tick(); } +void loop() { + // We're storing the event loop in a static variable so that it's only + // acquired once. Saves a few function calls per loop iteration. + static auto event_loop = SensESPBaseApp::get_event_loop(); + event_loop->tick(); +} diff --git a/examples/milone_level_sensor/milone_level_sensor.cpp b/examples/milone_level_sensor/milone_level_sensor.cpp index 07f9e5e5b..0dcee91cd 100644 --- a/examples/milone_level_sensor/milone_level_sensor.cpp +++ b/examples/milone_level_sensor/milone_level_sensor.cpp @@ -41,10 +41,6 @@ class ETapeInterpreter : public CurveInterpolator { } }; -// SensESP builds upon the ReactESP framework. Every ReactESP application -// defines an "app" object. -reactesp::ReactESP app; - void setup() { // Some initialization boilerplate when in debug mode... SetupLogging(); @@ -133,6 +129,9 @@ void setup() { new SKOutputFloat("tanks.freshwater.starboard.currentLevel")); } -// The loop function is called in an endless loop during program execution. -// It simply calls `app.tick()` which will then execute all reactions as needed. -void loop() { app.tick(); } +void loop() { + // We're storing the event loop in a static variable so that it's only + // acquired once. Saves a few function calls per loop iteration. + static auto event_loop = SensESPBaseApp::get_event_loop(); + event_loop->tick(); +} diff --git a/examples/minimal_app.cpp b/examples/minimal_app.cpp index db2415bb8..54893adef 100644 --- a/examples/minimal_app.cpp +++ b/examples/minimal_app.cpp @@ -26,8 +26,6 @@ const uint8_t output_pin2 = 21; // with a jumper wire, you should see changes in the reported values on the // serial console. -reactesp::ReactESP app; - void setup() { SetupLogging(); @@ -60,14 +58,17 @@ void setup() { })); pinMode(output_pin1, OUTPUT); - app.onRepeat(5, + SensESPBaseApp::get_event_loop()->onRepeat(5, []() { digitalWrite(output_pin1, !digitalRead(output_pin1)); }); pinMode(output_pin2, OUTPUT); - app.onRepeat(100, + SensESPBaseApp::get_event_loop()->onRepeat(100, []() { digitalWrite(output_pin2, !digitalRead(output_pin2)); }); } -// The loop function is called in an endless loop during program execution. -// It simply calls `app.tick()` which will then execute all reactions as needed. -void loop() { app.tick(); } +void loop() { + // We're storing the event loop in a static variable so that it's only + // acquired once. Saves a few function calls per loop iteration. + static auto event_loop = SensESPBaseApp::get_event_loop(); + event_loop->tick(); +} diff --git a/examples/raw_json.cpp b/examples/raw_json.cpp index c9ba78c39..cf23e36bf 100644 --- a/examples/raw_json.cpp +++ b/examples/raw_json.cpp @@ -9,8 +9,6 @@ using namespace sensesp; -reactesp::ReactESP app; - ObservableValue toggler; void setup() { @@ -21,7 +19,7 @@ void setup() { ->set_wifi("Hat Labs Sensors", "kanneluuri2406") ->get_app(); - reactesp::ReactESP::app->onRepeat(1000, + SensESPBaseApp::get_event_loop()->onRepeat(1000, []() { toggler.set(!toggler.get()); }); // take some boolean input and convert it into a simple serialized JSON @@ -47,4 +45,9 @@ void setup() { jsonify->connect_to(new SKOutputRawJson(sk_path, "")); } -void loop() { app.tick(); } +void loop() { + // We're storing the event loop in a static variable so that it's only + // acquired once. Saves a few function calls per loop iteration. + static auto event_loop = SensESPBaseApp::get_event_loop(); + event_loop->tick(); +} diff --git a/examples/relay_control.cpp b/examples/relay_control.cpp index 763fd9bef..45ec47a19 100644 --- a/examples/relay_control.cpp +++ b/examples/relay_control.cpp @@ -17,10 +17,6 @@ using namespace sensesp; // an alarm, or whatever. This example demonstrates how to turn on a navigation // light when it gets dark outside. -// SensESP builds upon the ReactESP framework. Every ReactESP application -// defines an "app" object. -reactesp::ReactESP app; - void setup() { // Some initialization boilerplate when in debug mode... SetupLogging(); @@ -58,6 +54,9 @@ void setup() { ->connect_to(new DigitalOutput(5)); } -// The loop function is called in an endless loop during program execution. -// It simply calls `app.tick()` which will then execute all reactions as needed. -void loop() { app.tick(); } +void loop() { + // We're storing the event loop in a static variable so that it's only + // acquired once. Saves a few function calls per loop iteration. + static auto event_loop = SensESPBaseApp::get_event_loop(); + event_loop->tick(); +} diff --git a/examples/repeat_sensor_analog_input.cpp b/examples/repeat_sensor_analog_input.cpp index 766a96ebd..52bff0b96 100644 --- a/examples/repeat_sensor_analog_input.cpp +++ b/examples/repeat_sensor_analog_input.cpp @@ -20,8 +20,6 @@ using namespace sensesp; -reactesp::ReactESP app; - // GPIO pin that we'll be using for the analog input. const uint8_t kAnalogInputPin = 36; @@ -65,6 +63,9 @@ void setup() { new SKOutputFloat(sk_path, "", new SKMetadata("ratio", "Indoor light"))); } -// The loop function is called in an endless loop during program execution. -// It simply calls `app.tick()` which will then execute all reactions as needed. -void loop() { app.tick(); } +void loop() { + // We're storing the event loop in a static variable so that it's only + // acquired once. Saves a few function calls per loop iteration. + static auto event_loop = SensESPBaseApp::get_event_loop(); + event_loop->tick(); +} diff --git a/examples/repeat_transform.cpp b/examples/repeat_transform.cpp index 6679abd27..859086336 100644 --- a/examples/repeat_transform.cpp +++ b/examples/repeat_transform.cpp @@ -24,8 +24,6 @@ using namespace sensesp; -reactesp::ReactESP app; - SensESPMinimalApp* sensesp_app; void setup() { @@ -140,4 +138,9 @@ void setup() { [](int value) { ESP_LOGD("App", "Repeat: %d", value); })); } -void loop() { app.tick(); } +void loop() { + // We're storing the event loop in a static variable so that it's only + // acquired once. Saves a few function calls per loop iteration. + static auto event_loop = SensESPBaseApp::get_event_loop(); + event_loop->tick(); +} diff --git a/examples/rpm_counter.cpp b/examples/rpm_counter.cpp index f110bcf2a..a8ba03ace 100644 --- a/examples/rpm_counter.cpp +++ b/examples/rpm_counter.cpp @@ -9,10 +9,6 @@ using namespace sensesp; -// SensESP builds upon the ReactESP framework. Every ReactESP application -// defines an "app" object. -reactesp::ReactESP app; - void setup() { SetupLogging(); @@ -79,6 +75,9 @@ void setup() { // to a Signal K Output as a number } -// The loop function is called in an endless loop during program execution. -// It simply calls `app.tick()` which will then execute all reactions as needed. -void loop() { app.tick(); } +void loop() { + // We're storing the event loop in a static variable so that it's only + // acquired once. Saves a few function calls per loop iteration. + static auto event_loop = SensESPBaseApp::get_event_loop(); + event_loop->tick(); +} diff --git a/examples/smart_switch/remote_switch_example.cpp b/examples/smart_switch/remote_switch_example.cpp index 5575ea7b4..6c25c9704 100644 --- a/examples/smart_switch/remote_switch_example.cpp +++ b/examples/smart_switch/remote_switch_example.cpp @@ -35,10 +35,6 @@ using namespace sensesp; #define LED_ON_COLOR 0x004700 #define LED_OFF_COLOR 0x261900 -// SensESP builds upon the ReactESP framework. Every ReactESP application -// defines an "app" object. -reactesp::ReactESP app; - void setup() { SetupLogging(); @@ -105,6 +101,9 @@ void setup() { sk_listener->connect_to(controller); } -// The loop function is called in an endless loop during program execution. -// It simply calls `app.tick()` which will then execute all reactions as needed. -void loop() { app.tick(); } +void loop() { + // We're storing the event loop in a static variable so that it's only + // acquired once. Saves a few function calls per loop iteration. + static auto event_loop = SensESPBaseApp::get_event_loop(); + event_loop->tick(); +} diff --git a/examples/smart_switch/smart_switch_example.cpp b/examples/smart_switch/smart_switch_example.cpp index eba6dbb6b..23806b8fb 100644 --- a/examples/smart_switch/smart_switch_example.cpp +++ b/examples/smart_switch/smart_switch_example.cpp @@ -38,10 +38,6 @@ using namespace sensesp; #define LED_ON_COLOR 0x004700 #define LED_OFF_COLOR 0x261900 -// SensESP builds upon the ReactESP framework. Every ReactESP application -// defines an "app" object. -reactesp::ReactESP app; - void setup() { SetupLogging(); @@ -115,6 +111,9 @@ void setup() { ->connect_to(new SKOutputBool(sk_path, config_path_sk_output)); } -// The loop function is called in an endless loop during program execution. -// It simply calls `app.tick()` which will then execute all reactions as needed. -void loop() { app.tick(); } +void loop() { + // We're storing the event loop in a static variable so that it's only + // acquired once. Saves a few function calls per loop iteration. + static auto event_loop = SensESPBaseApp::get_event_loop(); + event_loop->tick(); +} diff --git a/examples/temperature_sender.cpp b/examples/temperature_sender.cpp index cf2cc223b..23bf596ba 100644 --- a/examples/temperature_sender.cpp +++ b/examples/temperature_sender.cpp @@ -55,10 +55,6 @@ class TemperatureInterpreter : public CurveInterpolator { } }; -// SensESP builds upon the ReactESP framework. Every ReactESP application -// defines an "app" object. -reactesp::ReactESP app; - void setup() { SetupLogging(); @@ -166,6 +162,9 @@ void setup() { new SKOutputFloat(sk_path, "/12V_alternator/temp/sk", metadata)); } -// The loop function is called in an endless loop during program execution. -// It simply calls `app.tick()` which will then execute all reactions as needed. -void loop() { app.tick(); } +void loop() { + // We're storing the event loop in a static variable so that it's only + // acquired once. Saves a few function calls per loop iteration. + static auto event_loop = SensESPBaseApp::get_event_loop(); + event_loop->tick(); +} diff --git a/examples/time_counter.cpp b/examples/time_counter.cpp index ebec86c2d..b91116642 100644 --- a/examples/time_counter.cpp +++ b/examples/time_counter.cpp @@ -24,8 +24,6 @@ using namespace sensesp; -reactesp::ReactESP app; - unsigned long cycle_start_time = 0; unsigned long freq_start_time = 0; int freq = 0; @@ -39,7 +37,7 @@ void setup() { // set GPIO 18 to output mode pinMode(18, OUTPUT); - app.onRepeat(10, []() { + SensESPBaseApp::get_event_loop()->onRepeat(10, []() { if (freq == 0) { if (millis() - freq_start_time >= 10000) { freq = 10; @@ -109,4 +107,9 @@ void setup() { new SKMetadata("s", "Main Engine running time"))); } -void loop() { app.tick(); } +void loop() { + // We're storing the event loop in a static variable so that it's only + // acquired once. Saves a few function calls per loop iteration. + static auto event_loop = SensESPBaseApp::get_event_loop(); + event_loop->tick(); +} diff --git a/library.json b/library.json index 49bf6f75b..e7c3657c4 100644 --- a/library.json +++ b/library.json @@ -28,7 +28,7 @@ { "owner": "mairas", "name": "ReactESP", - "version": "^2.0.0" + "version": "^3.0.0" }, { "owner": "bblanchon", diff --git a/platformio.ini b/platformio.ini index 433e253db..2723e85d3 100644 --- a/platformio.ini +++ b/platformio.ini @@ -27,7 +27,7 @@ upload_speed = 460800 monitor_speed = 115200 lib_deps = - mairas/ReactESP @ ^2.0.0 + mairas/ReactESP @ ^3.0.0 bblanchon/ArduinoJson @ ^7.0.0 pfeerick/elapsedMillis @ ^1.0.6 bxparks/AceButton @ ^1.10.1 diff --git a/src/sensesp/controllers/smart_switch_controller.cpp b/src/sensesp/controllers/smart_switch_controller.cpp index de0bd6b23..4817a39c8 100644 --- a/src/sensesp/controllers/smart_switch_controller.cpp +++ b/src/sensesp/controllers/smart_switch_controller.cpp @@ -1,6 +1,7 @@ #include "smart_switch_controller.h" #include "sensesp/transforms/truth_text.h" +#include "sensesp_base_app.h" namespace sensesp { @@ -22,7 +23,8 @@ SmartSwitchController::SmartSwitchController(bool auto_initialize, // Emit the initial state once the event loop starts if (auto_initialize_) { - reactesp::ReactESP::app->onDelay(0, [this]() { this->emit(is_on); }); + SensESPBaseApp::get_event_loop()->onDelay(0, + [this]() { this->emit(is_on); }); } } diff --git a/src/sensesp/net/discovery.cpp b/src/sensesp/net/discovery.cpp index a4e03dc21..404720742 100644 --- a/src/sensesp/net/discovery.cpp +++ b/src/sensesp/net/discovery.cpp @@ -5,7 +5,7 @@ namespace sensesp { MDNSDiscovery::MDNSDiscovery() { - reactesp::ReactESP::app->onDelay(0, [this]() { + SensESPBaseApp::get_event_loop()->onDelay(0, [this]() { String hostname = SensESPBaseApp::get_hostname(); // MDNS.begin(hostname) will crash if hostname is blank diff --git a/src/sensesp/net/http_server.h b/src/sensesp/net/http_server.h index 3868485fa..214fca24b 100644 --- a/src/sensesp/net/http_server.h +++ b/src/sensesp/net/http_server.h @@ -79,7 +79,7 @@ class HTTPServer : public Configurable { ESP_LOGE(__FILENAME__, "Only one HTTPServer instance is allowed"); return; } - reactesp::ReactESP::app->onDelay(0, [this]() { + SensESPBaseApp::get_event_loop()->onDelay(0, [this]() { esp_err_t error = httpd_start(&server_, &config_); if (error != ESP_OK) { ESP_LOGE(__FILENAME__, "Error starting HTTP server: %s", diff --git a/src/sensesp/net/networking.cpp b/src/sensesp/net/networking.cpp index d467f2e1a..6f088a18f 100644 --- a/src/sensesp/net/networking.cpp +++ b/src/sensesp/net/networking.cpp @@ -92,7 +92,7 @@ Networking::Networking(String config_path, String client_ssid, dns_server_->setErrorReplyCode(DNSReplyCode::NoError); dns_server_->start(53, "*", WiFi.softAPIP()); - reactesp::ReactESP::app->onRepeat( + SensESPBaseApp::get_event_loop()->onRepeat( 1, [this]() { dns_server_->processNextRequest(); }); } } @@ -190,10 +190,10 @@ void Networking::start_client_autoconnect() { // Perform an initial connection without a delay. reconnect_cb(); - // Launch a separate onRepeat reaction to (re-)establish WiFi connection. + // Launch a separate onRepeat event to (re-)establish WiFi connection. // Connecting is attempted only every 20 s to allow the previous connection // attempt to complete even if the network is slow. - reactesp::ReactESP::app->onRepeat(20000, reconnect_cb); + SensESPBaseApp::get_event_loop()->onRepeat(20000, reconnect_cb); } /** diff --git a/src/sensesp/net/networking.h b/src/sensesp/net/networking.h index 482ac543a..750b3e71b 100644 --- a/src/sensesp/net/networking.h +++ b/src/sensesp/net/networking.h @@ -49,7 +49,7 @@ class WiFiStateProducer : public ValueProducer { setup_wifi_callbacks(); // Emit the current state as soon as the event loop starts - reactesp::ReactESP::app->onDelay(0, [this]() { this->emit(this->output); }); + SensESPBaseApp::get_event_loop()->onDelay(0, [this]() { this->emit(this->output); }); } void setup_wifi_callbacks() { @@ -89,7 +89,7 @@ class WiFiStateProducer : public ValueProducer { // Setting the AP mode happens immediately, // so this callback is likely called already before all startables have been // initiated. Delay the WiFi state update until the start of the event loop. - reactesp::ReactESP::app->onDelay( + SensESPBaseApp::get_event_loop()->onDelay( 0, [this]() { this->emit(WiFiState::kWifiAPModeActivated); }); } diff --git a/src/sensesp/net/ota.h b/src/sensesp/net/ota.h index ade29983d..8e2161bfa 100644 --- a/src/sensesp/net/ota.h +++ b/src/sensesp/net/ota.h @@ -6,6 +6,8 @@ #include #include +#include "sensesp_base_app.h" + namespace sensesp { class OTA { @@ -16,7 +18,7 @@ class OTA { * @param password A password to be used for the OTA update. */ OTA(const char* password) : password_{password} { - reactesp::ReactESP::app->onDelay(0, [this]() { + SensESPBaseApp::get_event_loop()->onDelay(0, [this]() { ArduinoOTA.setPassword(password_); ArduinoOTA.onStart([]() { ESP_LOGW(__FILENAME__, "Starting OTA"); }); ArduinoOTA.onEnd([]() { ESP_LOGW(__FILENAME__, "OTA End"); }); @@ -39,7 +41,7 @@ class OTA { } }); ArduinoOTA.begin(); - reactesp::ReactESP::app->onRepeat(20, OTA::handle_ota); + SensESPBaseApp::get_event_loop()->onRepeat(20, OTA::handle_ota); }); } diff --git a/src/sensesp/net/web/base_command_handler.cpp b/src/sensesp/net/web/base_command_handler.cpp index 30049cdb5..71c6a614d 100644 --- a/src/sensesp/net/web/base_command_handler.cpp +++ b/src/sensesp/net/web/base_command_handler.cpp @@ -9,7 +9,7 @@ void add_http_reset_handler(HTTPServer* server) { "Resetting device back to factory defaults. " "You may have to reconfigure the WiFi settings.", 0); - reactesp::ReactESP::app->onDelay( + SensESPBaseApp::get_event_loop()->onDelay( 500, []() { SensESPBaseApp::get()->reset(); }); return ESP_OK; }); @@ -20,7 +20,7 @@ void add_http_restart_handler(HTTPServer* server) { HTTPRequestHandler* restart_handler = new HTTPRequestHandler( 1 << HTTP_POST, "/api/device/restart", [](httpd_req_t* req) { httpd_resp_send(req, "Restarting device", 0); - reactesp::ReactESP::app->onDelay(500, []() { ESP.restart(); }); + SensESPBaseApp::get_event_loop()->onDelay(500, []() { ESP.restart(); }); return ESP_OK; }); server->add_handler(restart_handler); diff --git a/src/sensesp/sensors/analog_input.cpp b/src/sensesp/sensors/analog_input.cpp index bd8562e3b..c416aeb19 100644 --- a/src/sensesp/sensors/analog_input.cpp +++ b/src/sensesp/sensors/analog_input.cpp @@ -3,6 +3,7 @@ #include "analog_input.h" #include "Arduino.h" +#include "sensesp_base_app.h" namespace sensesp { @@ -17,7 +18,7 @@ AnalogInput::AnalogInput(uint8_t pin, unsigned int read_delay, load_configuration(); if (this->analog_reader->configure()) { - reactesp::ReactESP::app->onRepeat(read_delay, [this]() { this->update(); }); + SensESPBaseApp::get_event_loop()->onRepeat(read_delay, [this]() { this->update(); }); } } diff --git a/src/sensesp/sensors/constant_sensor.h b/src/sensesp/sensors/constant_sensor.h index da1fe59a1..8dc4a0ce3 100644 --- a/src/sensesp/sensors/constant_sensor.h +++ b/src/sensesp/sensors/constant_sensor.h @@ -3,6 +3,7 @@ #include "Arduino.h" #include "sensesp/sensors/sensor.h" +#include "sensesp_base_app.h" namespace sensesp { @@ -58,9 +59,9 @@ class ConstantSensor : public Sensor { this->load_configuration(); // Emit the initial value once to set the output - reactesp::ReactESP::app->onDelay(0, [this]() { this->emit(value_); }); + SensESPBaseApp::get_event_loop()->onDelay(0, [this]() { this->emit(value_); }); // Then, emit the value at the specified interval - reactesp::ReactESP::app->onRepeat(send_interval_ * 1000, + SensESPBaseApp::get_event_loop()->onRepeat(send_interval_ * 1000, [this]() { this->emit(value_); }); } diff --git a/src/sensesp/sensors/digital_input.h b/src/sensesp/sensors/digital_input.h index 15ce19f85..e940c8e6a 100644 --- a/src/sensesp/sensors/digital_input.h +++ b/src/sensesp/sensors/digital_input.h @@ -3,6 +3,7 @@ #include +#include "sensesp_base_app.h" #include "sensor.h" namespace sensesp { @@ -56,8 +57,8 @@ class DigitalInputState : public DigitalInput, public Sensor { set_requires_restart(true); load_configuration(); - reactesp::ReactESP::app->onRepeat(read_delay_, - [this]() { emit(digitalRead(pin_)); }); + SensESPBaseApp::get_event_loop()->onRepeat( + read_delay_, [this]() { emit(digitalRead(pin_)); }); } private: @@ -92,10 +93,10 @@ class DigitalInputCounter : public DigitalInput, public Sensor { unsigned int read_delay, String config_path = "") : DigitalInputCounter(pin, pin_mode, interrupt_type, read_delay, config_path, [this]() { this->counter_++; }) { - reactesp::ReactESP::app->onInterrupt(pin_, interrupt_type_, - interrupt_handler_); + SensESPBaseApp::get_event_loop()->onInterrupt(pin_, interrupt_type_, + interrupt_handler_); - reactesp::ReactESP::app->onRepeat(read_delay_, [this]() { + SensESPBaseApp::get_event_loop()->onRepeat(read_delay_, [this]() { noInterrupts(); output = counter_; counter_ = 0; @@ -200,12 +201,13 @@ class DigitalInputChange : public DigitalInput, public Sensor { output = (bool)digitalRead(pin_); last_output_ = !output; // ensure that we always send the first output - reactesp::ReactESP::app->onInterrupt(pin_, interrupt_type_, [this]() { - output = (bool)digitalRead(pin_); - triggered_ = true; - }); + SensESPBaseApp::get_event_loop()->onInterrupt( + pin_, interrupt_type_, [this]() { + output = (bool)digitalRead(pin_); + triggered_ = true; + }); - reactesp::ReactESP::app->onTick([this]() { + SensESPBaseApp::get_event_loop()->onTick([this]() { if (triggered_ && (output != last_output_)) { noInterrupts(); triggered_ = false; diff --git a/src/sensesp/sensors/sensor.h b/src/sensesp/sensors/sensor.h index 7143db4b0..97cbf0024 100644 --- a/src/sensesp/sensors/sensor.h +++ b/src/sensesp/sensors/sensor.h @@ -6,6 +6,7 @@ #include "sensesp/system/configurable.h" #include "sensesp/system/observable.h" #include "sensesp/system/valueproducer.h" +#include "sensesp_base_app.h" namespace sensesp { @@ -69,7 +70,7 @@ class RepeatSensor : public Sensor { : Sensor(""), repeat_interval_ms_(repeat_interval_ms), returning_callback_(callback) { - reactesp::ReactESP::app->onRepeat(repeat_interval_ms_, [this]() { + SensESPBaseApp::get_event_loop()->onRepeat(repeat_interval_ms_, [this]() { this->emit(this->returning_callback_()); }); } @@ -92,8 +93,8 @@ class RepeatSensor : public Sensor { : Sensor(""), repeat_interval_ms_(repeat_interval_ms), emitting_callback_(callback) { - reactesp::ReactESP::app->onRepeat(repeat_interval_ms_, - [this]() { emitting_callback_(this); }); + SensESPBaseApp::get_event_loop()->onRepeat( + repeat_interval_ms_, [this]() { emitting_callback_(this); }); } protected: diff --git a/src/sensesp/sensors/system_info.h b/src/sensesp/sensors/system_info.h index 96c73daa7..4d709c31c 100644 --- a/src/sensesp/sensors/system_info.h +++ b/src/sensesp/sensors/system_info.h @@ -47,8 +47,9 @@ class SystemHz : public FloatSensor { SystemHz() { elapsed_millis_ = 0; - reactesp::ReactESP::app->onTick([this]() { this->tick(); }); - reactesp::ReactESP::app->onRepeat(1000, [this]() { this->update(); }); + SensESPBaseApp::get_event_loop()->onTick([this]() { this->tick(); }); + SensESPBaseApp::get_event_loop()->onRepeat(1000, + [this]() { this->update(); }); } String get_value_name() { return "systemhz"; } @@ -70,7 +71,8 @@ class SystemHz : public FloatSensor { class FreeMem : public IntSensor { public: FreeMem() { - reactesp::ReactESP::app->onRepeat(1000, [this]() { this->update(); }); + SensESPBaseApp::get_event_loop()->onRepeat(1000, + [this]() { this->update(); }); } String get_value_name() { return "freemem"; } @@ -89,7 +91,8 @@ class FreeMem : public IntSensor { class Uptime : public FloatSensor { public: Uptime() { - reactesp::ReactESP::app->onRepeat(1000, [this]() { this->update(); }); + SensESPBaseApp::get_event_loop()->onRepeat(1000, + [this]() { this->update(); }); } String get_value_name() { return "uptime"; } @@ -108,7 +111,8 @@ class Uptime : public FloatSensor { class IPAddrDev : public StringSensor { public: IPAddrDev() { - reactesp::ReactESP::app->onRepeat(10000, [this]() { this->update(); }); + SensESPBaseApp::get_event_loop()->onRepeat(10000, + [this]() { this->update(); }); } String get_value_name() { return "ipaddr"; } @@ -127,7 +131,8 @@ class IPAddrDev : public StringSensor { class WiFiSignal : public FloatSensor { public: WiFiSignal() { - reactesp::ReactESP::app->onRepeat(3000, [this]() { this->update(); }); + SensESPBaseApp::get_event_loop()->onRepeat(3000, + [this]() { this->update(); }); } String get_value_name() { return "wifisignal"; } diff --git a/src/sensesp/signalk/signalk_delta_queue.cpp b/src/sensesp/signalk/signalk_delta_queue.cpp index 719310cfb..604a3f91c 100644 --- a/src/sensesp/signalk/signalk_delta_queue.cpp +++ b/src/sensesp/signalk/signalk_delta_queue.cpp @@ -13,7 +13,8 @@ SKDeltaQueue::SKDeltaQueue(unsigned int max_buffer_size) : max_buffer_size{max_buffer_size}, meta_sent_{false} { semaphore_ = xSemaphoreCreateRecursiveMutex(); - reactesp::ReactESP::app->onDelay(0, [this]() { this->connect_emitters(); }); + SensESPBaseApp::get_event_loop()->onDelay( + 0, [this]() { this->connect_emitters(); }); } bool SKDeltaQueue::take_semaphore(uint64_t timeout_ms) { diff --git a/src/sensesp/signalk/signalk_put_request.cpp b/src/sensesp/signalk/signalk_put_request.cpp index db1b8aa8d..2174e6a7d 100644 --- a/src/sensesp/signalk/signalk_put_request.cpp +++ b/src/sensesp/signalk/signalk_put_request.cpp @@ -5,8 +5,6 @@ namespace sensesp { -extern reactesp::ReactESP app; - std::map SKRequest::request_map_; String SKRequest::send_request(JsonDocument& request, @@ -24,8 +22,8 @@ String SKRequest::send_request(JsonDocument& request, // After 10 seconds, if we haven't already handled a response, // assume its not coming. pending_request->timeout_cleanup = - reactesp::ReactESP::app->onDelay(timeout, [pending_request]() { - // Mark the delay reaction null as it will be cleaned up by the ReactESP + SensESPBaseApp::get_event_loop()->onDelay(timeout, [pending_request]() { + // Mark the delay eventll as it will be cleaned up by the ReactESP // framework if this executes... ESP_LOGW(__FILENAME__, "No response from server for request Id %s", pending_request->request_id.c_str()); @@ -81,7 +79,8 @@ void SKRequest::remove_request(String request_id) { if (pending_request->timeout_cleanup != nullptr) { // The timeout code was not called, so just // remove it from the ReactESP execution queue... - pending_request->timeout_cleanup->remove(); + pending_request->timeout_cleanup->remove( + SensESPBaseApp::get_event_loop()); } // Now, remove the request from the map... diff --git a/src/sensesp/signalk/signalk_put_request.h b/src/sensesp/signalk/signalk_put_request.h index bc3adcd0a..68eaba2de 100644 --- a/src/sensesp/signalk/signalk_put_request.h +++ b/src/sensesp/signalk/signalk_put_request.h @@ -47,7 +47,7 @@ class SKRequest { public: String request_id; std::function callback; - reactesp::DelayReaction* timeout_cleanup; + reactesp::DelayEvent* timeout_cleanup; }; /// A map to hold all of the requests we are expecting future @@ -55,7 +55,7 @@ class SKRequest { static std::map request_map_; /// Removes the specified request_id from the request_map, - /// cleaning up outstanding reactions if necessary + /// cleaning up outstanding events if necessary static void remove_request(String request_id); /// Returns the pending request object associated with diff --git a/src/sensesp/signalk/signalk_ws_client.cpp b/src/sensesp/signalk/signalk_ws_client.cpp index fc21994ba..948d126fe 100644 --- a/src/sensesp/signalk/signalk_ws_client.cpp +++ b/src/sensesp/signalk/signalk_ws_client.cpp @@ -90,7 +90,7 @@ SKWSClient::SKWSClient(const String& config_path, SKDeltaQueue* sk_delta_queue, [this]() { this->emit(this->connection_state_.get()); }); // process any received updates in the main task - reactesp::ReactESP::app->onRepeat( + SensESPBaseApp::get_event_loop()->onRepeat( 1, [this]() { this->process_received_updates(); }); // set the singleton object pointer @@ -101,7 +101,7 @@ SKWSClient::SKWSClient(const String& config_path, SKDeltaQueue* sk_delta_queue, // Connect the counters delta_tx_tick_producer_.connect_to(&delta_tx_count_producer_); - reactesp::ReactESP::app->onDelay(0, [this]() { + SensESPBaseApp::get_event_loop()->onDelay(0, [this]() { ESP_LOGD(__FILENAME__, "Starting SKWSClient"); xTaskCreate(ExecuteWebSocketTask, "SKWSClient", kWsClientTaskStackSize, this, 1, NULL); diff --git a/src/sensesp/signalk/signalk_ws_client.h b/src/sensesp/signalk/signalk_ws_client.h index 6ae1036fb..cdaaf22c2 100644 --- a/src/sensesp/signalk/signalk_ws_client.h +++ b/src/sensesp/signalk/signalk_ws_client.h @@ -14,6 +14,7 @@ #include "sensesp/system/task_queue_producer.h" #include "sensesp/system/valueproducer.h" #include "sensesp/transforms/integrator.h" +#include "sensesp_base_app.h" namespace sensesp { @@ -104,7 +105,8 @@ class SKWSClient : public Configurable, TaskQueueProducer connection_state_ = TaskQueueProducer( - SKWSConnectionState::kSKWSDisconnected, reactesp::ReactESP::app); + SKWSConnectionState::kSKWSDisconnected, + SensESPBaseApp::get_event_loop()); /// task_connection_state is used to track the internal task state which might /// be out of sync with the published connection state. @@ -116,7 +118,7 @@ class SKWSClient : public Configurable, SKDeltaQueue* sk_delta_queue_; /// @brief Emits the number of deltas sent since last report TaskQueueProducer delta_tx_tick_producer_ = - TaskQueueProducer(0, reactesp::ReactESP::app, 5, 990); + TaskQueueProducer(0, SensESPBaseApp::get_event_loop(), 5, 990); Integrator delta_tx_count_producer_{1, 0, ""}; Integrator delta_rx_count_producer_{1, 0, ""}; diff --git a/src/sensesp/system/async_response_handler.h b/src/sensesp/system/async_response_handler.h index 636a34ffe..2f2ad142c 100644 --- a/src/sensesp/system/async_response_handler.h +++ b/src/sensesp/system/async_response_handler.h @@ -48,17 +48,17 @@ class AsyncResponseHandler : public ValueConsumer, status_ = AsyncResponseStatus::kPending; this->emit(status_); - if (timeout_reaction_ != nullptr) { - reactesp::ReactESP::app->remove(timeout_reaction_); - timeout_reaction_ = nullptr; + if (timeout_event_ != nullptr) { + reactesp::EventLoop::app->remove(timeout_event_); + timeout_event_ = nullptr; } - timeout_reaction_ = reactesp::ReactESP::app->onDelay(timeout_, [this]() { + timeout_event_ = reactesp::EventLoop::app->onDelay(timeout_, [this]() { if (status_ == AsyncResponseStatus::kPending) { ESP_LOGV("AsyncResponseHandler", "Timeout"); status_ = AsyncResponseStatus::kTimeout; this->emit(status_); } - this->timeout_reaction_ = nullptr; + this->timeout_event_ = nullptr; }); } @@ -70,10 +70,10 @@ class AsyncResponseHandler : public ValueConsumer, return; } - // Clear the timeout reaction - if (timeout_reaction_ != nullptr) { - reactesp::ReactESP::app->remove(timeout_reaction_); - timeout_reaction_ = nullptr; + // Clear the timeout event + if (timeout_event_ != nullptr) { + reactesp::EventLoop::app->remove(timeout_event_); + timeout_event_ = nullptr; } ESP_LOGV("AsyncResponseHandler", "Received response: %d", success); @@ -89,7 +89,7 @@ class AsyncResponseHandler : public ValueConsumer, const AsyncResponseStatus get_status() const { return status_; } protected: - reactesp::DelayReaction* timeout_reaction_ = nullptr; + reactesp::DelayEvent* timeout_event_ = nullptr; AsyncResponseStatus status_ = AsyncResponseStatus::kReady; String result_message_; int timeout_ = 3000; // Default timeout in ms diff --git a/src/sensesp/system/base_button.h b/src/sensesp/system/base_button.h index 294de6e62..14e72c9e4 100644 --- a/src/sensesp/system/base_button.h +++ b/src/sensesp/system/base_button.h @@ -32,7 +32,8 @@ class BaseButtonHandler : public Configurable, public IEventHandler { ESP_LOGD(__FILENAME__, "Button handler started"); - reactesp::ReactESP::app->onRepeat(4, [this]() { this->button_->check(); }); + SensESPBaseApp::get_event_loop()->onRepeat( + 4, [this]() { this->button_->check(); }); } protected: diff --git a/src/sensesp/system/led_blinker.cpp b/src/sensesp/system/led_blinker.cpp index 049dd9e67..1267467a2 100644 --- a/src/sensesp/system/led_blinker.cpp +++ b/src/sensesp/system/led_blinker.cpp @@ -11,7 +11,7 @@ namespace sensesp { BaseBlinker::BaseBlinker(int pin) : pin_{pin} { pinMode(pin, OUTPUT); - reactesp::ReactESP::app->onDelay(1, [this]() { this->tick(); }); + SensESPBaseApp::get_event_loop()->onDelay(1, [this]() { this->tick(); }); } /** @@ -44,13 +44,13 @@ void BaseBlinker::blip(int duration) { bool const orig_state = this->state_; this->set_state(false); int const current_counter = this->update_counter_; - reactesp::ReactESP::app->onDelay( + SensESPBaseApp::get_event_loop()->onDelay( duration, [this, duration, orig_state, current_counter]() { // only update if no-one has touched the LED in the meanwhile if (this->update_counter_ == current_counter) { this->set_state(true); int const new_counter = this->update_counter_; - reactesp::ReactESP::app->onDelay( + SensESPBaseApp::get_event_loop()->onDelay( duration, [this, orig_state, new_counter]() { // again, only update if no-one has touched the LED if (this->update_counter_ == new_counter) { @@ -75,7 +75,7 @@ void BaseBlinker::set_enabled(bool state) { } else { this->set_state(false); if (was_enabled) { - reaction_->remove(); + event_->remove(SensESPBaseApp::get_event_loop()); } } } @@ -91,8 +91,8 @@ void EvenBlinker::tick() { return; } this->flip_state(); - reaction_ = - reactesp::ReactESP::app->onDelay(period_, [this]() { this->tick(); }); + event_ = SensESPBaseApp::get_event_loop()->onDelay( + period_, [this]() { this->tick(); }); } RatioBlinker::RatioBlinker(int pin, unsigned int period, float ratio) @@ -107,8 +107,8 @@ void RatioBlinker::tick() { int const off_duration = max(0, period_ - on_duration); unsigned int const ref_duration = state_ == false ? off_duration : on_duration; - reaction_ = reactesp::ReactESP::app->onDelay(ref_duration, - [this]() { this->tick(); }); + event_ = SensESPBaseApp::get_event_loop()->onDelay( + ref_duration, [this]() { this->tick(); }); } PatternBlinker::PatternBlinker(int pin, int pattern[]) @@ -137,16 +137,16 @@ void PatternBlinker::tick() { // odd indices indicate times when LED should be OFF, even when ON bool const new_state = (pattern_ptr_ % 2) == 0; this->set_state(new_state); - reaction_ = reactesp::ReactESP::app->onDelay(pattern_[pattern_ptr_++], - [this]() { this->tick(); }); + event_ = SensESPBaseApp::get_event_loop()->onDelay( + pattern_[pattern_ptr_++], [this]() { this->tick(); }); } void PatternBlinker::restart() { state_ = false; pattern_ptr_ = 0; - if (reaction_ != NULL) { - reaction_->remove(); - reaction_ = NULL; + if (event_ != NULL) { + event_->remove(SensESPBaseApp::get_event_loop()); + event_ = NULL; this->tick(); } } diff --git a/src/sensesp/system/led_blinker.h b/src/sensesp/system/led_blinker.h index f10e83f25..087347411 100644 --- a/src/sensesp/system/led_blinker.h +++ b/src/sensesp/system/led_blinker.h @@ -30,7 +30,7 @@ class BaseBlinker { bool enabled_ = true; bool state_ = false; int update_counter_ = 0; - reactesp::Reaction* reaction_ = NULL; + reactesp::Event* event_ = NULL; }; /** diff --git a/src/sensesp/system/stream_producer.h b/src/sensesp/system/stream_producer.h index cd5e6fde3..e9bbac6b4 100644 --- a/src/sensesp/system/stream_producer.h +++ b/src/sensesp/system/stream_producer.h @@ -14,7 +14,7 @@ namespace sensesp { class StreamCharProducer : public ValueProducer { public: StreamCharProducer(Stream* stream) : stream_{stream} { - read_reaction_ = reactesp::ReactESP::app->onAvailable(*stream_, [this]() { + read_event_ = reactesp::EventLoop::app->onAvailable(*stream_, [this]() { while (stream_->available()) { char c = stream_->read(); this->emit(c); @@ -24,7 +24,7 @@ class StreamCharProducer : public ValueProducer { protected: Stream* stream_; - reactesp::StreamReaction* read_reaction_; + reactesp::StreamEvent* read_event_; }; /** @@ -36,7 +36,7 @@ class StreamLineProducer : public ValueProducer { : stream_{stream}, max_line_length_{max_line_length} { static int buf_pos = 0; buf_ = new char[max_line_length_ + 1]; - read_reaction_ = reactesp::ReactESP::app->onAvailable(*stream_, [this]() { + read_event_ = reactesp::EventLoop::app->onAvailable(*stream_, [this]() { while (stream_->available()) { char c = stream_->read(); if (c == '\n') { @@ -59,7 +59,7 @@ class StreamLineProducer : public ValueProducer { const int max_line_length_; char* buf_; Stream* stream_; - reactesp::StreamReaction* read_reaction_; + reactesp::StreamEvent* read_event_; }; } // namespace sensesp diff --git a/src/sensesp/system/task_queue_producer.h b/src/sensesp/system/task_queue_producer.h index 64c07bd1b..169bd4257 100644 --- a/src/sensesp/system/task_queue_producer.h +++ b/src/sensesp/system/task_queue_producer.h @@ -3,6 +3,7 @@ #include "ReactESP.h" #include "observablevalue.h" +#include "sensesp_base_app.h" namespace sensesp { @@ -23,7 +24,7 @@ template class TaskQueueProducer : public ObservableValue { public: TaskQueueProducer(const T& value, - reactesp::ReactESP* consumer_app = reactesp::ReactESP::app, + reactesp::EventLoop* consumer_app = SensESPBaseApp::get_event_loop(), int queue_size = 1, unsigned int poll_rate = 990) : ObservableValue(value), queue_size_{queue_size} { queue_ = xQueueCreate(queue_size, sizeof(T)); @@ -31,7 +32,7 @@ class TaskQueueProducer : public ObservableValue { ESP_LOGE(__FILENAME__, "Failed to create queue"); } - // Create a repeat reaction that will poll the queue and emit the values + // Create a repeat event that will poll the queue and emit the values consumer_app->onRepeatMicros(poll_rate, [this]() { T value; while (xQueueReceive(queue_, &value, 0) == pdTRUE) { @@ -42,7 +43,7 @@ class TaskQueueProducer : public ObservableValue { TaskQueueProducer(const T& value, int queue_size = 1, unsigned int poll_rate = 990) - : TaskQueueProducer(value, reactesp::ReactESP::app, queue_size, + : TaskQueueProducer(value, SensESPBaseApp::get_event_loop(), queue_size, poll_rate) {} virtual void set(const T& value) override { diff --git a/src/sensesp/transforms/click_type.cpp b/src/sensesp/transforms/click_type.cpp index b1beba6de..ac57bc5cf 100644 --- a/src/sensesp/transforms/click_type.cpp +++ b/src/sensesp/transforms/click_type.cpp @@ -1,6 +1,7 @@ #include "click_type.h" #include "ReactESP.h" +#include "sensesp_base_app.h" namespace sensesp { @@ -53,7 +54,7 @@ void ClickType::on_button_press() { // of the double_click_interval. Remove any "SingleClick" report that may // have been queued up.... if (delayed_click_report_ != NULL) { - delayed_click_report_->remove(); + delayed_click_report_->remove(SensESPBaseApp::get_event_loop()); delayed_click_report_ = NULL; ESP_LOGD(__FILENAME__, "ClickType press is double click. Removed queued SingleClick " @@ -100,7 +101,7 @@ void ClickType::on_button_release() { // DoubleClick uint64_t const time_of_event = millis(); int64_t const pd = (long)press_duration_; - delayed_click_report_ = reactesp::ReactESP::app->onDelay( + delayed_click_report_ = SensESPBaseApp::get_event_loop()->onDelay( double_click_interval_ + 20, [this, pd, time_of_event]() { ESP_LOGD( __FILENAME__, @@ -128,7 +129,8 @@ void ClickType::on_button_release() { } void ClickType::emitDelayed(ClickTypes value) { - reactesp::ReactESP::app->onDelay(5, [this, value]() { this->emit(value); }); + SensESPBaseApp::get_event_loop()->onDelay( + 5, [this, value]() { this->emit(value); }); } void ClickType::on_click_completed() { diff --git a/src/sensesp/transforms/click_type.h b/src/sensesp/transforms/click_type.h index 98624952d..51241c845 100644 --- a/src/sensesp/transforms/click_type.h +++ b/src/sensesp/transforms/click_type.h @@ -95,7 +95,7 @@ class [[deprecated( /// if the second click of a double click comes through. This /// value will be NULL if no click report is currently /// queued up. - reactesp::DelayReaction* delayed_click_report_{}; + reactesp::DelayEvent* delayed_click_report_{}; /// Processes incoming values that represent a "ButonPress" event void on_button_press(); diff --git a/src/sensesp/transforms/debounce.h b/src/sensesp/transforms/debounce.h index 1ee855bca..8df3aec23 100644 --- a/src/sensesp/transforms/debounce.h +++ b/src/sensesp/transforms/debounce.h @@ -49,13 +49,13 @@ class Debounce : public SymmetricTransform { if (input != debounced_value_ || !value_received_) { debounced_value_ = input; - if (reaction_) { - reaction_->remove(); - reaction_ = nullptr; + if (event_) { + event_->remove(SensESPBaseApp::get_event_loop()); + event_ = nullptr; } - reaction_ = - reactesp::ReactESP::app->onDelay(ms_min_delay_, [this, input]() { - this->reaction_ = nullptr; + event_ = + SensESPBaseApp::get_event_loop()->onDelay(ms_min_delay_, [this, input]() { + this->event_ = nullptr; this->debounced_value_ = input; this->emit(input); }); @@ -67,7 +67,7 @@ class Debounce : public SymmetricTransform { int ms_min_delay_; bool value_received_ = false; T debounced_value_; - reactesp::DelayReaction* reaction_ = nullptr; + reactesp::DelayEvent* event_ = nullptr; virtual void get_configuration(JsonObject& doc) override { doc["min_delay"] = ms_min_delay_; } diff --git a/src/sensesp/transforms/press_repeater.cpp b/src/sensesp/transforms/press_repeater.cpp index 63b9916b2..79b48f6d8 100644 --- a/src/sensesp/transforms/press_repeater.cpp +++ b/src/sensesp/transforms/press_repeater.cpp @@ -12,7 +12,7 @@ PressRepeater::PressRepeater(const String& config_path, int integer_false, repeating_{false} { load_configuration(); - reactesp::ReactESP::app->onRepeat(10, [this]() { + SensESPBaseApp::get_event_loop()->onRepeat(10, [this]() { if (pushed_) { // A press is currently in progress if (repeating_) { diff --git a/src/sensesp/transforms/repeat.h b/src/sensesp/transforms/repeat.h index 073545ef1..585ddbf4d 100644 --- a/src/sensesp/transforms/repeat.h +++ b/src/sensesp/transforms/repeat.h @@ -29,17 +29,17 @@ class Repeat : public SymmetricTransform { void set(T input) override { this->emit(input); - if (repeat_reaction_ != nullptr) { - // Delete the old repeat reaction - repeat_reaction_->remove(); + if (repeat_event_ != nullptr) { + // Delete the old repeat event + repeat_event_->remove(); } - repeat_reaction_ = reactesp::ReactESP::app->onRepeat( + repeat_event_ = reactesp::EventLoop::app->onRepeat( interval_, [this]() { this->notify(); }); } protected: long interval_; - reactesp::RepeatReaction* repeat_reaction_ = nullptr; + reactesp::RepeatEvent* repeat_event_ = nullptr; }; // For compatibility with the old RepeatReport class @@ -59,22 +59,22 @@ class RepeatStopping : public Repeat { : Repeat(interval), max_age_{max_age} { age_ = max_age; - if (this->repeat_reaction_ != nullptr) { - // Delete the old repeat reaction - this->repeat_reaction_->remove(); + if (this->repeat_event_ != nullptr) { + // Delete the old repeat event + this->repeat_event_->remove(); } - this->repeat_reaction_ = reactesp::ReactESP::app->onRepeat( + this->repeat_event_ = reactesp::EventLoop::app->onRepeat( this->interval_, [this]() { this->repeat_function(); }); } virtual void set(const T& input) override { this->emit(input); age_ = 0; - if (this->repeat_reaction_ != nullptr) { - // Delete the old repeat reaction - this->repeat_reaction_->remove(); + if (this->repeat_event_ != nullptr) { + // Delete the old repeat event + this->repeat_event_->remove(); } - this->repeat_reaction_ = reactesp::ReactESP::app->onRepeat( + this->repeat_event_ = reactesp::EventLoop::app->onRepeat( this->interval_, [this]() { this->repeat_function(); }); } @@ -87,10 +87,10 @@ class RepeatStopping : public Repeat { if (age_ < max_age_) { this->notify(); } else { - if (this->repeat_reaction_ != nullptr) { - // Delete the old repeat reaction - this->repeat_reaction_->remove(); - this->repeat_reaction_ = nullptr; + if (this->repeat_event_ != nullptr) { + // Delete the old repeat event + this->repeat_event_->remove(); + this->repeat_event_ = nullptr; } } }; @@ -109,22 +109,22 @@ class RepeatExpiring : public Repeat { : Repeat(interval), max_age_{max_age}, expired_value_{expired_value} { age_ = max_age; - if (this->repeat_reaction_ != nullptr) { - // Delete the old repeat reaction - this->repeat_reaction_->remove(); + if (this->repeat_event_ != nullptr) { + // Delete the old repeat event + this->repeat_event_->remove(); } - this->repeat_reaction_ = reactesp::ReactESP::app->onRepeat( + this->repeat_event_ = reactesp::EventLoop::app->onRepeat( this->interval_, [this]() { this->repeat_function(); }); } virtual void set(const T& input) override { this->emit(input); age_ = 0; - if (this->repeat_reaction_ != nullptr) { - // Delete the old repeat reaction - this->repeat_reaction_->remove(); + if (this->repeat_event_ != nullptr) { + // Delete the old repeat event + this->repeat_event_->remove(); } - this->repeat_reaction_ = reactesp::ReactESP::app->onRepeat( + this->repeat_event_ = reactesp::EventLoop::app->onRepeat( this->interval_, [this]() { this->repeat_function(); }); } @@ -161,12 +161,12 @@ class RepeatConstantRate : public RepeatExpiring { public: RepeatConstantRate(long interval, long max_age, T expired_value) : RepeatExpiring(interval, max_age, expired_value) { - if (this->repeat_reaction_ != nullptr) { - // Delete the old repeat reaction - this->repeat_reaction_->remove(); + if (this->repeat_event_ != nullptr) { + // Delete the old repeat event + this->repeat_event_->remove(); } - this->repeat_reaction_ = reactesp::ReactESP::app->onRepeat( + this->repeat_event_ = reactesp::EventLoop::app->onRepeat( interval, [this]() { this->repeat_function(); }); } diff --git a/src/sensesp_app_builder.h b/src/sensesp_app_builder.h index ba82b8721..bb8549614 100644 --- a/src/sensesp_app_builder.h +++ b/src/sensesp_app_builder.h @@ -220,7 +220,7 @@ class SensESPAppBuilder : public SensESPBaseAppBuilder { input == SystemStatus::kWifiNoAP) { ESP_LOGW(__FILENAME__, "Unable to connect to wifi for too long; restarting."); - reactesp::ReactESP::app->onDelay(1000, []() { ESP.restart(); }); + SensESPBaseApp::get_event_loop()->onDelay(1000, []() { ESP.restart(); }); } })); diff --git a/src/sensesp_base_app.cpp b/src/sensesp_base_app.cpp index 2fc527fe8..807002111 100644 --- a/src/sensesp_base_app.cpp +++ b/src/sensesp_base_app.cpp @@ -31,6 +31,14 @@ SensESPBaseApp::SensESPBaseApp() : filesystem_(new Filesystem()) { */ SensESPBaseApp* SensESPBaseApp::get() { return instance_; } +/** + * @brief Get the event loop object from the singleton SensESPBaseApp instance. + * + */ + reactesp::EventLoop* SensESPBaseApp::get_event_loop() { + return &(SensESPBaseApp::get()->event_loop_); +} + /** * @brief Perform initialization of SensESPBaseApp once builder configuration is * done. @@ -51,7 +59,7 @@ void SensESPBaseApp::reset() { "Resetting the device configuration to system defaults."); Resettable::reset_all(); - reactesp::ReactESP::app->onDelay(1000, []() { + this->event_loop_.onDelay(1000, []() { ESP.restart(); delay(1000); }); diff --git a/src/sensesp_base_app.h b/src/sensesp_base_app.h index 4fa613baa..c9fb37354 100644 --- a/src/sensesp_base_app.h +++ b/src/sensesp_base_app.h @@ -56,6 +56,8 @@ class SensESPBaseApp { static String get_hostname(); + static reactesp::EventLoop* get_event_loop(); + protected: /** * @brief Construct a new SensESP Base App object @@ -68,6 +70,8 @@ class SensESPBaseApp { virtual void setup(); + reactesp::EventLoop event_loop_; + static SensESPBaseApp* instance_; PersistingObservableValue* hostname_{};