Skip to content

ESP32-S3 HMI43V3 Build Scripts

The esp32s3_hmi43v3_build_scripts module provides the board-specific Python build orchestration for the ESP32-S3 HMI43V3 panel — a 4.3-inch, 800×480 display board using the RM68120 controller over an Intel 8080 (i80) parallel interface. These scripts define every supported firmware variant, drive the ESP-IDF toolchain, regenerate the UI resources partition, assemble the factory artifacts, and produce a ready-to-flash installer directory — all from a single command.


The module lives at boards/esp32s3_hmi43v3/build_scripts/ and consists of exactly three files. This structure is the same pattern used by every board in the project (see esp32s3_bzm_tft35_gt911_build_scripts.md, pibot_pendant_v1_0_build_scripts.md, etc.).

FileRole
build_one.pyCLI entry point — parses arguments, resolves the variant, delegates to common.py
common.pyBuild orchestration engine — all pipeline logic, path helpers, IDF invocation
variants.pyVariant registry — CMake flag matrices for every supported firmware configuration
PropertyValue
MCUESP32-S3
Flash8 MB
Display4.3″ 800×480 RM68120 via Intel 8080 (i80)
TouchCapacitive (I²C)
IDF_TARGETesp32s3
Resolution tokenres_800_480
Partition CSVpartitions_8mb.csv

The BSP layer that initialises this hardware at runtime is documented in esp32s3_hmi43v3_bsp.md. The factory recovery application is documented in esp32s3_hmi43v3_factory_app.md.


Build Outputs

External Tools

boards/esp32s3_hmi43v3/build_scripts/

Developer / CI

build_one.py <variant>

build_mgr.py

build_one.py

(CLI entry point)

common.py

(pipeline engine)

variants.py

(variant registry)

tools/build_scripts/generate_resources.py

tools/build_scripts/package_user_resources_kit.py

tools/flash_scripts/flash_mgr.py

ESP-IDF idf.py

build/esp32s3_hmi43v3_<variant>/

(CMake / ELF / .bin)

installer/ESP32S3_HMI43V3_<variant>/

(flashable artifacts)

Factory/installer/ESP3D-FACTORY_8MB/

(bootloader + partitions)


Provides a direct, single-variant build command. It is the human-facing interface; automated multi-variant builds use build_mgr.py (see tools_build_scripts.md).

Function: main()

Usage: python build_one.py <variant_name> [--clean] [--check]
FlagEffect
(none)Full build: resources + firmware + postbuild steps
--cleanWipe the build and installer directories, then exit
--checkCMake configure-only (idf.py reconfigure) — no compilation

Resolution logic:

No

Yes

No

Yes

Yes

No

build_one.py invoked

Parse sys.argv

all_variants = FACTORY_VARIANTS ∪ VARIANTS

Name argument

provided?

Print usage + variant list

exit 1

Name in

all_variants?

Print error

exit 1

--check

in args?

check_variant(config)

build_variant(config)

exit with return code


Defines all supported firmware configurations as Python dictionaries. Each entry is a variant config consumed by build_variant().

The central helper for constructing clean, reproducible CMake argument lists. It works by the all-OFF-then-ON principle:

  1. ROOT_CMAKE_OPTIONS enumerates every known CMake option for the entire project (boards, memory sizes, transports, firmware targets, services).
  2. DEFAULT_OFF_CMAKE_ARGS expands each into -D <OPTION>=OFF, resetting all options to a known baseline.
  3. make_variant_args(*on_flags) copies DEFAULT_OFF_CMAKE_ARGS and appends each requested flag as -D <FLAG> (which must carry its own =ON suffix).
# Example internal expansion for 8mb_wifi_fluidnc:
make_variant_args(
"ESP32S3_HMI43V3=ON",
"MEMORY_8_MB=ON",
"TARGET_FW_FLUIDNC=ON",
"SERIAL_SERVICE=ON",
"WIFI_SERVICE=ON",
"TFT_UI_SERVICE=ON",
"TFT_TOUCH_SERVICE=ON",
"MDNS_SERVICE=ON",
"SOCKET_CLIENT_SERVICE=ON",
"UPDATE_SERVICE=ON",
"LUA_INTERPRETER_SERVICE=ON",
)
# Result: [..., -D ESP32S3_HMI43V3=OFF, ..., -D ESP32S3_HMI43V3=ON, ...]
# All 60+ options forced OFF first, then only the 11 above set ON.

This guarantees that no stale CMakeCache value from a previous build can bleed into a new configuration.

Every entry in VARIANTS and FACTORY_VARIANTS is a dict with four keys:

KeyTypeDescription
namestrHuman-readable identifier, also used as build-dir suffix
cmakelist[str]Full cmake argument list produced by make_variant_args()
cwdstrWorking directory for idf.py — REPO_ROOT for regular variants, FACTORY_DIR for factory
build_dirstrAbsolute path to the dedicated CMake build directory
Variant NameMemoryTransportCNC FirmwareExtra Services
8mb_wifi_fluidnc8 MBSerial + WiFiFluidNCmDNS, Socket Client, Lua
8mb_serial_fluidnc8 MBSerialFluidNC—
8mb_serial_grbl8 MBSerialGRBL—
8mb_wifi_grblhal8 MBSerial + WiFigrblHALmDNS, Socket Client

All firmware variants share: ESP32S3_HMI43V3=ON, TFT_UI_SERVICE=ON, TFT_TOUCH_SERVICE=ON, UPDATE_SERVICE=ON.

Variant NamePurposecwd
factory_8mbRecovery/test app flashed to factory partitionboards/esp32s3_hmi43v3/Factory/

The factory build produces bootloader_8MB.bin and partition table binaries that are mandatory prerequisites for all regular firmware variants (see esp32s3_hmi43v3_factory_app.md).

{memory_mb}mb_{transport}_{firmware}
Examples:
8mb_wifi_fluidnc
8mb_serial_grbl
8mb_wifi_grblhal

The same convention drives build_config_name() in common.py to derive the installer output directory name (ESP32S3_HMI43V3_8MB_wifi_fluidnc, etc.) and resource_variant_string() to select the correct UI partition configuration.


Contains all pipeline logic. It is imported by both build_one.py and the project-wide build_mgr.py.

ConstantValuePurpose
SCRIPT_DIRboards/esp32s3_hmi43v3/build_scripts/Location of these scripts
BOARD_ROOTboards/esp32s3_hmi43v3/Root of this board’s tree
REPO_ROOTRepository rootcwd for regular firmware variants
IDF_PATH$IDF_PATH env or Windows defaultESP-IDF installation
IDF_PY$IDF_PATH/tools/idf.pyESP-IDF build entry point
GENERATE_RESOURCEStools/build_scripts/generate_resources.pyUI partition generator
PACKAGE_USER_KITtools/build_scripts/package_user_resources_kit.pyKit packager
RESOLUTION"res_800_480"Board display resolution token
EXPECTED_IDF_TARGET"esp32s3"Enforced IDF target for this board

build_variant(config) — Full Build Pipeline

Section titled “build_variant(config) — Full Build Pipeline”

The primary public function. Executes the complete sequence to produce a flashable installer directory:

Yes

Yes

No

No

No

Yes

No

Yes

No

Yes

No

Yes

build_variant called

--clean

in argv?

clean_build_dir

build_dir

cwd !=

REPO_ROOT?

Also clean parent

build dir if CMakeCache present

clean installer_dir

return 0

prepare_build_dir(build_dir)

→ create dir + write .idf_target marker

generate_resources(cmake_args, build_dir)

→ ui_resources_*.bin + esp3d_ui_offsets.h

result == 0?

FAILED: resources

return rc

run_cmake_build(cmake_args, cwd, build_dir)

→ idf.py -B build_dir <cmake_args> build

result == 0?

FAILED: cmake

return rc

_show_size_report()

→ idf.py size

cwd ==

REPO_ROOT?

OK: factory variant

copy_factory_artifacts(cmake_args)

→ bootloader + partitions

result == 0?

FAILED: factory artifacts

return 1

_copy_ui_resources_bin()

→ ui_resources_*.bin → installer_dir

_package_user_resources_kit()

→ installer_dir/ui_resources_kit/

_log_firmware_artifacts()

→ installer_history.log

generate_flash_map()

→ flash_map.json

OK: regular variant

check_variant(config) — Configuration Validation

Section titled “check_variant(config) — Configuration Validation”

Runs idf.py reconfigure (CMake configure step only, no compilation). Used for rapid CMake flag validation without a full compile.

idf.py reconfigurecheck_variant()build_one.py --checkidf.py reconfigurecheck_variant()build_one.py --checkconfig dictprepare_build_dir()subprocess(idf.py -B build_dir cmake_args reconfigure)exit codeexit code (0 = OK)
FunctionReturnsPurpose
parse_cmake_flags(cmake_args)dictExtracts -D KEY=VALUE pairs from a cmake args list
build_config_name(cmake_args)strDerives ESP32S3_HMI43V3_8MB_wifi_fluidnc-style installer dir name
resource_variant_string(cmake_args)str or NoneDerives 8mb_wifi_fluidnc-style string for generate_resources.py --variant
installer_dir_for(config)str or NoneReturns the absolute installer output dir for a config
prepare_build_dir(build_dir)—Creates the build dir and writes .idf_target; clears it if target changed
_ensure_clean_build_dir(build_dir)—Clears build_dir if .idf_target mismatches EXPECTED_IDF_TARGET
clean_build_dir(build_dir)—shutil.rmtree wrapper with logging
ensure_idf_py()—Verifies IDF_PY exists; exits 1 with instructions if not
run_cmake_build(cmake_args, cwd, build_dir)intInvokes idf.py -B build_dir … build with correct env
run_cmake_check(cmake_args, cwd, build_dir)intInvokes idf.py -B build_dir … reconfigure
generate_resources(cmake_args, build_dir)intCalls generate_resources.py to produce the UI partition binary
copy_factory_artifacts(cmake_args)intCopies bootloader/partition binaries from factory installer dir; auto-builds factory if missing
_factory_artifacts_complete(source_dir)boolReturns True only when a bootloader_*.bin is present in the factory installer dir
_build_missing_factory(source_dir)intFinds and rebuilds the factory variant matching the given installer dir
_copy_ui_resources_bin(build_dir, installer_dir)—Copies ui_resources_*.bin from build_dir to installer_dir
_package_user_resources_kit(cmake_args, build_dir, installer_dir)intRuns package_user_resources_kit.py to assemble the standalone customization kit
_log_firmware_artifacts(variant_name, build_dir, installer_dir, cmake_args)—Appends a timestamped FIRMWARE section to installer_history.log
_show_size_report(build_dir, cwd)—Runs idf.py size after a successful build
generate_flash_map(config)—Calls flash_mgr.py --generate to produce flash_map.json
_get_jobs_env_value()str or NoneReads --jobs=N from argv for CMAKE_BUILD_PARALLEL_LEVEL

installer/ESP32S3_HMI43V3_8MB_<transport>_<fw>/

build/esp32s3_hmi43v3_<variant>/

common.py pipeline

Inputs

variants.py

(cmake flags)

Environment

IDF_PATH, --jobs=N

partitions_8mb.csv

boards/esp32s3_hmi43v3/

resources/ (optional)

generate_resources.py

--variant --resolution

--partition-csv

idf.py build

(CMake + ninja)

copy_factory_artifacts

bootloader_8MB.bin

partitions_8MB.bin

package_user_resources_kit.py

flash_mgr.py --generate

ui_resources_8mb_*.bin

esp3d_ui_offsets.h

.elf

firmware.bin

ui_resources_manifest_*.json

bootloader_8MB.bin

partitions_8MB.bin

firmware_8MB.bin

ui_resources_8mb_*.bin

ui_resources_kit/

flash_map.json

installer_history.log


  • The installer directory name comes from CMake (cmake/build_config_name.cmake, which appends the log level _LOG_<LEVEL>): installer_config_name(cmake_args, build_dir) reads <build_dir>/build_config_name.txt and falls back to build_config_name() before any configure; copy_factory_artifacts(cmake_args, build_dir) uses it too.
  • build_config_name() (no log suffix) is passed to generate_resources.py as --build-name, so a resources binary fits the variant with or without logs (build trailer, see tools_build_scripts_ui_resources.md).
  • New 8mb_serial_marlin variant (Marlin groundwork, TARGET_FW_MARLIN=ON).
  • components/bsp/lv_conf.h is regenerated for LVGL 9.6 (see Board_Support_Packages.md).

common.py

variants.py

build_one.py

main()

make_variant_args()

VARIANTS dict

FACTORY_VARIANTS dict

build_variant()

check_variant()

generate_resources()

run_cmake_build()

run_cmake_check()

prepare_build_dir()

copy_factory_artifacts()

_build_missing_factory()

_factory_artifacts_complete()

_copy_ui_resources_bin()

_package_user_resources_kit()

generate_flash_map()

_log_firmware_artifacts()

build_config_name()

resource_variant_string()

parse_cmake_flags()


Regular firmware variants require bootloader and partition binaries produced by the factory variant. common.py enforces this dependency automatically:

Factory/installer/ESP3D-FACTORY_8MB/build_variant(factory_8mb)_build_missing_factory()_factory_artifacts_complete()copy_factory_artifacts()build_variant(regular)Factory/installer/ESP3D-FACTORY_8MB/build_variant(factory_8mb)_build_missing_factory()_factory_artifacts_complete()copy_factory_artifacts()build_variant(regular)cmake_args (MEMORY_8_MB=ON)check source_dirFalse (missing or empty)source_dirbuild factory variantwrites bootloader_8MB.bin + partitions_8MB.bin0 (success)re-check source_dirTruecopy files to installer_dir0 (success)

_factory_artifacts_complete() validates the presence of a bootloader_*.bin file (not just directory existence) because CMake creates the target directory during configure but populates it only after a successful factory build.


To prevent corrupted builds when switching between different IDF_TARGET values, prepare_build_dir() writes an .idf_target marker file and validates it on every invocation:

No

Yes

No

Yes

No

Yes

prepare_build_dir(build_dir)

build_dir

exists?

mkdir + write .idf_target = 'esp32s3'

.idf_target

file present?

cached = None

read cached target string

cached ==

'esp32s3'?

shutil.rmtree(build_dir)

then mkdir + write marker

build_dir OK as-is


After a complete regular variant build, the following directory structure is produced:

build/
└── esp32s3_hmi43v3_8mb_wifi_fluidnc/ # CMake build artifacts
├── .idf_target # Target marker ('esp32s3')
├── esp3d_ui_offsets.h # Generated UI offset header
├── ui_resources_8mb_wifi_fluidnc.bin # UI resources partition binary
├── ui_resources_manifest_8mb_wifi_fluidnc.json
├── firmware.elf
└── ...
installer/
└── ESP32S3_HMI43V3_8MB_wifi_fluidnc/ # Flashable artifacts
├── bootloader_8MB.bin # From factory build
├── partitions_8MB.bin # From factory build
├── firmware_8MB.bin # Main application binary
├── ui_resources_8mb_wifi_fluidnc.bin # UI partition binary
├── flash_map.json # Flash addresses + offsets
├── installer_history.log # Timestamped build provenance
└── ui_resources_kit/ # Standalone customization kit
├── build_ui_resources_from_manifest.py
├── ui_resources_manifest_*.json
└── ...
boards/esp32s3_hmi43v3/Factory/installer/
└── ESP3D-FACTORY_8MB/ # Factory variant outputs
├── bootloader_8MB.bin
└── partitions_8MB.bin

ROOT_CMAKE_OPTIONS in variants.py enumerates every project-level option. The categories relevant to this board are:

CategoryOptions Used for This Board
Board selectionESP32S3_HMI43V3
Flash memoryMEMORY_8_MB
PSRAM(not used in current variants)
CNC firmware targetTARGET_FW_FLUIDNC, TARGET_FW_GRBLHAL, TARGET_FW_GRBL
CommunicationSERIAL_SERVICE, WIFI_SERVICE, SOCKET_CLIENT_SERVICE
Display / TouchTFT_UI_SERVICE, TFT_TOUCH_SERVICE
DiscoveryMDNS_SERVICE
ScriptingLUA_INTERPRETER_SERVICE
OTAUPDATE_SERVICE

All other options in ROOT_CMAKE_OPTIONS are forced to OFF by make_variant_args() to prevent any residual CMakeCache state from affecting the output.

For the full list of options and their interactions (sanity checks, mutual exclusions), see board_build_guidelines.md.


idf.py has no native -j / --jobs option. Parallelism is conveyed through the CMAKE_BUILD_PARALLEL_LEVEL environment variable, which the underlying cmake --build step honours regardless of generator (Ninja or Make):

# _get_jobs_env_value() reads --jobs=N injected by build_mgr.py,
# then sets env["CMAKE_BUILD_PARALLEL_LEVEL"] = N before subprocess.run().

build_mgr.py (see tools_build_scripts.md) injects --jobs=N when invoking per-board build scripts in parallel.


Before any firmware compilation, generate_resources() calls generate_resources.py with the exact variant flags, ensuring that:

  1. The ui_resources partition binary matches the flash layout defined by partitions_8mb.csv.
  2. The generated esp3d_ui_offsets.h header is present in the build directory before the C++ compiler reads it.
  3. Board-specific UI overrides (icons, fonts, theme colours) in boards/esp32s3_hmi43v3/resources/ are applied when the directory exists.

The resource_variant_string() function bridges the CMake flag domain into the naming convention consumed by generate_resources.py:

cmake flags → resource variant string
MEMORY_8_MB=ON → "8" → "8mb"
WIFI_SERVICE=ON → "wifi"
TARGET_FW_FLUIDNC=ON → "fluidnc"
────────────────────────────── ──────────────────────────
combined → "8mb_wifi_fluidnc"

For full details on the UI resources system, partition binary format, and the ui_resources_kit/, see development.md.


Full Regular Variant Build: Sequence Diagram

Section titled “Full Regular Variant Build: Sequence Diagram”
flash_mgr.pypackage_user_resources_kit.pyfactory build (if needed)idf.py (ESP-IDF)generate_resources.pycommon.pyvariants.pybuild_one.pyUserflash_mgr.pypackage_user_resources_kit.pyfactory build (if needed)idf.py (ESP-IDF)generate_resources.pycommon.pyvariants.pybuild_one.pyUserChecks Factory/installer/ESP3D-FACTORY_8MB/bootloader_8MB.binalt[artifacts missing or incomplete]python build_one.py 8mb_wifi_fluidnclook up variant configconfig dict (cmake args, build_dir, cwd=REPO_ROOT)build_variant(config)prepare_build_dir() - mkdir + write .idf_targetgenerate_resources --variant 8mb_wifi_fluidnc --resolution res_800_480ui_resources_8mb_wifi_fluidnc.bin + esp3d_ui_offsets.hidf.py -B build_dir -D ESP32S3_HMI43V3=ON ... buildfirmware ELF + BIN_show_size_report() - idf.py sizecopy_factory_artifacts()build_variant(factory_8mb)bootloader_8MB.bin + partitions_8MB.bincopy bootloader + partitions → installer_dir_copy_ui_resources_bin() - copy .bin to installer_dirpackage_user_resources_kit --variant 8mb_wifi_fluidncinstaller_dir/ui_resources_kit/_log_firmware_artifacts() - append to installer_history.logflash_mgr.py --generate --variant-dir installer_dirflash_map.jsonreturn 0exit 0 (OK)
Terminal window
# Activate ESP-IDF environment first
. $IDF_PATH/export.sh # Linux / macOS
# or: %IDF_PATH%\export.bat (Windows)
cd boards/esp32s3_hmi43v3/build_scripts/
# List all available variants
python build_one.py
# Build specific firmware variants
python build_one.py 8mb_wifi_fluidnc
python build_one.py 8mb_serial_fluidnc
python build_one.py 8mb_serial_grbl
python build_one.py 8mb_wifi_grblhal
# Build the factory recovery app
python build_one.py factory_8mb
# Validate CMake configuration without compiling
python build_one.py 8mb_wifi_fluidnc --check
# Full clean then rebuild
python build_one.py 8mb_wifi_fluidnc --clean
python build_one.py 8mb_wifi_fluidnc
# Development build (skips -DPROD_BUILD=ON)
python build_one.py 8mb_wifi_fluidnc --dev
# Build all variants via build manager (parallel)
python tools/build_scripts/build_mgr.py --board esp32s3_hmi43v3 --jobs=4

ModuleRelationship
esp32s3_hmi43v3_bsp.mdRuntime BSP: board_init(), LVGL setup, i80 flush callback — built by the firmware variants defined here
esp32s3_hmi43v3_factory_app.mdFactory recovery app built by factory_8mb; provides bootloader and partition binaries required by all regular variants
tools_build_scripts.mdShared build tools: build_mgr.py (multi-board orchestrator), generate_resources.py (UI partition generator), package_user_resources_kit.py (kit assembler), flash_mgr.py (flash map generator)
development.mdUI resources partition: binary format, esp3d_ui_offsets.h API, resource variant naming, board-specific overrides
board_build_guidelines.mdBoard-level build conventions, CMake option interactions, and sanity checks shared across all BSPs
esp32s3_bzm_tft35_gt911_build_scripts.mdSibling board build scripts — same three-file pattern, different display (SPI ST7796 + GT911 touch)
pibot_pendant_v1_0_build_scripts.mdSibling board build scripts — same three-file pattern, pendant hardware with ILI9341
esp32s3_8048s070c_build_scripts.mdSibling board build scripts — RGB panel (ST7262), larger 7″ display