Skip to content

Development Guide

Relevant source files

This document provides practical guidance for developers extending or modifying the PiBot CNC Pendant firmware. It covers common development tasks including adding settings, creating screens, extending G-code support, and working with the translation system.

Related Documentation:


Before diving into specific development tasks, understanding these foundational patterns is essential for maintaining code quality and consistency.

The firmware uses X-macros to define settings in a single location, generating both enum values and metadata tables at compile time. This ensures consistency between setting identifiers and their storage keys.

Title: Settings Generation Flow

esp3d_settings_defs.inc ESP3D_SET_DEF macros

esp3d_target_settings_defs.inc Target-specific macros

Enum Generation #include in esp3d_settings.h

Table Generation #include in esp3d_settings.cpp

ESP3DSettingIndex enum Public API identifiers

ESP3DSettingsData[] Metadata table

Compile-time validation NVS key length checks

Sources: main/core/includes/esp3d_settings.h#97-108, main/core/esp3d_settings.cpp#108-119, main/core/esp3d_settings.cpp#125-144

Icons and fonts are not compiled into the firmware but reside in a dedicated ui_resources flash partition. This allows for customization without full firmware reflashing.

Title: UI Resource Build Flow

PNG Sources resources/resolution/

Font Sources resources/fonts/

resources_config.py Metadata

generate_resources.py

ui_resources.bin Flash Partition

esp3d_ui_offsets.h Compiled Offsets

Sources: docs/guides/ui_resources_guide.md#46-56, docs/ui_resources/development.md#13-28, tools/build_scripts/generate_resources.py#156-159

All UI components follow a strict two-phase destruction pattern to prevent race conditions from late-arriving hardware events or callbacks.

Title: UI Component Lifecycle

Sources: main/display/cnc/fluidnc/screens/files_screen.cpp#104-107, main/display/cnc/fluidnc/screens/files_screen.cpp#139-145


The firmware uses a CMake-based build system integrated with the ESP-IDF. Feature selection is handled via OPTION() flags in the root CMakeLists.txt, which are then translated into C++ preprocessor defines in cmake/features.cmake.

For details, see Build System and Feature Flags.

Sources: CMakeLists.txt#6-55, cmake/features.cmake#6-64, cmake/sanity_check.cmake#68-77, main/CMakeLists.txt#25-33


Screens are the primary UI containers. Adding a new screen involves extending the GenericScreen class and registering the new type in the UIManager.

  1. Enum Definition: Add a new value to ESP3DScreenTypemain/display/cnc/fluidnc/screens/esp3d_screen_type.h#26-61.
  2. Implementation: Create a new class/namespace inheriting from GenericScreen patterns.
  3. Registration: Update the centralized createScreen() function to instantiate your class main/display/cnc/fluidnc/screens/esp3d_screen_type.cpp#122-232.

For details, see Adding New Screens.

Sources: main/display/cnc/fluidnc/screens/esp3d_screen_type.h#26-61, main/display/cnc/fluidnc/screens/esp3d_screen_type.cpp#122-232


Settings are persistent configuration values stored in NVS. The system uses an X-macro pattern defined in .inc files to manage metadata, validation, and defaults.

  • Definition: Modify esp3d_settings_defs.inc or esp3d_target_settings_defs.inc.
  • Validation: Implement custom logic in isValidIntegerSetting() or similar functions in esp3d_settings.cpp.
  • Access: Use esp3dTftsettings.readUint32() or esp3dTftsettings.readString().

For details, see Adding New Settings.

Sources: main/core/includes/esp3d_settings.h#97-108, main/core/esp3d_settings.cpp#699-737


The esp3dTftValues service manages real-time system state (e.g., positions, status).

For details, see Adding Real-time Values.

Sources: main/display/cnc/fluidnc/screens/files_screen.cpp#149-150, main/display/cnc/fluidnc/screens/files_screen.cpp#170-171


G-code handling is centralized in the ESP3DGcodeHandlerService.

  • Commands: Extend sendGcode() to support new custom commands.
  • Parsing: Modify parsing logic to handle new fields in the controller’s status report (e.g., MPos, WCO, or custom firmware fields).

For details, see Extending G-code Support.

Sources: main/display/cnc/fluidnc/screens/files_screen.cpp#159-160


The translation system uses X-macros to compile translations directly into the firmware, avoiding external file dependencies for core UI strings.

For details, see Working with Translations.

Sources: main/display/esp3d_translations_init.cpp#31-37, main/display/esp3d_translations_list.h#36-47, tools/language_packs/template.lng#11-122


Reusable components should inherit standard lifecycle patterns to ensure stability.

For details, see Creating Custom UI Components.

Sources: main/display/cnc/fluidnc/screens/files_screen.cpp#139-145, main/display/cnc/fluidnc/screens/esp3d_screen_type.h#64-76


The firmware includes several tools for development:

For details, see Debugging and Testing.

Sources: main/display/cnc/fluidnc/screens/files_screen.cpp#187, CMakeLists.txt#62-79, cmake/sanity_check.cmake#71-77