BackDeployed
Deployed2025 — presentAuthor

PrabalOS

A connected ESP32 device for staying in touch

A physical device for family communication that had to keep working, unattended, from the other side of the world — so everything about it is designed around not being able to touch it again.

Problem

Moving thousands of kilometres away turns a hobby device into infrastructure. It has to stay up without physical access, survive a bad firmware flash, and be usable by people who are not going to debug it.

Every interesting decision in the project follows from that: the device has to be updatable remotely, and the update path has to be able to fail safely.

What I built

The hardware, the firmware, the backend and the control panel.

  • ESP32 hardware with display, touch input, audio and physical buttons
  • WiFi communication with backend APIs and device synchronisation
  • Remote messaging, voice notes and drawings, with multi-sender interactions
  • Discord integration
  • Secure login with TOTP authentication and recovery codes
  • Private blob storage and a remote firmware update flow
  • Timezone handling

Designing for no physical access

Remote firmware delivery is the load-bearing feature. A device you cannot reach needs an update path that verifies what it downloaded and can roll back when the new image does not come up — which is the problem the HttpsOta library was extracted to solve.

A message reaching a device on another continent

The interesting part is not the feature. It is that every hop has to survive the device being unreachable, asleep, or on a network nobody controls.

  1. Someone writes, draws or records a voice note

    From the web control panel, or via the Discord integration.

  2. Authenticated

    TOTP, with recovery codes for the case where the authenticator is lost.

    Not authenticated — the API returns 401 rather than a redirect
  3. Stored

    Private blob storage for drawings and voice notes; state in Redis.

  4. The device polls and synchronises

    Over WiFi, on its own schedule — the backend never assumes it is reachable.

  5. It lands on the display

    With touch, audio and physical buttons to respond.

Updating a device you cannot reach

The load-bearing feature. A failed update on a device thousands of kilometres away is the end of the device, which is why the OTA path was extracted into its own library.

  1. A new firmware image is published

  2. The device checks version, hash and size

  3. Downloads to the inactive OTA slot

    SHA-256 verified while downloading.

    Hash mismatch or stall — nothing is installed
  4. Reboots into the new image

    Comes up and reports its version
    Does not — automatic rollback to the previous slot

The parts

LayerWhat is there
DeviceESP32, display, touch input, audio, physical buttons, WiFi
FirmwareSynchronisation, rendering, input handling, OTA client
BackendAPIs for messaging, voice notes, drawings and device sync; Redis state; private blob storage
Control panelWeb UI for sending, plus firmware delivery and device status
AuthTOTP login, recovery codes, session guard on every write route
IntegrationsDiscord, and timezone handling for a device in another timezone

Limitations and failure modes

  • One deployed device. Nothing here is validated at fleet scale.

Gallery

Not yet captured

  • The device
  • The control panel
  • Drawing and voice note arriving on the device

Attribution

Built by me
Hardware, firmware, backend, control panel and deployment.

Related

  • HttpsOta

    Over-the-air updates for ESP32, over TLS, with rollback