ESP32-S3 environment-control research and product-development repository combining a portable C++ controller, TinyML inference, deterministic safety, simulation/calibration tooling, a scientific 3D twin, and browser-based hardware configuration.
Integration status:
integration/convergence-2026-08is a non-destructive convergence workspace. The original product lines and dated archive snapshots remain available until this branch is fully validated. See docs/INTEGRATION_CONVERGENCE.md.
- Interactive 3D chamber configurator: https://michalmatu.github.io/growbox-ml-controller/chamber-3d
- Hardware / JSON configurator: https://michalmatu.github.io/growbox-ml-controller/
The currently deployed Pages build still comes from the preserved configurator line. It will not be replaced from this integration branch until firmware, simulator/twin, frontend and deployment checks all pass.
The native ESP-IDF application runs a generated C inference model and places a deterministic SafetySupervisor between the model proposal and the final control decision. The demonstration firmware uses a local simulator and bounded UART/NDJSON protocol; it does not drive real GPIO loads in the demo configuration.
The portable lib/environment_control layer is intentionally independent of ESP-IDF, Arduino, serial I/O, JSON, GPIO, Wi-Fi, FreeRTOS, sensor drivers and the simulator.
Firmware/controller contract: schemas/environment-controller.json is currently schema v4: 4 pot slots, 128 model features and 15 outputs. This remains the active firmware/wire contract during repository convergence.
Python tooling generates deterministic synthetic scenarios, trains the model, exports it through the emlearn-compatible C runtime, checks generated artifacts and validates parity against golden vectors.
The simulator line also contains calibration, deviations/foresight work and physically inspired chamber/pot models. These tools are research/engineering aids, not a calibrated real-world safety model.
tools/ml/twin/ provides a PyVista visual layer over the simulator, with GrowboxProfile, chamber/pot geometry, hardware profiles, camera/HUD tooling, live interaction and tests. The scientific twin intentionally visualizes a lumped model rather than pretending to be CFD.
See docs/simulator/TWIN_VIEW.md and docs/simulator/CALIBRATION.md.
web/ is a React + TypeScript + Vite application. It contains:
- schema-driven hardware/JSON configuration at
/ - interactive React Three Fiber chamber configuration at
/chamber-3d - Three.js / React Three Fiber geometry for enclosure, lighting, pots and fans
- tests, type checking, linting and a production build gate
The browser configurator has evolved beyond the current firmware contract and therefore carries its own explicit bundled schema at web/schema/environment-controller.v5.json.
Web configurator contract: schema v5: up to 9 pot slots, 228 model features and 25 outputs.
The v4 firmware and v5 browser contract are deliberately kept separate during convergence. This is an architectural migration boundary, not something to silently reconcile as repository cleanup.
flowchart TB
subgraph Host["Development / simulation host"]
V4["Firmware contract v4\n128 features / 15 outputs"] --> Sim["Simulation / teacher / calibration"]
Sim --> Train["Keras training"]
Train --> Export["emlearn-compatible C model"]
Twin["PyVista scientific twin\nGrowboxProfile"] --> Sim
end
subgraph Board["ESP32-S3 / ESP-IDF"]
Input["Sensors / validity / targets / capabilities"] --> Encoder["FeatureEncoder"]
Encoder --> Runtime["ModelRuntime"]
Runtime --> Proposal["Raw ML proposal"]
Proposal --> Safety["Deterministic SafetySupervisor"]
Input --> Safety
Safety --> Decision["Safe control decision"]
Decision --> Demo["Demo simulator / NDJSON"]
end
Export --> Runtime
subgraph Browser["Browser tooling"]
V5["Configurator contract v5\n228 features / 25 outputs"] --> Config["Hardware / JSON configurator"]
Config --> Chamber["React Three Fiber chamber 3D"]
end
- ESP-IDF 5.5.1 baseline in CI
- ESP32-S3, C++17
- CMake / CTest portable host tests
- emlearn-compatible generated C inference
- deterministic safety supervisor
- ESP-IDF UART, timers, FreeRTOS, heap diagnostics and JSON component
- clang-tidy / clang-format / pre-commit quality gates
Default CI firmware profile: ESP32-S3-DevKitC-1 N8 (8 MB quad flash, no PSRAM). An explicit N32R16V profile is also retained for compatible hardware.
- React 19
- TypeScript
- Vite
- Three.js
- React Three Fiber / drei
- Tailwind CSS / shadcn UI
- Vitest / ESLint / typecheck
components/emlearn_runtime/ pinned inference runtime
config/idf/ ESP-IDF board profiles
docs/ architecture, contracts, simulator and integration docs
examples/ scenarios / examples
lib/environment_control/ portable C++ controller
profiles/ saved GrowboxProfile examples
schemas/ active firmware/controller contract (v4)
scripts/ CI, IDF and helper scripts
src/ ESP-IDF demo application
test/host/ portable C++ CMake/CTest suite
tests/ Python simulator / ML / profile / twin tests
tools/ml/ simulation, training, calibration, analysis and twin
tools/panel/ local board control/diagnostic panel
tools/serial/ capture and replay
web/ browser configurator + React Three Fiber chamber 3D
web/schema/ explicit browser-side v5 contract snapshot
More detail: docs/PROJECT_LAYOUT.md.
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -r requirements-lock.txt
python -m tools.ml.pipeline --quick
cmake -S test/host -B build/host-tests
cmake --build build/host-tests --parallel
ctest --test-dir build/host-tests --output-on-failure
idf.py -B build/idf -D GROWBOX_BOARD_PROFILE=esp32s3-devkitc1-n8 buildPyVista is optional so the default firmware/ML environment does not require the GUI stack.
pip install -e '.[twin]'
python -m tools.ml.twin_view --liveA saved profile can be loaded with:
python -m tools.ml.twin_view --live --profile profiles/example-single-pot.jsonRequires Node.js 22 and pnpm 11.10.0.
corepack enable
corepack prepare pnpm@11.10.0 --activate
pnpm --dir web install --frozen-lockfile
pnpm --dir web devProduction gate:
pnpm --dir web typecheck
pnpm --dir web lint
pnpm --dir web test
pnpm --dir web buildThe convergence branch validates the product layers independently:
- Python / host C++ / generated-artifact / clang-tidy checks.
- ESP-IDF 5.5.1 ESP32-S3 firmware build and clang-check.
- Browser typecheck, lint, tests and production build.
The separate gates are intentional: a frontend experiment must not silently redefine the firmware contract, and firmware changes must not silently break the browser tooling.
The ESP-IDF demo accepts one JSON command per line, including status, reset, seed, pause, resume, step, target, load_scenario and mode (closed_loop or replay). The UART adapter uses a bounded line buffer and returns structured errors for malformed or unsupported input.
Example replay:
python -m tools.serial.replay \
--port /dev/cu.usbserial-10 \
--scenario examples/scenarios/nominal.jsonl \
--output logs/nominal-session.ndjson- Synthetic training does not establish real-world control performance or hardware safety.
- The simulator is still being calibrated and should not be treated as a validated physical model.
- The scientific 3D twin is a visualization of a lumped model, not CFD.
- The demo firmware does not connect calibrated physical sensors/actuators or drive production loads.
- The v4 firmware contract and v5 browser configurator contract are not yet a single production contract.
A future integration with the private GrowClip / LiteGraph firmware is intended to replace the demo provider with a device adapter while preserving the portable encoder/runtime/safety boundary. See docs/PORTING_TO_LITEGRAPH.md.
No source branch is considered disposable merely because its code has been copied into this branch. Before deleting any historical/product branch, the convergence checklist requires successful firmware, host, Python, frontend and Pages validation plus confirmation that no unique docs, profiles, calibration data, tests or experiments remain only on the old branch.
The exact snapshot branches and deletion criteria are documented in docs/INTEGRATION_CONVERGENCE.md.
Released under the MIT License. The in-tree emlearn runtime subset retains its upstream MIT notice in components/emlearn_runtime/LICENSE.