Getting Started NEXT firmware

Programming the ESP32-C3 (Wireless)

Last updated Jul 10, 2026

The HealthyPi 5 carries two microcontrollers, each with its own firmware. The RP2040 acquires the biosignals. The ESP32-C3 owns the radios. Flashing one does not touch the other.

Chip Firmware What it does
RP2040 protocentral_healthypi_5_firmware Sensors, DSP, USB streaming, microSD
ESP32-C3 healthybridge-esp32 BLE, Wi-Fi, MQTT, web dashboard

This page covers the ESP32-C3. For the RP2040, see Arduino Quick Start.

Moving an existing board to NEXT? You must flash this chip too

Your ESP32-C3 does not have HealthyBridge on it. Boards running the earlier firmware carry a plain Bluetooth HCI controller image instead — a different thing entirely.

Flashing NEXT onto the RP2040 without also flashing HealthyBridge onto the ESP32-C3 leaves you with no Bluetooth at all: the device simply never appears in the phone app.

Jump to Upgrading an existing board.

Do you need to do this?

Moving an existing board to NEXT: yes, always. See below.

Otherwise, only if you want wireless. The board is fully useful without ever touching the ESP32-C3:

You want… ESP32-C3 firmware needed?
Live signals in OpenView 2 over USB No
Recording to the microSD card No
The teaching sketches (01–09, 11) No
Heart rate / SpO₂ / respiration on-device No
BLE streaming to the phone app Yes
Wi-Fi dashboard in a browser Yes
MQTT publishing Yes
10_Wireless_Bridge tutorial Yes

Upgrading an existing board

This is the common case: you have a HealthyPi 5 that has been running the earlier firmware, and you’re moving it to NEXT.

NEXT inverts which chip owns Bluetooth. That’s why a second flash is unavoidable.

Earlier firmware NEXT
RP2040 Ran the whole BLE host stack — GATT services, advertising Acquires and streams framed vitals over UART
ESP32-C3 A bare HCI controller — just the radio, driven over UART Runs HealthyBridge: its own BLE stack, plus Wi-Fi, MQTT, dashboard
The UART between them Bluetooth HCI H4 commands HealthyBridge frames — 0xAA55 + CRC-16, 921600 baud, RTS/CTS

Under the old design the ESP32-C3 never knew what a heart rate was; it relayed raw Bluetooth controller traffic and the RP2040 did the thinking. Under NEXT the roles swap: the ESP32-C3 becomes a self-contained wireless application, and the RP2040 just hands it finished vitals and waveforms.

The two firmwares therefore speak completely different protocols over the same wire. An HCI controller cannot parse HealthyBridge frames, and nothing on a NEXT RP2040 speaks HCI.

What you’ll see if you skip it

  • No Bluetooth. The device never advertises, so it never appears in the phone app or a BLE scanner. Advertising used to be driven by the RP2040’s host stack, and NEXT doesn’t have one.
  • Everything else works. USB streaming to OpenView 2, microSD recording, on-device vitals, and all the teaching sketches are unaffected — none of them involve the ESP32-C3.

What to do

Flash the ESP32-C3 with HealthyBridge, using Option A below. Use its own USB-C port. A full install is correct here — there are no HealthyBridge settings to preserve on a chip that has never run it.

Once both chips are updated you also gain capabilities the board never had: a Wi-Fi dashboard, MQTT publishing, and captive-portal provisioning. The BLE service map is preserved from the earlier firmware, so the existing OpenView 2 phone app connects unchanged.

Use the ESP32-C3’s own USB-C port

The board has two USB Type-C ports — one wired to the RP2040, one to the ESP32-C3. Flashing the ESP32-C3 requires the ESP32 port. Plugging into the RP2040 port and running these commands will simply not find the chip.

Option A — flash the prebuilt firmware

The quickest path, and no toolchain beyond esptool.

  1. Install esptool.

     pip install esptool
  2. Download from the latest release, into one directory:

    File Why
    healthybridge-esp32-merged.bin Full image — bootloader + partition table + app
    healthybridge-esp32-app.bin App only, for updates that keep your settings
    flash.sh (macOS/Linux) or flash.bat (Windows) Wrapper around esptool
  3. Find the serial port with the ESP32-C3 port connected:

    OS Port looks like
    macOS /dev/cu.usbmodem*
    Linux /dev/ttyACM0
    Windows COM5
  4. Flash.

     ./flash.sh /dev/ttyACM0                # full install
     ./flash.sh /dev/ttyACM0 --app-only     # update, keep Wi-Fi settings
  5. Reset the board — unplug and replug, or press reset — to run the new firmware.

A full install erases your Wi-Fi credentials

The merged image is written at 0x0 and overwrites the NVS partition, so stored Wi-Fi, MQTT and dashboard settings go with it. You’ll re-provision through the captive portal afterwards.

Use --app-only (written at 0x10000) to update the firmware and keep those settings.

There is no over-the-air update path — the partition table has a single factory app, so every update is over USB.

Option B — build from source

Needed if you’re modifying the bridge firmware.

  1. Install ESP-IDF v6.0 or later, following the official Get Started guide, then load it into your shell:

     . $IDF_PATH/export.sh
  2. Clone and build. The MQTT and mDNS managed components are fetched automatically on the first build; they aren’t vendored in the tree.

     git clone https://github.com/Protocentral/healthybridge-esp32.git
     cd healthybridge-esp32
     idf.py set-target esp32c3
     idf.py build
  3. Flash and watch the log. Press Ctrl-] to leave the monitor.

     idf.py -p /dev/ttyACM0 flash monitor

First-time provisioning

With no stored Wi-Fi credentials, the ESP32-C3 comes up as a captive portal.

  1. On your phone or laptop, join the open access point named HealthyPi-XXXX.
  2. A form opens automatically. Enter your Wi-Fi SSID and password, and toggle the MQTT and dashboard options.
  3. Submit. The device reboots into station mode and joins your network.
  4. Open http://healthypi.local — the dashboard shows live vitals, ECG and PPG waveforms, battery level, Wi-Fi signal, and BLE status.

If Wi-Fi fails repeatedly, the device falls back to the setup portal on its own. There’s also a re-provision button in the dashboard.

Provision on a network you trust

This firmware targets lab benches and personal LANs. It is not hardened for hostile networks:

  • The provisioning access point is open — no password — so anyone in radio range during setup can join it and submit the form.
  • The captive portal and the dashboard have no authentication, and both serve plain HTTP. Any host on your network can read vitals, change settings, and trigger a re-provision.
  • Wi-Fi credentials are stored unencrypted in NVS. If physical access to the board is a concern, enable NVS and flash encryption.
  • mqtt:// is unencrypted. Use mqtts:// with a TLS-capable broker if the vitals stream leaves your network.

What you get

Once both chips are running their firmware, the ESP32-C3 re-exposes the RP2040’s stream over three channels at once:

  • BLE — advertises as “HealthyPi 5”, with the same service map as the earlier firmware, so the existing OpenView 2 mobile app connects unchanged. Standard SIG services for heart rate, battery, pulse oximetry and temperature, plus custom services for the ECG/PPG waveforms and the command plane.
  • Web dashboard — live vitals and waveform streaming at http://healthypi.local, with lead-off warnings and a settings form.
  • MQTT — vitals JSON (hr, spo2, rr, temp) published once per second to healthypi5/<mac>/vitals. Optional; broker URI is configurable.

BLE and Wi-Fi share the single 2.4 GHz radio through software coexistence, so you don’t have to choose.

Checking the link

On the RP2040 side, enable the bridge with HealthyPi5.enableBridge() and watch the 1 Hz HPI_INSTR telemetry line on UART0. The hbtx counter should climb.

If frames sent stay at 0 while drops rise, the ESP32-C3 isn’t draining the UART — it’s unflashed, held in reset, or its CTS line is deasserted. The RP2040 drops frames rather than blocking, so acquisition keeps running regardless. Full symptom table: Wireless: BLE & Wi-Fi.

The link is already wired on the PCB

The two chips are connected by UART at 921600 8N1 with RTS/CTS. Nothing to wire. On the ESP32-C3 side the pins are fixed in main/hb_link.c: TX GPIO6, RX GPIO7, RTS GPIO5, CTS GPIO4.

Next