Project-agnostic ESP-IDF component that renders a configurable, LVGL-based menu on OLED (SSD1306/SH1107) with a rotary encoder. Menu structure is defined in JSON and compiled to C via Jinja2 templates.
- LVGL UI with focus styles that work on monochrome OLEDs
- JSON-driven menu; code generated from templates (no manual UI wiring)
- Works as a reusable component or via the included example
- Rotary encoder + button input, NVS persistence hooks
Always build from the example directory, not the repo root.
- Configure hardware and features
cd examples/basic_menu
idf.py menuconfig # ESP Menu Configuration → set display, height, encoder pins/count- Generate menu code (from repo root) after editing
assets/menu.json
cd ../..
python3 scripts/generate_menu_from_templates.py assets/menu.json components/esp_menu/generated assets/templates- Build, flash, and monitor
cd examples/basic_menu
idf.py build flash monitorVS Code tasks are provided: Build Example, Flash Example, Monitor Example.
- Add this repo as a component (via git submodule or by setting
EXTRA_COMPONENT_DIRS). - Managed dependencies are declared in
components/esp_menu/idf_component.ymland resolved by IDF Component Manager (requires ESP-IDF 5.4+):- lvgl/lvgl
- espressif/esp_lvgl_port
- espressif/button
- espressif/knob
- esp_lcd
- nvs_flash
- Call the one-line init in your app:
#include "esp_menu.h"
void app_main(void) {
ESP_ERROR_CHECK(esp_menu_init());
}- Source of truth:
assets/menu.json - Templates:
assets/templates/menu.c.j2andmenu.h.j2 - Generated files:
components/esp_menu/generated/menu.candmenu_data.h
Regenerate after any JSON or template change:
python3 scripts/generate_menu_from_templates.py assets/menu.json components/esp_menu/generated assets/templatesDo not edit generated C files directly. Make changes in the templates.
components/esp_menu/
include/ # public headers (esp_menu.h, user_actions.h)
src/ # core implementation (esp_menu.c)
assets/ # reference JSON/templates (fallbacks)
generated/ # auto-generated menu.c/menu_data.h
idf_component.yml
assets/ # project-level JSON/templates & user_* (preferred)
scripts/ # generator script
examples/basic_menu
ESP Menu Configuration includes:
- OLED type: SSD1306 or SH1107
- Display height: 64 or 32 px
- I2C host/SDA/SCL/address
- Rotary encoder count (1–4) and pins (A/B/button) per encoder
- Optional NVS integration
See DISPLAY_CONFIG.md for details.
- Implement your app’s actions in
assets/user_actions.c(project-level) orcomponents/esp_menu/assets/user_actions.c(fallback). - Action prototypes are generated into
menu_data.hbased on callbacks found inmenu.json. - If NVS is enabled, implement
user_save_params_to_nvs()anduser_load_params_from_nvs()inuser_actions.c.
-
Unknown CMake command idf_component_register / “No project() command”
- You’re building from the repo root. Build from
examples/basic_menu/.
- You’re building from the repo root. Build from
-
Failed to resolve component 'lvgl' (or 'lvgl__lvgl')
- Ensure ESP-IDF 5.4+ is active and
examples/basic_menuis using IDF’s Component Manager. Re-runidf.py reconfigure.
- Ensure ESP-IDF 5.4+ is active and
-
I2C conflict “driver_ng is not allowed to be used with this old driver”
- Avoid mixing legacy
driver/i2c.hwithesp_driver_i2c. This component uses the modern driver.
- Avoid mixing legacy
-
No focus highlight when turning encoder
- The component sets the encoder’s LVGL group as default and applies focus styles; ensure generated code is up to date and the example is flashed.
MIT. See LICENSE.
- ESP-IDF — https://github.com/espressif/esp-idf
- LVGL — https://lvgl.io/