This document describes the UI development workflow using EEZ Studio and the LVGL simulator.
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ EEZ Studio │────▶│ Sync Script │────▶│ Simulator │
│ (UI design) │ │ │ │ (quick test) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │
│ ┌───────────────────────┘
│ │
▼ ▼
┌─────────────────────────────────────────┐
│ Firmware Flash │
│ (final device test) │
└─────────────────────────────────────────┘
# 1. Make changes in EEZ Studio, then Build/Export
# 2. Sync EEZ output to firmware and simulator
cd firmware
./update_eez_screens.sh
# 3. Build and test in simulator
cd ../lvgl-simulator-sdl/build
cmake --build . -j
./simulator
# 4. When ready, build and flash firmware
cd ../../firmware
cargo build --release| Location | Content |
|---|---|
eez/ |
EEZ Studio project |
eez/src/ui/ |
EEZ Studio output (source of truth for UI layout) |
firmware/components/eez_ui/ |
Symlinks to EEZ + custom code |
lvgl-simulator-sdl/ui/ |
Symlinks to both EEZ and firmware custom code |
These files are generated by EEZ Studio and should not be manually edited:
screens.c/screens.h- Screen layouts and widget creationimages.c/images.h- Image referencesui_image_*.c- Image datastyles.c/styles.h- Style definitionsstructs.h- Data structuresfonts.h- Font referencesvars.h- Variablesactions.h- Action declarations
These files contain our custom logic and are never overwritten by EEZ:
| File | Purpose |
|---|---|
ui.c |
Screen navigation, button wiring, tick loop |
ui_backend.c |
Backend communication, AMS display, printer status |
ui_printer.c |
Printer add/edit/delete, discovery |
ui_wifi.c |
WiFi settings and connection |
ui_settings.c |
Settings screen tabs and navigation |
ui_nvs.c |
NVS persistence (ESP32) / mock (simulator) |
ui_scale.c |
Scale calibration and tare |
ui_update.c |
Firmware update UI |
ui_internal.h |
Shared types, macros, and declarations |
The firmware/update_eez_screens.sh script:
- Applies LVGL 9.x compatibility fixes to EEZ output
- Fixes EEZ-generated code bugs (empty parameters, undefined enums)
- Creates symlinks from firmware to EEZ output
- Creates symlinks from simulator to EEZ output
- Preserves all custom code files
The LVGL simulator (lvgl-simulator-sdl/) allows testing UI changes without flashing:
- Uses SDL2 for display rendering
- Connects to the backend server at
http://localhost:3000 - Mock implementations for WiFi, OTA, scale (no real hardware)
- Same UI code as firmware via
#ifdef ESP_PLATFORMguards
cd lvgl-simulator-sdl
mkdir -p build && cd build
cmake ..
cmake --build . -jcd lvgl-simulator-sdl/build
./simulatorPress ESC or close the window to exit.
When adding new custom UI functionality:
- Create the file in
firmware/components/eez_ui/(e.g.,ui_newfeature.c) - Add
#ifdef ESP_PLATFORMguards for platform-specific code - Add the file to
CUSTOM_FILESarray inupdate_eez_screens.sh - Run
./update_eez_screens.shto create simulator symlink - Add mock implementations to
lvgl-simulator-sdl/sim_mocks.cif needed
Use this pattern for code that differs between firmware and simulator:
#ifdef ESP_PLATFORM
// ESP32 firmware: real implementation
#include "esp_log.h"
#define MY_LOG(fmt, ...) ESP_LOGI("tag", fmt, ##__VA_ARGS__)
extern void real_hardware_function(void);
#else
// Simulator: mock/stub implementation
#define MY_LOG(fmt, ...) printf("[tag] " fmt "\n", ##__VA_ARGS__)
static void real_hardware_function(void) { /* mock */ }
#endifcd lvgl-simulator-sdl/build
rm -rf CMakeCache.txt CMakeFiles
cmake ..
cmake --build . -jcd firmware
./update_eez_screens.shThe sync script automatically fixes common issues:
lv_img_dsc_t→lv_image_dsc_t(LVGL 9.x)- Empty
lv_image_set_pivot()/lv_image_set_rotation()calls LV_LABEL_LONG_undefined→LV_LABEL_LONG_WRAP- Duplicate
settingsidentifier →settings_main