v0.6.1-esp32

ruvnet/RuViewv0.6.1-esp32Apr 16, 2026by ruvnet

AI Summary

Critical firmware fix for node_id clobber issue in multi-node deployments where all ESP32 nodes transmitted node_id=1 despite correct NVS provisioning. Implements defense-in-depth capture of node_id at init time.

Key Highlights

  • Defense-in-depth fix for node_id clobber in multi-node deployments
  • Module-local static capture of node_id at initialization
  • Clobber canary warning system for divergence detection
  • Hardware validated on ESP32-S3 with correct node_id=2
  • 4MB variant (SuperMini) support maintained

New Features

  • node_id defensive capture into static s_node_id
  • csi_collector_get_node_id() accessor function
  • Clobber canary WARN logging on divergence
  • All consumers updated to use new accessor

Full Release Notes

## ESP32-S3 CSI Firmware v0.6.1

### Critical fix: `node_id` clobber on multi-node deployments

Closes #232, #375, #385, #386, #390.

Users on multi-node deployments reported that every ESP32 node transmitted `node_id=1` in UDP frames, despite NVS provisioning showing the correct value. This made multi-node setups indistinguishable downstream.

### What changed

**Defense-in-depth fix** — the firmware now captures `node_id` into a module-local static at init time, isolating the UDP frame header from any memory corruption of `g_nvs_config`:

1. `csi_collector_init()` captures `g_nvs_config.node_id` into `static uint8_t s_node_id` **once** at init
2. `csi_serialize_frame()` writes `buf[4] = s_node_id` — bypasses the global entirely
3. All other consumers (`edge_processing.c`, `wasm_runtime.c`, `display_ui.c`, `swarm_bridge_init`) use the new `csi_collector_get_node_id()` accessor
4. **Clobber canary** logs `WARN` if `g_nvs_config.node_id` diverges from the captured value at init — helps isolate the upstream corruption path

### Hardware validation (ESP32-S3 on COM8)

| Check | Result |
|-------|--------|
| NVS `node_id` | `2` (provisioned) |
| Boot log `main:` | `Node ID: 2` |
| Defensive capture log | `Captured node_id=2 at init` |
| `csi_collector` init log | `node_id=2, channel=5` |
| UDP packets (15/15) | `byte[4] = 2` |
| Clobber canary | Quiet (no WARN) |
| App version | `0.6.1` |
| Binary size | 865 KB (54% flash free) |

### Binaries

| File | Flash size | Description |
|------|-----------|-------------|
| `esp32-csi-node.bin` | 8MB | Main firmware |
| `bootloader.bin` | 8MB | Bootloader |
| `partition-table.bin` | 8MB | Partition table (dual OTA) |
| `ota_data_initial.bin` | 8MB | OTA data |
| `esp32-csi-node-4mb.bin` | 4MB | Main firmware (SuperMini) |
| `partition-table-4mb.bin` | 4MB | Partition table (SuperMini) |

### Flash command

```bash
python -m esptool --chip esp32s3 -p COM8 -b 460800 \
  --before default_reset --after hard_reset \
  write_flash --flash_mode dio --flash_size 8MB --flash_freq 80m \
  0x0 bootloader.bin \
  0x8000 partition-table.bin \
  0xf000 ota_data_initial.bin \
  0x20000 esp32-csi-node.bin
```

For 4MB SuperMini boards, use `esp32-csi-node-4mb.bin` and `partition-table-4mb.bin` with `--flash_size 4MB`.

### SHA-256 hashes

```
7f943b26...88197f7  bootloader.bin
9e650bf1...54bd43   esp32-csi-node.bin
15c263f6...02b32    esp32-csi-node-4mb.bin
7d2c7ac4...82c62f   ota_data_initial.bin
4c2cc4ff...d81f0    partition-table.bin
4c2cc4ff...d81f0    partition-table-4mb.bin
```

### Who should upgrade

All users running multi-node ESP32-S3 deployments. Single-node users are unaffected but the upgrade is safe.