idf-new is a command-line tool that generates clean, minimal ESP-IDF projects for specific ESP32 boards. Pick a board, pick optional peripherals and modules, and get a ready-to-build project — without copy-pasting old repos or re-discovering pinouts.
idf-new my_project --board waveshare/wvshr200_touch --feature tf_card --module gps_neo6mgit clone https://github.com/dmatking/esp32-idf-new.git
cd esp32-idf-new
python3 -m venv .venv
source .venv/bin/activate
pip install -e idf_new_toolThe
-e(editable) flag is required — idf-new readsboards/,modules/, andidf-templates/directly from the repo checkout at runtime.
After the initial setup, activate the venv at the start of each session alongside ESP-IDF:
source ~/esp/esp-idf/export.sh
source ~/esp32-idf-new/.venv/bin/activateOn Debian/Raspberry Pi OS, system Python is externally managed and blocks global pip installs. A venv sidesteps this cleanly. If you'd prefer a one-liner without a venv, see Alternative: system-wide install.
Generate a project:
idf-new my_project --board generic
cd my_project
idf.py set-target <esp32 | esp32s3 | esp32c3 | etc.>
idf.py build flash monitorIf you see serial output from your board, you're up and running.
The generic board target builds a minimal FreeRTOS heartbeat project and should run on nearly any ESP32. It's a good smoke test to verify a board powers up, flashes, and runs correctly.
idf-new assumes a working ESP-IDF development environment.
You'll need:
- Python 3.11+
- ESP-IDF installed and
idf.pyavailable in your shell (tested with ESP-IDF v5.5.1)
Quick sanity check:
python --version
idf.py --versionIf
idf.pyis not found, install ESP-IDF using Espressif's official installer or setup guide for your OS.
idf-new does not install ESP-IDF for you — it generates projects that ESP-IDF builds and flashes.
idf-new is built around three tiers:
1. Boards — Hardware-specific wiring, pin definitions, LCD/touch initialization, and display drawing primitives. Every board implements a small C interface (board_interface.h).
2. Board Features — Optional peripherals that are physically on the board (TF card slot, speaker, buttons, etc.). These are board-specific — a feature only exists if the board has that hardware.
3. Modules — Generic off-the-shelf breakout boards you wire up yourself (GPS, sensors, IMUs, etc.). Modules use menuconfig for pin selection and work across any board.
Plus the base Template — a minimal ESP-IDF project with no hardware assumptions that everything is built on top of.
idf-new/
├── boards/ # Board wiring & pin definitions (per-board C files)
│ └── <vendor>/
│ └── <board>/
│ ├── board_impl.c # Required: implements board_interface.h
│ ├── board.json # Metadata for CLI listing
│ ├── idf_component.yml # Component dependencies
│ ├── main.cmake.extra # Optional CMake additions
│ └── features/ # Optional on-board peripherals
│ └── <name>/ # e.g. tf_card/, speaker/, buttons/
├── modules/ # Generic breakout board drivers
│ └── gps/
│ ├── _common/ # Shared NMEA/UART core (gps.c, gps.h, Kconfig)
│ ├── neo6m/ # u-blox NEO-6M / GY-NEO6MV2
│ └── atgm336h/ # ATGM336H
├── idf-templates/ # Minimal ESP-IDF base project template
└── idf_new_tool/ # Python CLI and generator
idf-new myapp --board waveshare/wvshr200_touch --feature tf_card --module gps_neo6mThis command:
- Copies the base ESP-IDF template
- Installs the selected board's wiring (
board_impl.c, helpers, component deps) - Applies selected board features (copies
boards/.../features/tf_card/into the project) - Applies selected modules (copies
modules/gps/_common/gps.c,gps.h, mergesKconfig) - Merges all
idf_component.ymldependency declarations - Updates project name and CMake config
The result is a minimal, fully wired ESP-IDF project ready to build.
idf-new --list-boards # All supported boards
idf-new --list-modules # All generic modules (GPS, sensors, etc.)Board features are board-specific — check boards/<vendor>/<board>/features/ or the board's board.json for what a given board supports.
- Create
boards/<vendor>/<board_name>/ - Add
board_impl.cimplementing the functions fromboard_interface.h:- Required:
board_init(),board_get_name(),board_has_lcd() - LCD boards:
board_lcd_sanity_test(),board_lcd_fill(), plus the display drawing API (board_lcd_width(),board_lcd_height(),board_lcd_flush(),board_lcd_clear(),board_lcd_set_pixel_raw(),board_lcd_set_pixel_rgb(),board_lcd_pack_rgb(),board_lcd_get_pixel_raw(),board_lcd_unpack_rgb()) - Weak no-op defaults are provided in
board_defaults.cfor headless boards
- Required:
- Optionally add:
board.json— metadata for--list-boardsidf_component.yml— component dependenciesmain.cmake.extra— CMake additions (extra sources, defines, requires)- Additional
.c/.hhelper files (copied into generated project automatically) features/<name>/— optional on-board peripheral implementations
- Test:
idf-new test_proj --board <vendor>/<board_name>
Board features live under boards/<vendor>/<board>/features/<name>/ and represent optional peripherals physically on that board (TF card, speaker, buttons, etc.).
- Create
boards/<vendor>/<board>/features/<name>/ - Add any combination of:
.c/.hsource files (copied into generated project'smain/)Kconfig— appended toKconfig.projbuildidf_component.yml— merged into project dependenciesmain.cmake.extra— appended to project's CMake extras
- Add
"board_features": ["<name>"]to the board'sboard.json
Enable via:
idf-new my_project --board <vendor>/<board> --feature <name>The --feature flag is repeatable: --feature tf_card --feature buttons
Modules are generic drivers for off-the-shelf breakout boards. Pins are configured via menuconfig.
- Create
modules/<category>/<module_name>/with amodule.jsondescriptor - Add shared C code under
modules/<category>/_common/(or directly in the module dir) - Add a
Kconfigwith pin and configuration options - Create
idf_new_tool/idf_new/modules/<category>.py:- Implement the
Moduleprotocol (name,flag,category,apply()) - Call
register()at module load apply()copies source files and merges Kconfig into the project
- Implement the
Enable via:
idf-new my_project --board generic --module <flag>Use idf-new --list-modules to see registered modules.
For boards with an LCD, --sim adds a native desktop build that renders your display code in an SDL2 window — no hardware needed. It can also save PNG screenshots for documentation.
idf-new my_project --board waveshare/wvshr_p4_720_touch --simThis creates a sim/ directory inside the generated project:
my_project/
├── main/ # Your ESP-IDF app code (runs on device)
└── sim/
├── CMakeLists.txt
├── main_sim.c # Desktop entry point (replace gradient with your rendering)
└── screencap/ # git submodule — esp32-screencap library
The sim compiles your project's main/ drawing code (via board_interface.h) against a native SDL2 backend instead of real hardware. Your rendering code runs unchanged.
cd my_project/sim
mkdir build && cd build
cmake .. && make
./my_project_sim # interactive SDL2 window
./my_project_sim --screenshot out.png --frames 1 # headless PNG capturePrerequisites: libsdl2-dev (Debian/Ubuntu: sudo apt install libsdl2-dev)
- Live SDL2 window with integer-scaled preview
- Press P to save a screenshot (
screenshot_NNNN.png) - Esc or close the window to quit
Works over SSH with no display server — useful for CI or headless Pis:
./my_project_sim --screenshot summary.png --frames 1--frames N runs N iterations of your render loop before saving. This lets you capture specific screens if your app cycles through multiple views.
The sim reuses your project's rendering code through board_interface.h — the same HAL that idf-new scaffolds for every LCD board. A generic board_interface_sim.c (provided by esp32-screencap) implements the HAL against an in-memory framebuffer. SDL2 displays it on screen; stb_image_write saves it as PNG.
Your drawing code doesn't know or care whether it's running on an ESP32 or a desktop — it just calls board_lcd_set_pixel_rgb(), board_lcd_flush(), etc.
To view the SDL2 window from a remote Pi on your local machine:
ssh -X user@pi
cd my_project/sim/build && ./my_project_simOn Windows, WSL2 with WSLg handles X11 forwarding natively — just ssh -X from a WSL terminal.
idf-new must be installed as an editable install from the repo checkout — it reads boards/, modules/, and idf-templates/ from the repo at runtime.
git clone https://github.com/dmatking/esp32-idf-new.git
cd esp32-idf-new
python3 -m venv .venv
source .venv/bin/activate
pip install -e idf_new_toolTo update: just git pull in the repo — no reinstall needed.
If you don't want to manage a venv, you can install directly into your user Python environment. On Debian/Raspberry Pi OS you'll need to pass --break-system-packages:
pip install -e idf_new_tool --break-system-packagesThis is safe for a dev tool with a single dependency (PyYAML), but the venv approach above is cleaner and won't interfere with system packages.
idf-new grew out of repeatedly solving the same ESP-IDF setup problems across many boards and projects.
Rather than maintaining dozens of near-duplicate repos, this tool centralizes:
- board wiring knowledge
- optional peripheral implementations
- generic driver modules
- clean project structure
The goal is to make starting a new ESP32 project boring — in the best possible way.
All original code in this repository is licensed under the Apache License 2.0.
ESP-IDF and bundled third-party libraries are licensed separately under permissive licenses (Apache, MIT, BSD, etc.).
Built with:
- Python 3.13.5
- ESP-IDF 5.5.1
- Claude Code