{"id":21446951,"url":"https://github.com/etdds/esp-idf-button-events","last_synced_at":"2025-03-17T01:43:02.741Z","repository":{"id":158476554,"uuid":"620268278","full_name":"etdds/esp-idf-button-events","owner":"etdds","description":null,"archived":false,"fork":false,"pushed_at":"2023-11-16T09:39:01.000Z","size":114,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-23T11:33:26.854Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/etdds.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":"2023-03-28T11:02:01.000Z","updated_at":"2023-04-28T23:55:06.000Z","dependencies_parsed_at":"2025-01-23T11:39:41.310Z","dependency_job_id":null,"html_url":"https://github.com/etdds/esp-idf-button-events","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/etdds%2Fesp-idf-button-events","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/etdds%2Fesp-idf-button-events/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/etdds%2Fesp-idf-button-events/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/etdds%2Fesp-idf-button-events/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/etdds","download_url":"https://codeload.github.com/etdds/esp-idf-button-events/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243960448,"owners_count":20375101,"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":[],"created_at":"2024-11-23T03:08:24.272Z","updated_at":"2025-03-17T01:43:02.716Z","avatar_url":"https://github.com/etdds.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ESP IDF Button Event Library\n\nA ESP IDF component for managing buttons tied to GPIO pins in a publish / suscribe fashion. The component internally handles button debouncing and allows subscription to the following events:\n - Button down event.\n - Button up event.\n - Button press event.\n - Button long press event.\n - Button held event.\n - Button held repeat event.\n\nGenerated events can be a one to many subscribers, or multiple events to a single subscriber. Button events are managed by a FSM triggered by ISR events and timer callbacks. Minimal to no processing time is required if no buttons are being toggled.\n\n# Example Usage\n\nThe following example is also located at `examples/buttons`.\n\n```c++\n#include \u003cfreertos/FreeRTOS.h\u003e\n#include \u003cfreertos/task.h\u003e\n#include \u003cstdio.h\u003e\n\n#include \u003cesp_idf_button_events/button.hpp\u003e\n\n#include \"esp_system.h\"\n\n#define LOG_TAG \"MAIN\"\n\n// Specify namespace to reduce verbosity.\nusing namespace ButtonEvents;\n\n// Specify a dummy class to demonstrate calling a class member on event handler.\nclass Object {\n public:\n  void handler() { ESP_LOGI(LOG_TAG, \"Class handler called\"); }\n};\n\n// Three event handlers which are called on button events.\nstatic void press_any(void* handler_args, esp_event_base_t base, int32_t id, void* event_data) {\n  auto event = EventData(event_data);\n  if(handler_args) {\n    auto arg = static_cast\u003cint*\u003e(handler_args);\n  }\n  ESP_LOGI(LOG_TAG, \"Any handler: %s: ID %li, arg: %d\", event.button-\u003ename(), id, *arg);\n}\n\nstatic void press_handler(void* handler_args, esp_event_base_t base, int32_t id, void* event_data) {\n  auto event = EventData(event_data);\n  ESP_LOGI(LOG_TAG, \"Press handler: %s: ID %li\", event.button-\u003ename(), id);\n}\n\nstatic void long_handler(void* handler_args, esp_event_base_t base, int32_t id, void* event_data) {\n  auto event = EventData(event_data);\n  ESP_LOGI(LOG_TAG, \"Long handler: %s: ID %li\", event.button-\u003ename(), id);\n}\n\nextern \"C\" void app_main(void) {\n  // Create a button using the Kconfig default options.\n  Button* button_a = Button::create(\"Button A\", GPIO_NUM_0);\n\n  // Create another button, with custom button specific configuration.\n  Button* button_b = Button::create(\"Button B\", GPIO_NUM_35)\n                       .inverted(false)\n                       .pull_up(true)\n                       .pull_down(false)\n                       .debounce_ms(50)\n                       .short_press_ms(100)\n                       .long_press_ms(1000)\n                       .hold_press_ms(3000)\n                       .hold_repeat_ms(200);\n\n\n  // Example value to pass through to the event handler.\n  uint32_t handler_value = 55;\n\n  // An object who's method is called on an event through a lambda.\n  Object object;\n\n  // Add handler for all events on button B.\n  button_b-\u003eadd_handler(press_any, \u0026handler_value, EventType::BUTTON_DOWN);\n  button_b-\u003eadd_handler(press_any, \u0026handler_value, EventType::BUTTON_UP);\n  button_b-\u003eadd_handler(press_any, \u0026handler_value, EventType::BUTTON_PRESS);\n  button_b-\u003eadd_handler(press_any, \u0026handler_value, EventType::BUTTON_LONG_PRESS);\n  button_b-\u003eadd_handler(press_any, \u0026handler_value, EventType::BUTTON_HELD);\n\n  // Add handler specifically press and long events on button B\n  button_b-\u003eadd_handler(press_handler, \u0026handler_value, EventType::BUTTON_PRESS);\n  button_b-\u003eadd_handler(long_handler, \u0026handler_value, EventType::BUTTON_LONG_PRESS);\n\n  // Add press and long handler for button A.\n  button_a-\u003eadd_handler(long_handler, \u0026handler_value, EventType::BUTTON_LONG_PRESS);\n  button_a-\u003eadd_handler(press_handler, \u0026handler_value, EventType::BUTTON_PRESS);\n\n  button_a-\u003eadd_handler(\n    [](void* handler_args, esp_event_base_t base, int32_t id, void* event_data) {\n      auto o = static_cast\u003cObject*\u003e(handler_args);\n      o-\u003ehandler();\n    },\n    \u0026object, EventType::BUTTON_PRESS);\n\n  ESP_LOGI(LOG_TAG, \"Waiting for events...\");\n  while(1) {\n    // Delay the task for 1000ms (1 second)\n    vTaskDelay(pdMS_TO_TICKS(1000));\n  }\n}\n\n```\n\nPossible output:\n```\nI (0) cpu_start: App cpu up.\nI (210) cpu_start: Pro cpu start user code\nI (210) cpu_start: cpu freq: 160000000 Hz\nI (210) cpu_start: Application information:\nI (215) cpu_start: Project name:     buttons\nI (220) cpu_start: App version:      1\nI (224) cpu_start: Compile time:     Apr 24 2023 09:06:09\nI (230) cpu_start: ELF file SHA256:  c431627ce8601034...\nI (236) cpu_start: ESP-IDF:          v5.0.1\nI (241) cpu_start: Min chip rev:     v0.0\nI (246) cpu_start: Max chip rev:     v3.99 \nI (251) cpu_start: Chip rev:         v3.0\nI (256) heap_init: Initializing. RAM available for dynamic allocation:\nI (263) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM\nI (269) heap_init: At 3FFB2988 len 0002D678 (181 KiB): DRAM\nI (275) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM\nI (281) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM\nI (288) heap_init: At 4008CB50 len 000134B0 (77 KiB): IRAM\nI (296) spi_flash: detected chip: winbond\nI (299) spi_flash: flash io: dio\nW (303) spi_flash: Detected size(16384k) larger than the size in the binary image header(2048k). Using the size in the binary image header.\nI (317) cpu_start: Starting scheduler on PRO CPU.\nI (0) cpu_start: Starting scheduler on APP CPU.\nI (328) gpio: GPIO[0]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:3 \nI (338) gpio: GPIO[35]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:3 \nI (348) MAIN: Waiting for events...\nI (2158) MAIN: Press handler: Button A: ID 2\nI (2158) MAIN: Class handler called\nI (3538) MAIN: Any handler: Button B: ID 1, arg: 55\nI (3718) MAIN: Any handler: Button B: ID 0, arg: 55\nI (3718) MAIN: Any handler: Button B: ID 2, arg: 55\n```\n\nTo build the example locally:\n```bash\n# Configure for ttgo-tdisplay. This only effects the GPIO numbers used in the board. Other boards can be tested by changing\n# The GPIO numbers in the example\ncd examples/buttons \u0026\u0026 rm -f sdkconfig* \u0026\u0026 cp ttgo-tdisplay.defaults sdkconfig.defaults \u0026\u0026 idf.py set-target esp32\n\n# Build the example (from the examples/buttons directory)\nidf.py build\n\n# Flash\nidf.py -p (PORT) flash\n\n# Monitor output\nidf.py -p (PORT) monitor\n\n# Clean\nidf.py fullclean\n\n```\n\n# Installation\n\n## ESP IDF component manager\n\nAdd to your main `idf_component.yml` file, under dependencies.\n\n```yaml\ndependencies:\n  esp-idf-button-events:\n    git: https://github.com/etdds/esp-idf-button-events.git\n```\n\n## Direct component\nAdd the repository as a standard IDF component.\n```\ngit clone https://github.com/etdds/esp-idf-button-events.git components/esp-idf-button-events\n```\n\n## Submodule component\nAdd the repository as a standard IDF component.\n```\ngit submodule add https://github.com/etdds/esp-idf-button-events.git components/esp-idf-button-events\n```\n\n# Configuration\n\nDefault configuration for buttons and tasks is done using KConfig. When using the ESP-IDF component manager, use `idf.py menuconfig` and browse to Component config -\u003e ESP IDF Button Events\n\n# Limitiations / TODO\n\nSome known limitations which may be addressed in the future. Feel free to implement and open a pull request, or open an issue to disccuss.\n  - There is a hard limit on the number of buttons which can be used (6). Some modification to the event generation FreeRTOS event bits needs to be done to support more.\n  - Buttons are never deinitialised, nor is there a method to release the memory allocated for the button. This should be added together.\n  - The button could be fetched by name, since the event manager keeps track of the button handlers. That way, the button handler doesn't need to be tracked externally.\n  - Timers for individual buttons have the same name.\n  - Could add an option to reduce the number of possible events. E.g filter out press down and press up events. Reducing load when an event occurs.\n  - Could add the option to use the inbuilt ESP event loop, to save resources.\n  - The manager task and event loop stack size / prioriy are just initial values. Some profiling could be done to choose better defaults.\n  - It is (currently) not possible to remove a handler from an event.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fetdds%2Fesp-idf-button-events","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fetdds%2Fesp-idf-button-events","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fetdds%2Fesp-idf-button-events/lists"}