{"id":15416876,"url":"https://github.com/mairas/reactesp","last_synced_at":"2025-04-09T10:06:56.470Z","repository":{"id":33171101,"uuid":"152993896","full_name":"mairas/ReactESP","owner":"mairas","description":"An asynchronous programming library for the ESP32 and other microcontrollers using the Arduino framework.","archived":false,"fork":false,"pushed_at":"2024-10-30T10:13:18.000Z","size":1386,"stargazers_count":71,"open_issues_count":7,"forks_count":9,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-02T08:09:17.261Z","etag":null,"topics":["esp32","esp32-arduino"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mairas.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-10-14T16:20:32.000Z","updated_at":"2025-03-27T05:27:30.000Z","dependencies_parsed_at":"2025-01-15T18:18:52.116Z","dependency_job_id":"2af14c5e-d0f7-4ab5-b701-4a5faf111aa5","html_url":"https://github.com/mairas/ReactESP","commit_stats":{"total_commits":105,"total_committers":7,"mean_commits":15.0,"dds":0.4476190476190476,"last_synced_commit":"884253e782984120e83c92d495e7df384f6efb23"},"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mairas%2FReactESP","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mairas%2FReactESP/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mairas%2FReactESP/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mairas%2FReactESP/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mairas","download_url":"https://codeload.github.com/mairas/ReactESP/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248018060,"owners_count":21034048,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["esp32","esp32-arduino"],"created_at":"2024-10-01T17:14:04.053Z","updated_at":"2025-04-09T10:06:56.445Z","avatar_url":"https://github.com/mairas.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ReactESP\n\n![C++](https://img.shields.io/badge/language-C++-blue.svg)\n[![license: MIT](https://img.shields.io/badge/license-MIT-brightgreen.svg)](https://opensource.org/licenses/MIT)\n\nBy [Matti Airas](https://github.com/mairas)\n\nAn asynchronous programming and event loop library for the ESP32 and other microcontrollers using the Arduino framework.\n\nThe library is at the core of the [SensESP](https://github.com/SignalK/SensESP) project but is completely generic and can be used for standalone projects without issues.\n\nThis library gets much of its inspiration (and some code) from [`Reactduino`](https://github.com/Reactduino/Reactduino). `ReactESP`, however, has been internally re-implemented for maintainability and readability, and has significantly better performance when there are lots of defined events. It also supports arbitrary callables as callbacks, allowing parametric creation of callback functions.\n\n## Blink\n\nIf you have worked with the Arduino framework before, it is likely that you will have come across the [blink sketch](https://www.arduino.cc/en/tutorial/blink). This is a simple program that flashes an LED every second, and it looks something like this:\n\n```cpp\n#include \u003cArduino.h\u003e\n\nvoid setup() {\n  pinMode(LED_BUILTIN, OUTPUT);\n}\n\nvoid loop() {\n  digitalWrite(LED_BUILTIN, HIGH);\n  delay(1000);\n  digitalWrite(LED_BUILTIN, LOW);\n  delay(1000);\n}\n```\n\nUsing ReactESP, the sketch can be rewritten to the following:\n\n```cpp\n#include \u003cReactESP.h\u003e\n\nusing namespace reactesp;\n\nEventLoop event_loop;\n\nsetup() {\n  pinMode(LED_BUILTIN, OUTPUT);\n\n  event_loop.onRepeat(1000, [] () {\n      static bool state = false;\n      digitalWrite(LED_BUILTIN, state = !state);\n  });\n}\n\nvoid loop() {\n  event_loop.tick();\n}\n```\n\nInstead of directly defining the program logic in the `loop()` function, _events_ are defined in the `setup()` function. An event is a function that is executed when a certain event happens. In this case, the event is that the function should repeat every second, as defined by the `onRepeat()` method call. The second argument to the `onRepeat()` method is a [lambda function](http://en.cppreference.com/w/cpp/language/lambda) that is executed every time the event is triggered. If the syntax feels weird, you can also use regular named functions instead of lambdas.\n\nThe `event_loop.tick()` call in the `loop()` function is the main loop of the program. It is responsible for calling the events that have been defined. You can also add additional code to the `loop()` function, any delays or other long-executing code should be avoided.\n\n## Why Bother?\n\nCharlie wants to make a simple program which echoes data on the `Serial` port. Their Arduino sketch will looks like this:\n\n```cpp\n#include \u003cArduino.h\u003e\n\nvoid setup()\n{\n    Serial.begin(9600);\n}\n\nvoid loop()\n{\n    if (Serial.available() \u003e 0) {\n        Serial.write(Serial.read());\n    }\n\n    yield();\n}\n```\n\nThis works, but Charlie decides that they would like to blink the built-in LED every time it processes data. Now, their sketch looks like this:\n\n```cpp\n#include \u003cArduino.h\u003e\n\nvoid setup()\n{\n    Serial.begin(9600);\n    pinMode(LED_BUILTIN, OUTPUT);\n}\n\nvoid loop()\n{\n    if (Serial.available() \u003e 0) {\n        Serial.write(Serial.read());\n\n        digitalWrite(LED_BUILTIN, HIGH);\n        delay(20);\n        digitalWrite(LED_BUILTIN, LOW);\n    }\n\n    yield();\n}\n```\n\nThe problem with this sketch is that whilst the LED is blinking, Charlie's program is not relaying data from the Serial port. The longer Charlie blinks the LED for, the slower the rate of transfer.\n\nTo solve this problem, Charlie refactors their code to look something like this:\n\n```cpp\n#include \u003cArduino.h\u003e\n\nuint32_t start;\nbool blink = false;\n\nvoid setup()\n{\n    Serial.begin(9600);\n    pinMode(LED_BUILTIN, OUTPUT);\n}\n\nvoid loop()\n{\n    if (Serial.available() \u003e 0) {\n        Serial.write(Serial.read());\n\n        blink = true;\n        start = millis();\n        digitalWrite(LED_BUILTIN, HIGH);\n    }\n\n    if (blink \u0026\u0026 millis() - start \u003e 1000) {\n        blink = false;\n        digitalWrite(LED_BUILTIN, LOW);\n    }\n\n    yield();\n}\n```\n\nThis solves Charlie's problem, but it's quite verbose. Using ReactESP, Charlie can write the same script like this:\n\n```c++\n#include \u003cReactESP.h\u003e\n\nusing namespace reactesp;\n\nEventLoop event_loop;\n\nvoid setup() {\n  Serial.begin(9600);\n  pinMode(LED_BUILTIN, OUTPUT);\n\n  event_loop.onAvailable(\u0026Serial, [] () {\n    Serial.write(Serial.read());\n    digitalWrite(LED_BUILTIN, HIGH);\n\n    event_loop.onDelay(1000, [] () { digitalWrite(LED_BUILTIN, LOW); });\n  });\n}\n\nvoid loop() {\n  event_loop.tick();\n}\n```\n\n## Advanced callback support\n\nCallbacks can be not just void pointers but any callable supported by `std::function`. This means they can use lambda captures or argument binding using `std::bind`. For example, the following code creates 20 different repeating events updating different fields of an array:\n\n```c++\nstatic int timer_ticks[20];\n\nfor (int i=0; i\u003c20; i++) {\n  timer_ticks[i] = 0;\n  int delay = (i+1)*(i+1);\n  event_loop.onRepeat(delay, [i]() {\n    timer_ticks[i]++;\n  });\n}\n```\n\n## API\n\n### Namespace use\n\nNote that beginning of ReactESP 2.0.0, the ReactESP library has been wrapped in\na `reactesp` namespace.\nThis is to avoid name conflicts with other libraries.\n\nThe impact to the user is that they need to define the namespace when using the library.\nThis can be done either globally by placing the following statement in the source code right after the `#include` statements:\n\n    using namespace reactesp;\n\nThis shouldn't be done in header files, however! Alternatively, the `reactesp::` prefix can be used when using the library:\n\n    reactesp::EventLoop event_loop;\n\n### Event Registration Functions\n\nAll of the registration functions return an `Event` object pointer. This can be used to store and manipulate\nthe event. `react_callback` is a typedef for `std::function\u003cvoid()\u003e` and can therefore be any callable supported by the C++ standard template library.\n\n```cpp\nDelayEvent event_loop.onDelay(uint32_t t, react_callback cb);\n```\n\nDelay the executation of a callback by `t` milliseconds.\n\n```cpp\nRepeatEvent event_loop.onRepeat(uint32_t t, react_callback cb);\n```\n\nRepeatedly execute a callback every `t` milliseconds.\n\n```cpp\nStreamEvent event_loop.onAvailable(Stream *stream, react_callback cb);\n```\n\nExecute a callback when there is data available to read on an input stream (such as `\u0026Serial`).\n\n```cpp\nISREvent event_loop.onInterrupt(uint8_t pin_number, int mode, react_callback cb);\n```\n\nExecute a callback when an interrupt number fires. This uses the same API as the `attachInterrupt()` Arduino function.\n\n```cpp\nTickEvent event_loop.onTick(react_callback cb);\n```\n\nExecute a callback on every tick of the event loop.\n\n### Management functions\n\n```cpp\nvoid Event::remove();\n```\n\nRemove the event from the execution queue.\n\n*Note*: Calling `remove()` for `DelayEvent` objects is only safe if the event has not been triggered yet. Upon triggering, the `DelayEvent` object is deleted and any pointers to it will be invalidated.\n\n### Examples\n\n- [`Minimal`](examples/minimal/src/main.cpp): A minimal example with two timers switching the LED state.\n\n- [`Torture test`](examples/torture_test/src/main.cpp): A stress test of twenty simultaneous repeat events as well as a couple of interrupts, a stream, and a tick event. For kicks, try changing `NUM_TIMERS` to 200. Program performance will be practically unchanged!\n\n## Changes between version 2 and 3\n\n- Renamed classes from ReactESP to EventLoop and from *Reaction to *Event to better\n  reflect their purpose.\n- Removed the `app` singleton. The user is now responsible for maintaining the EventLoop object.\n\n## Changes between version 1 and 2\n\nReactESP version 2 has changed the software initialization approach from version 1.\nVersion 1 implemented the Arduino framework standard `setup()` and `loop()` functions behind the scenes,\nand a user just instantiated an EventLoop object and provided a setup function as an argument:\n\n    ReactESP app([]() {\n        app.onDelay(...);\n    });\n\nWhile this approach was \"neat\", it was also confusing to many users familiar with the Arduino framework. Therefore, ReactESP version 2 has reverted back to the more conventional approach:\n\n    ReactESP app;\n\n    void setup() {\n        app.onDelay(...);\n    }\n\n    void loop() {\n        app.tick();\n    }\n\nNote the changes:\n- ReactESP app object is instantiated without any arguments\n- There is an explicit `setup()` function.\n  Its contents can be copied verbatim from the version 1 lambda function.\n- There is an explicit `loop()` function.\n  `app.tick()` must be called in the loop.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmairas%2Freactesp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmairas%2Freactesp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmairas%2Freactesp/lists"}