Skip to content

OTA Flashing

OneSeventyFour edited this page May 14, 2026 · 1 revision

OTA flashing receivers

Once a receiver is online and reachable from the dongle, you can update its firmware over the air instead of plugging in a USB cable. This is the right tool when:

  • Receivers are mounted in their enclosures and inconvenient to open.
  • You're at a show site without a laptop and serial cable.
  • You're updating an entire fleet at once and don't want to handle each unit.

The OTA path uses the same os4_receiver_v<N>.bin artifact that USB flashing uses (the app partition only, written at offset 0x10000). NVS — and therefore the receiver's NODE_ID and ident — is preserved.

What it can't do

  • Brand-new chips. OTA needs working firmware on the receiver to negotiate the transfer. A virgin chip needs an initial USB flash; afterwards it can be OTA'd indefinitely.
  • Bricked receivers. If a receiver is in a bootloop, the radio never comes up, and OTA can't reach it. Recover via USB (flash_receiver.py --full).
  • Bilusocn 433 MHz receivers. They're TX-only one-way devices; the dongle can't talk back.

Where to start it

OTA lives in the web UI:

  1. Open the Settings page → Debug tab.
  2. Find the OTA Flash panel.
  3. Pick the target receiver from the dropdown (only online BKYD_TS_24_1 receivers are listed).
  4. Click Choose firmware and pick a .bin file from your devices/os4_receiver/bin/ directory (typically os4_receiver_v<N>.bin or latest.bin).
  5. Optionally pick an OTA data rate (see below).
  6. Click Start flash.

The progress bar streams live updates from the daemon. A typical 340 KB receiver image takes ~30–60 s at 2 Mbps.

What's actually happening

Sequence:

  1. The UI uploads the .bin to /tmp/ota_staging/<filename> inside the container (via the POST /api/system/ota_flash route).
  2. The daemon's OtaFlashDriver reads the entire image into memory and computes its CRC32.
  3. The daemon issues a flash_begin command to the dongle: flash_begin <ident> <total_size> <total_chunks> <crc32_hex> <rate>.
  4. The dongle relays an OTA_BEGIN frame to the target receiver over nRF24. The receiver allocates an Update.begin() write region, switches to the requested data rate, and replies begin_ok via ACK payload.
  5. For each 29-byte chunk: flash_data <idx> <hex> → dongle relays OTA_DATA → receiver writes to its OTA partition → ACK payload reports state. Strict ACK gating — chunk N+1 isn't sent until chunk N is acked.
  6. After the last chunk: flash_end → receiver does Update.end(true) and reboots into the new image.
  7. The dongle pings the receiver until it sees a RECEIVER_STATUS from the new firmware (rejoin window, 30 s timeout).

If a chunk nacks, the driver retries up to 12 times with backoff. After 3, 6, and 9 failures, it escalates flash_recover (REPLAY → SOFT → FULL) to recover the radio link.

OTA data rates

The dongle and receiver normally run at 250 kbps (RF24's most reliable rate). For OTA, you can pick a higher rate:

Rate flag Speed When to use
0 250 kbps Slowest, most reliable. Use if you're on a noisy channel or far away.
1 1 Mbps A reasonable balance.
2 2 Mbps (default) Fastest. Works fine in normal conditions and at typical operating distances.

After OTA finishes, the link returns to 250 kbps automatically.

Safety gating

The daemon refuses to start an OTA if any of these are true:

  • A show is currently loaded.
  • The system is armed.
  • The target receiver isn't currently online.
  • The target is BILUSOCN_433_TX_ONLY.
  • The image file can't be read.

So in practice: unload any staged show first, disarm the box, then start the OTA.

Watching progress

The progress bar in the UI shows:

  • Current chunk / total chunks.
  • Bytes transferred / total bytes.
  • Throughput (KB/s).
  • Current phase (begin, streaming, end, rejoin, done).

If you see lots of retries or the rate drops, the channel is congested or the link is marginal. Either move the receiver, switch RF channels (Settings → Debug → RF Scan finds clean channels), or step the rate down.

Aborting

Click Abort in the OTA panel. The driver sends flash_abort, the dongle relays OTA_ABORT, the receiver tears down its Update partition, and the radio returns to 250 kbps. The receiver remains on the previous firmware — OTA never overwrites the running image; only the inactive OTA slot is written, and the activation only happens on flash_end.

What if the receiver doesn't come back?

After a successful flash_end, the dongle waits up to 30 seconds for the receiver to re-emit a RECEIVER_STATUS from the new firmware. If that doesn't happen, the OTA reports error / timeout. Recovery options:

  1. Power-cycle the receiver. A reboot usually clears it. The receiver should come up on the new firmware (because Update.end(true) already swapped the active partition).
  2. Re-flash over USB. flash_receiver.py (no flag) writes the same artifact and resets boot_app0 to app0.
  3. Worst case, full recovery. flash_receiver.py --full. This always works on a chip that isn't physically broken.

Reference

Clone this wiki locally