Offline-first electronic patient records over a small ESP32 Bluetooth Low Energy relay mesh.
Warning
Research prototype only. HMS Offline is not clinically certified, production-ready, or approved for patient care. Do not use it with real patient data or as the basis for clinical decisions.
Hospitals and field clinics cannot assume continuous internet access. HMS Offline explores whether several phones can keep a small electronic patient record (EPR) dataset available and eventually consistent using local storage and inexpensive BLE relay nodes, without a central server.
- A Flutter mobile app for iOS and Android with a local SQLite database managed by Drift (schema version 9).
- ESP32 firmware that accepts phone connections and forwards framed sync traffic across a small multi-hop BLE relay mesh.
- Conflict-aware replication that preserves concurrent edits for manual, field-level resolution instead of silently choosing a winner.
- A Dart evaluation harness, macOS site runner, Swift CoreBluetooth proxy, and physical BLE smoke-test utility.
flowchart LR
subgraph A[Phone A]
AUI[Flutter EPR]
ADB[(Drift / SQLite v9)]
AUI --- ADB
end
subgraph Mesh[Small ESP32 BLE relay mesh]
R1[ESP32 relay]
R2[ESP32 relay]
R3[ESP32 relay]
R1 <--> R2
R2 <--> R3
R1 <--> R3
end
subgraph B[Phone B]
BUI[Flutter EPR]
BDB[(Drift / SQLite v9)]
BUI --- BDB
end
AUI <-->|BLE framed messages| R1
R3 <-->|BLE framed messages| BUI
Phones own the durable patient data. ESP32 nodes are bounded, store-and-forward transports: they queue, deduplicate, and flood messages but do not maintain the EPR database. Each protocol payload is wrapped in an 8-byte header containing magic, version, flags, payload length, and CRC16.
Mutable patient and medical-record rows carry the Lamport timestamp and
content hash of the version their editor saw. An incoming edit fast-forwards
only when that (parentLamport, parentRowHash) matches the receiver's current
row. A mismatch preserves the incoming version as a conflict branch for manual
field-level merge. Lamport clocks still provide logical ordering; the content
parent hash prevents equal-clock versions from being mistaken for the same
parent.
Vital observations are immutable. Corrections create a new vital linked to the original, giving the table grow-only-set semantics instead of in-place edits.
Periodic Merkle roots cheaply detect that two datasets differ. The live repair
path then exchanges cursor-paginated (rowId, leafHash) manifests, computes a
keyed set difference, and requests only missing or divergent rows. The older
positional Merkle walk remains in the codebase but is dormant because tree
shape can differ when peers hold different row sets.
See the protocol reference and conflict-resilience design for the wire formats and decision rules.
| Path | Purpose |
|---|---|
mobile-app/ |
Flutter EPR application and sync engine |
embedded/ESP32-Mesh-Node/ |
ESP32 relay and mesh firmware |
harness/ |
Distributed scenarios, orchestration, assertions, and site runners |
hardware-test/ |
Physical macOS BLE smoke utility using virtual phones and a real relay |
tools/ble-proxy/ |
Swift CoreBluetooth bridge used by simulated phones |
docs/ |
Architecture, protocol, design history, setup, and evaluation material |
- Verified release toolchain: Flutter 3.41.6 (stable) with its bundled Dart 3.11.4. Other versions are not part of the reproducibility baseline.
- PlatformIO 6.x and an ESP32 development board for firmware.
- Android Studio or Xcode for a mobile build; device signing is platform specific.
- macOS 12 or later with Xcode command-line tools and Bluetooth for the Swift proxy and physical BLE utilities.
See the development guide for device setup and troubleshooting.
Executable Dart/Flutter packages commit pubspec.lock so pub get reuses the
validated dependency versions. Reusable library packages
harness/shared and harness/scenarios intentionally do not commit locks.
Mobile app:
cd mobile-app
flutter pub get
flutter test
# Optional Android build
flutter build apkESP32 firmware:
cd embedded/ESP32-Mesh-Node
pio test -e native_test
pio run -e meshDart director:
cd harness/director
dart pub get
dart test
export HOME_PC_TOKEN="$(openssl rand -hex 32)"
dart run bin/director.dart serve --port 8080 \
--scenarios-dir ../scenarios/exampleThe director listens on 0.0.0.0; run it only on a trusted private network
behind a firewall and configure every client with the same HOME_PC_TOKEN.
macOS BLE proxy:
cd tools/ble-proxy
swift build -c releaseSimulation and physical evidence are kept distinct:
- Automated simulation exercises convergence, partitions, concurrent edits, anti-entropy, and bounded-ripple assertions without claiming radio behavior.
- Physical testing validated two phones through one relay, including convergence and empty-phone backfill.
- A two-phone, two-relay chain validated multi-hop reconciliation in both directions.
- A three-relay triangle formed and converged under light incremental load.
Heavy bulk traffic over the triangle has not been validated. It can exhaust the constrained BLE buffer pool on a redundant edge, so the light-load result must not be read as a throughput or production-scale claim. Reproduction procedures and empty result tables are in the evaluation runbook and results template.
- Direct phone-to-phone transport is deferred; deployed sync paths assume an ESP32 relay.
- iOS background sync is not implemented, so iOS sync is foreground-only.
- Relays have no peer authentication, messages have no application-layer encryption, and the app has no role-based access control (RBAC). The current threat model assumes trusted lab devices and is unsuitable for clinical data.
- Flood routing and the current lock-based firmware design target a small mesh of roughly four relays or fewer. Larger deployments need a different routing and ownership model.
- Hardware results cover the specific topologies and loads listed above, not reliability, safety, or performance in a clinical deployment.
Additional constraints are tracked in the architecture and sync design evolution.
- System architecture
- Protocol reference
- Conflict-resilience design
- Sync design evolution
- Development guide
- Evaluation runbook
- Results template
- Glossary
Copyright (c) 2026 Idrees Mahmood. All rights reserved. This repository is available for viewing and evaluation only; see LICENSE.