A lightweight real-time heart-rate monitoring system using a Samsung Galaxy Watch 4, Heart for Bluetooth, HR PUSH, and FastAPI WebSockets.
The project receives heart-rate data from the watch through Bluetooth, forwards it to a FastAPI webhook, and instantly displays the data on a live web dashboard.
No MQTT. No database. No polling. No external frontend framework.
ββββββββββββββββββββββββ
β Samsung Galaxy β
β Watch 4 β
ββββββββββββ¬ββββββββββββ
β
β Heart Rate
βΌ
ββββββββββββββββββββββββ
β Heart for Bluetooth β
β Wear OS App β
ββββββββββββ¬ββββββββββββ
β
β Bluetooth LE
βΌ
ββββββββββββββββββββββββ
β HR PUSH β
β Android App β
ββββββββββββ¬ββββββββββββ
β
β HTTP POST
βΌ
ββββββββββββββββββββββββ
β FastAPI β
β /webhook/hr β
ββββββββββββ¬ββββββββββββ
β
β Validate + Normalize
βΌ
ββββββββββββββββββββββββ
β In-Memory State β
β Latest HR + History β
ββββββββββββ¬ββββββββββββ
β
β WebSocket
βΌ
ββββββββββββββββββββββββ
β Web Dashboard β
β β
β β€οΈ 82 BPM β
β β
β Min Avg Max + Chart β
ββββββββββββββββββββββββ
Install Heart for Bluetooth on the Galaxy Watch from Google Play.
[Heart for Bluetooth β Google Play](https://play.google.com/store/apps/details?id=lukas.the.coder.heartforbluetooth
The application runs on Wear OS and turns the watch into a standard Bluetooth Low Energy heart-rate sensor. Galaxy Watch 4/5 are listed among its tested watches.
Important: Heart for Bluetooth is installed on the watch, not the Android phone.
Install HR PUSH on the Android phone.
HR PUSH receives the Bluetooth heart-rate data and forwards it to your HTTP endpoint.
- Samsung Galaxy Watch 4
- Android phone
- Bluetooth enabled
- Phone and FastAPI server reachable over the network
- Python
- FastAPI
- Uvicorn
- WebSockets
-
main.py: for vercel (it require redis) -
app.py: for vps server -
hr.service: systemd setup for webhook server -
install packages
pip install fastapi uvicorn httpx gunicorn websockets httptools uvloop- Test on Localhost
uvicorn app:app --host 0.0.0.0 --port 6023- Open Google Play Store on the Galaxy Watch 4.
- Install Heart for Bluetooth.
- Open the application on the watch.
- Start heart-rate broadcasting.
- Keep Bluetooth enabled.
- Make sure the phone is able to detect the watch's BLE heart-rate service.
Heart for Bluetooth exposes the watch's current heart rate using the standardized Bluetooth Low Energy heart-rate protocol.
If heart-rate transmission stops when the Watch 4 screen turns off, check the watch's background activity permissions for Heart for Bluetooth.
Open HR PUSH on your Android phone.
Configure its HTTP/webhook destination:
http://SERVER_IP:2603/webhook/hr
For example:
http://127.0.0.1:2603/webhook/hr
Use:
Method: POST
Content-Type: application/json
The phone must be able to reach the FastAPI server.
The FastAPI endpoint accepts common heart-rate JSON formats.
{
"heart_rate": 82
}Also supported:
{
"bpm": 82
}{
"hr": 82
}{
"heartRate": 82
}Nested data is also supported:
{
"data": {
"heart_rate": 82
}
}Before testing with HR PUSH, verify the server manually:
curl -X POST \
http://127.0.0.1:2603/webhook/hr \
-H "Content-Type: application/json" \
-d '{"heart_rate":82}'Expected response:
{
"success": true,
"message": "Heart-rate reading accepted",
"timestamp": "2026-09-09T07:30:00.000Z",
"data": {
"heart_rate": 82,
"timestamp": "2026-09-09T07:30:00.000Z",
"source": "HR PUSH",
"connected_clients": 1
}
}The browser should immediately display:
β€οΈ
82
BPM
No page refresh is required.
| Endpoint | Method | Description |
|---|---|---|
/ |
GET | Live dashboard |
/webhook/hr |
POST | Receive HR data |
/api/hr |
GET | Get latest HR |
/api/health |
GET | Service health |
/ws |
WebSocket | Real-time HR stream |
The server broadcasts:
{
"type": "heart_rate",
"data": {
"heart_rate": 82,
"timestamp": "2026-09-09T07:30:00.123Z",
"source": "HR PUSH"
}
}When a browser initially connects, it receives a snapshot:
{
"type": "snapshot",
"data": {
"heart_rate": 82,
"timestamp": "2026-09-09T07:30:00.123Z",
"source": "HR PUSH"
},
"history": [],
"server_time": "2026-09-09T07:30:01.000Z"
}FastAPI provides native WebSocket support for persistent real-time connections and can send/receive text, JSON, and binary data.
Incoming heart-rate values are validated before broadcasting.
Default accepted range:
25 BPM β 250 BPM
Invalid values are rejected.
Examples:
null β
"hello" β
-10 β
0 β
999 β
82 β
The server also validates:
- HTTP method
- Content-Type
- JSON syntax
- JSON object structure
- Heart-rate field
- Numeric value
- Physiological range
For a public server, configure a webhook token:
export HR_WEBHOOK_TOKEN="your-long-random-secret"Then send:
X-Webhook-Token: your-long-random-secret
Example:
curl -X POST \
http://127.0.0.1:2603/webhook/hr \
-H "Content-Type: application/json" \
-H "X-Webhook-Token: your-long-random-secret" \
-d '{"heart_rate":82}'The web interface provides:
- β€οΈ Current BPM
- π’ Live connection status
- π Last update time
- Minimum HR
- Average HR
- Maximum HR
- Lightweight real-time graph
- Automatic WebSocket reconnect
- Responsive mobile/desktop UI
The dashboard uses the browser's native WebSocket API and HTML/CSS/JavaScript.
The application is intentionally lightweight.
HTTP webhook
β
Validate
β
Update in-memory state
β
Broadcast WebSocket message
β
Browser
There is:
- No database query for every reading
- No HTTP polling
- No MQTT broker
- No Redis
- No background worker
- No frontend framework
- No external JavaScript library
Recent readings are stored in a bounded in-memory history, preventing unlimited RAM growth.
Samsung Galaxy Watch 4
β
β Bluetooth LE
βΌ
Heart for Bluetooth
β
βΌ
HR PUSH
β
β HTTP POST / JSON
βΌ
FastAPI
β
βββ REST API
β
βββ WebSocket
β
βΌ
HTML + CSS + JavaScript
- Python
- FastAPI
- Uvicorn
- WebSockets
- HTML5
- CSS3
- Modern JavaScript
- WebSocket API
- Canvas API
- Bluetooth Low Energy
- HTTP/HTTPS
- JSON
- WebSocket
A heart-rate reading of 82 BPM travels through the system:
Galaxy Watch
β
β 82 BPM
βΌ
Heart for Bluetooth
β
β BLE Heart Rate
βΌ
HR PUSH
β
β POST /webhook/hr
β {"heart_rate":82}
βΌ
FastAPI
β
β Validate
β Store latest value
βΌ
WebSocket
β
β {"type":"heart_rate",...}
βΌ
Browser
β
βΌ
β€οΈ 82 BPM
Typical end-to-end behavior is event-driven: the server does not repeatedly ask for the current heart rate; it receives the reading and pushes it to connected browsers.
Heart for Bluetooth
HR PUSH
FastAPI
This project is intended for personal monitoring and experimentation.
The displayed heart rate should not be considered a medical measurement or used for medical diagnosis.
Built with:
- Samsung Galaxy Watch 4
- Heart for Bluetooth by Lukas the Coder
- HR PUSH
- FastAPI
- WebSockets
- Python