Files
WLED_MM_Infinity/docs/rfp-node-flashing.md
jan 4bc4e1257e
Some checks failed
WLED CI / wled_build (push) Has been cancelled
Deploy Nightly / wled_build (push) Has been cancelled
Deploy Nightly / Deploy nightly (push) Has been cancelled
Backup RFP Infinity controller state before Resolume changes
2026-05-14 12:31:13 +02:00

475 lines
15 KiB
Markdown

# RFP Infinity Flashing
This document covers the two production firmware targets for the Infinity installation.
There is intentionally no separate `coldboot` firmware anymore: the reliable N16R8
boot settings are part of the normal master and node targets.
## Targets
- Master target: `rfp_esp32s3_wroom1_n16r8_master`
- Node target: `rfp_esp32s3_wroom1_n16r8_3x106`
## Firmware Release Names
These names are compiled into the firmware as `WLED_RELEASE_NAME` and show up in
WLED update metadata, OTA validation, serial boot logs, and `/json/info`.
- Master: `RFP_N16R8_MASTER_V20260511E`
- Node: `RFP_N16R8_NODE3x106_V20260511E`
Both targets use the same robust ESP32-S3-WROOM-1 N16R8 boot configuration:
- Flash: QIO / 16 MB
- Flash frequency: 80 MHz
- PSRAM: OPI / 8 MB octal
- Partition table: `tools/WLED_ESP32_16MB.csv`
- USB CDC on boot: disabled
- Boot delay: `WLED_BOOTUPDELAY=1200`
## Clean-Flash Warning
`erase_flash` removes the complete flash contents, including WLED's saved
`cfg.json`, Wi-Fi credentials, static IP settings, presets, and filesystem data.
The RFP master and node targets compile the show Wi-Fi as firmware defaults:
- SSID: `RFPLicht`
- Password: configured in the RFP build flags
After a full erase the board can therefore join Wi-Fi again, but runtime-only
settings that were stored through the WLED UI must be re-applied unless they are
also encoded as firmware defaults.
## Roles
- Master:
- Usually `192.168.178.10`
- Runs the `/infinity` web UI
- Accepts DMX and web commands
- Sends Infinity Sync packets to the nodes
- Keeps one dummy WLED pixel on `GPIO21` so the regular WLED UI remains valid
- Keeps the real WLED status pixel exclusively on `GPIO48`
- Nodes:
- Usually `192.168.178.11` to `192.168.178.16`
- Render the LED output locally
- Receive Infinity Sync from the master
- Use three LED outputs: `GPIO4/5/6`, each with `106` LEDs
## Build: Master
```bash
cd /home/jan/Documents/RFP/WLED-MM/repo
PATH=/home/jan/Documents/RFP/Finanz_App/node/current/bin:$PATH \
NPM_CONFIG_CACHE=$PWD/.npm-cache \
PLATFORMIO_CORE_DIR=$PWD/.piohome \
PLATFORMIO_PACKAGES_DIR=$PWD/.piohome/packages \
PLATFORMIO_PLATFORMS_DIR=$PWD/.piohome/platforms \
PLATFORMIO_CACHE_DIR=$PWD/.piohome/.cache \
PLATFORMIO_BUILD_CACHE_DIR=$PWD/.piohome/buildcache \
.venv/bin/python -m platformio run -e rfp_esp32s3_wroom1_n16r8_master
```
Master firmware output:
```text
.pio/build/rfp_esp32s3_wroom1_n16r8_master/firmware.bin
build_output/release/WLEDMM_14.7.2-mdev_RFP_N16R8_MASTER_V20260511E.bin
```
## Build: Nodes
```bash
cd /home/jan/Documents/RFP/WLED-MM/repo
PATH=/home/jan/Documents/RFP/Finanz_App/node/current/bin:$PATH \
NPM_CONFIG_CACHE=$PWD/.npm-cache \
PLATFORMIO_CORE_DIR=$PWD/.piohome \
PLATFORMIO_PACKAGES_DIR=$PWD/.piohome/packages \
PLATFORMIO_PLATFORMS_DIR=$PWD/.piohome/platforms \
PLATFORMIO_CACHE_DIR=$PWD/.piohome/.cache \
PLATFORMIO_BUILD_CACHE_DIR=$PWD/.piohome/buildcache \
.venv/bin/python -m platformio run -e rfp_esp32s3_wroom1_n16r8_3x106
```
Node firmware output:
```text
.pio/build/rfp_esp32s3_wroom1_n16r8_3x106/firmware.bin
build_output/release/WLEDMM_14.7.2-mdev_RFP_N16R8_NODE3x106_V20260511E.bin
```
## Recommended Update: Master USB First, Nodes Via Master
Use this for normal show updates. The laptop only needs USB access to the
master; it does not need to join the RFP Wi-Fi. The workflow is:
1. Build master and node firmware locally.
2. Flash the master app by USB.
3. Hard-reset the master and verify its RFP release over the serial relay.
4. Stream node OTA updates through the master to nodes `.11` to `.16`.
The master USB flash deliberately does **not** run `erase_flash` and does
**not** run `uploadfs`. This avoids rewriting the large LittleFS area during a
normal firmware update and keeps runtime config/filesystem data intact.
```bash
cd /home/jan/Documents/RFP/WLED-MM/repo
.venv/bin/python tools/rfp_update_master_usb_then_nodes.py --port /dev/ttyACM0
```
Use existing build artifacts without rebuilding:
```bash
cd /home/jan/Documents/RFP/WLED-MM/repo
.venv/bin/python tools/rfp_update_master_usb_then_nodes.py --port /dev/ttyACM0 --no-build
```
Resume node updates after a failure:
```bash
cd /home/jan/Documents/RFP/WLED-MM/repo
.venv/bin/python tools/rfp_update_master_usb_then_nodes.py --port /dev/ttyACM0 --no-build --nodes-only --start-from 192.168.178.14
```
Flash only the master with the same safe USB app-flash path:
```bash
cd /home/jan/Documents/RFP/WLED-MM/repo
./flash_master.sh
```
`flash_master.sh` is now intentionally an app/bootloader/partition update only:
no full erase and no filesystem upload. Use a full clean flash only when the
partition table or filesystem must be deliberately reset.
## USB App Flash: Master
Recommended helper:
```bash
cd /home/jan/Documents/RFP/WLED-MM/repo
./flash_master.sh
```
Manual flow:
```bash
cd /home/jan/Documents/RFP/WLED-MM/repo
ls /dev/ttyACM* /dev/ttyUSB* 2>/dev/null
PORT=/dev/ttyACM0
ENV=rfp_esp32s3_wroom1_n16r8_master
PATH=/home/jan/Documents/RFP/Finanz_App/node/current/bin:$PATH \
NPM_CONFIG_CACHE=$PWD/.npm-cache \
PLATFORMIO_CORE_DIR=$PWD/.piohome \
PLATFORMIO_PACKAGES_DIR=$PWD/.piohome/packages \
PLATFORMIO_PLATFORMS_DIR=$PWD/.piohome/platforms \
PLATFORMIO_CACHE_DIR=$PWD/.piohome/.cache \
PLATFORMIO_BUILD_CACHE_DIR=$PWD/.piohome/buildcache \
.venv/bin/python -m platformio run -e "$ENV"
.venv/bin/python .piohome/packages/tool-esptoolpy/esptool.py \
--chip esp32s3 \
--port "$PORT" \
--baud 460800 \
--before default_reset \
--after hard_reset \
write_flash -z \
--flash_mode qio \
--flash_freq 80m \
--flash_size 16MB \
0x0 .pio/build/rfp_esp32s3_wroom1_n16r8_master/bootloader.bin \
0x8000 .pio/build/rfp_esp32s3_wroom1_n16r8_master/partitions.bin \
0xe000 .piohome/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin \
0x10000 build_output/release/WLEDMM_14.7.2-mdev_RFP_N16R8_MASTER_V20260511E.bin
```
If upload does not start immediately:
1. Hold `BOOT`
2. Tap `RESET`
3. Release `BOOT`
4. Run the upload again
## USB Clean Flash: Node
Recommended helper:
```bash
cd /home/jan/Documents/RFP/WLED-MM/repo
./flash_node.sh
```
Manual flow:
```bash
cd /home/jan/Documents/RFP/WLED-MM/repo
ls /dev/ttyACM* /dev/ttyUSB* 2>/dev/null
PORT=/dev/ttyACM0
ENV=rfp_esp32s3_wroom1_n16r8_3x106
.venv/bin/python .piohome/packages/tool-esptoolpy/esptool.py \
--chip esp32s3 \
--port "$PORT" \
erase_flash
PATH=/home/jan/Documents/RFP/Finanz_App/node/current/bin:$PATH \
NPM_CONFIG_CACHE=$PWD/.npm-cache \
PLATFORMIO_CORE_DIR=$PWD/.piohome \
PLATFORMIO_PACKAGES_DIR=$PWD/.piohome/packages \
PLATFORMIO_PLATFORMS_DIR=$PWD/.piohome/platforms \
PLATFORMIO_CACHE_DIR=$PWD/.piohome/.cache \
PLATFORMIO_BUILD_CACHE_DIR=$PWD/.piohome/buildcache \
.venv/bin/python -m platformio run -e "$ENV" -t clean
PATH=/home/jan/Documents/RFP/Finanz_App/node/current/bin:$PATH \
NPM_CONFIG_CACHE=$PWD/.npm-cache \
PLATFORMIO_CORE_DIR=$PWD/.piohome \
PLATFORMIO_PACKAGES_DIR=$PWD/.piohome/packages \
PLATFORMIO_PLATFORMS_DIR=$PWD/.piohome/platforms \
PLATFORMIO_CACHE_DIR=$PWD/.piohome/.cache \
PLATFORMIO_BUILD_CACHE_DIR=$PWD/.piohome/buildcache \
.venv/bin/python -m platformio run -e "$ENV" -t upload --upload-port "$PORT"
```
## OTA Preflight
Check whether the current devices look OTA-updatable before flashing:
```bash
cd /home/jan/Documents/RFP/WLED-MM/repo
.venv/bin/python tools/rfp_update_all_ota.py --preflight-only --no-build
```
Single node:
```bash
cd /home/jan/Documents/RFP/WLED-MM/repo
.venv/bin/python tools/rfp_network_flash.py flash \
--targets 192.168.178.11 \
--firmware .pio/build/rfp_esp32s3_wroom1_n16r8_3x106/firmware.bin \
--expect-release RFP_N16R8_NODE3x106_V20260511E \
--preflight-only
```
## OTA Update: Whole Installation From RFP Wi-Fi
This builds locally and flashes nodes `.11` to `.16` first, then the master `.10`.
The master is flashed last so the show controller stays available while the nodes
update.
```bash
cd /home/jan/Documents/RFP/WLED-MM/repo
.venv/bin/python tools/rfp_update_all_ota.py
```
If your PC is not connected to the RFP Wi-Fi and the master is already on the
right release, keep the master connected by USB and let the master relay node
OTA updates through its own Wi-Fi connection:
```bash
cd /home/jan/Documents/RFP/WLED-MM/repo
.venv/bin/python tools/rfp_update_all_ota.py --via-master-usb --port /dev/ttyACM0 --no-build
```
This node-only relay is still useful for resumes and tests. For full updates,
prefer `tools/rfp_update_master_usb_then_nodes.py` so the master is flashed and
verified first. The relay streams the node firmware through the master and does
not store the full file on the master filesystem. The default relay baud rate is
`921600` for faster node updates; opening `/dev/ttyACM0` can reset the ESP32-S3,
so the tool waits briefly before sending commands. If a flaky USB cable or hub
causes serial errors, retry with `--relay-baud 115200`.
The updater prefers the named release binaries from `build_output/release/` when
they exist and verifies the expected RFP release name after reboot:
- Nodes: `RFP_N16R8_NODE3x106_V20260511E`
- Master: `RFP_N16R8_MASTER_V20260511E`
During the controlled migration from older generic WLED-MM builds, the updater
sends WLED's `skipValidation=1` upload parameter by default. The update is still
accepted only if the target reboots and then reports the expected RFP release
name in `/json/info`.
If you explicitly want WLED's release-name validation to block mismatches before
upload, use:
```bash
cd /home/jan/Documents/RFP/WLED-MM/repo
.venv/bin/python tools/rfp_update_all_ota.py --no-skip-validation
```
Use existing build artifacts without rebuilding:
```bash
cd /home/jan/Documents/RFP/WLED-MM/repo
.venv/bin/python tools/rfp_update_all_ota.py --no-build
```
Devices that already report the selected RFP release are skipped by default.
This avoids reflashing the same binary and then trying to prove an update from
an unchanged release string. To force reflashing the same release anyway:
```bash
cd /home/jan/Documents/RFP/WLED-MM/repo
.venv/bin/python tools/rfp_update_all_ota.py --no-build --force-current-release
```
Resume from a failed device:
```bash
cd /home/jan/Documents/RFP/WLED-MM/repo
.venv/bin/python tools/rfp_update_all_ota.py --no-build --start-from 192.168.178.14
```
## OTA Update: Single Device
Master:
```bash
cd /home/jan/Documents/RFP/WLED-MM/repo
.venv/bin/python tools/rfp_network_flash.py flash \
--targets 192.168.178.10 \
--firmware build_output/release/WLEDMM_14.7.2-mdev_RFP_N16R8_MASTER_V20260511E.bin \
--expect-release RFP_N16R8_MASTER_V20260511E \
--skip-validation
```
Node:
```bash
cd /home/jan/Documents/RFP/WLED-MM/repo
.venv/bin/python tools/rfp_network_flash.py flash \
--targets 192.168.178.11 \
--firmware build_output/release/WLEDMM_14.7.2-mdev_RFP_N16R8_NODE3x106_V20260511E.bin \
--expect-release RFP_N16R8_NODE3x106_V20260511E \
--skip-validation
```
## Why OTA Can Fail After Build Success
OTA updates only the application image. It does not reliably replace bootloader,
flash mode, or partition table. If a board still has an old partition layout, do
one USB clean flash with the production target first. After that, OTA should be
usable again.
The OTA helper is intentionally strict: upload is considered successful if the
device reboot is proven by an offline transition, an uptime reset, or a WLED
transport reset during upload plus the expected RFP release name in `/json/info`.
When flashing the exact same release again, the transport-reset proof is weaker,
so the whole-installation updater skips already matching devices by default.
## Global 2D Timing Check
The `/infinity` scene controls intentionally expose only one brightness control.
It sits next to `Master Speed`, starts at `100%`, and the old per-row dimmers
are forced to full output by the controller UI.
Global 2D animations derive their beat position from Infinity master time, not
from frame arrival time on each node. `Master Speed` is BPM, with one beat equal
to one visible 2D step. For example, `Checkerd` at `240 BPM` changes pattern
`240` times per minute.
Use `Strobe` in the `/infinity` Global 2D mode selector to check sync visually.
Its `Pulse Width` control is the normal `Size` control renamed for this mode.
The strobe is rendered from the shared beat phase, so all nodes should flash
in parallel at every BPM value from `20` to `240`.
## Master Crash Capture
If the master ever restarts unexpectedly, capture the next run with a serial log.
This keeps the production partition layout unchanged while still decoding ESP32
panic backtraces.
```bash
cd /home/jan/Documents/RFP/WLED-MM/repo
mkdir -p /tmp/rfp-master-crash
PATH=/home/jan/Documents/RFP/Finanz_App/node/current/bin:$PATH \
NPM_CONFIG_CACHE=$PWD/.npm-cache \
PLATFORMIO_CORE_DIR=$PWD/.piohome \
PLATFORMIO_PACKAGES_DIR=$PWD/.piohome/packages \
PLATFORMIO_PLATFORMS_DIR=$PWD/.piohome/platforms \
PLATFORMIO_CACHE_DIR=$PWD/.piohome/.cache \
PLATFORMIO_BUILD_CACHE_DIR=$PWD/.piohome/buildcache \
.venv/bin/python -m platformio device monitor \
-e rfp_esp32s3_wroom1_n16r8_master \
--port /dev/ttyACM0 \
-b 115200 \
--filter esp32_exception_decoder \
--filter log2file
```
After a crash, save:
- The monitor log from the current directory or PlatformIO log output
- The first `rst:` line after reboot
- Any `Guru Meditation`, `panic`, or decoded backtrace lines
- The current `/json/info` fields `ver`, `release`, `e32code`, and `e32text`
Do not switch to a coredump partition shortly before the event unless a repeated
crash proves that serial logs are not enough.
## WLED Backup Mode
The regular WLED UI is intentionally kept available as a fallback.
- `Show Mode: ON` means Infinity Sync is active.
- `WLED Backup: ON` means Infinity Sync is stopped and regular WLED control can be used.
Stop Infinity on the master by API:
```bash
curl -X POST http://192.168.178.10/json/infinity \
-H 'Content-Type: application/json' \
-d '{"enabled":false}'
```
Re-enable later:
```bash
curl -X POST http://192.168.178.10/json/infinity \
-H 'Content-Type: application/json' \
-d '{"enabled":true}'
```
## Coldboot Diagnosis
The firmware side is now consolidated into the normal production targets. If a
board still starts only after pressing `RESET`, capture the serial log directly
after real power-on.
```bash
cd /home/jan/Documents/RFP/WLED-MM/repo
PATH=/home/jan/Documents/RFP/Finanz_App/node/current/bin:$PATH \
NPM_CONFIG_CACHE=$PWD/.npm-cache \
PLATFORMIO_CORE_DIR=$PWD/.piohome \
PLATFORMIO_PACKAGES_DIR=$PWD/.piohome/packages \
PLATFORMIO_PLATFORMS_DIR=$PWD/.piohome/platforms \
PLATFORMIO_CACHE_DIR=$PWD/.piohome/.cache \
PLATFORMIO_BUILD_CACHE_DIR=$PWD/.piohome/buildcache \
.venv/bin/python -m platformio device monitor \
-e rfp_esp32s3_wroom1_n16r8_master \
--port /dev/ttyACM0 \
-b 115200
```
Expected directly after power-on:
```text
rst:0x1 (POWERON_RESET)
SPI_FAST_FLASH_BOOT
```
If there is no clean boot log until the reset button is pressed, inspect hardware:
- `EN` / `CHIP_PU` must not float.
- Use a proper pull-up and reset delay, e.g. `10 kOhm` pull-up plus `1 uF` from `EN` to GND.
- If the 3.3 V rail rises slowly or external loads drag it down, use a reset supervisor.
- Check strapping pins and external DMX/LED wiring for backfeeding during power-up.