- Python 92.5%
- JavaScript 4.9%
- Shell 2.6%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| scripts | ||
| tests | ||
| .gitignore | ||
| .pre-commit-config.yaml | ||
| .python-version | ||
| AGENTS.md | ||
| CLAUDE.md | ||
| config.example.toml | ||
| pyproject.toml | ||
| README.md | ||
| screenshot.png | ||
| setup.sh | ||
| uv.lock | ||
Embodiment: Polar H10 hub
Streams heart data from a Polar H10 chest strap (heart rate, RR intervals, ECG, acceleration) and derived measures (HRV, breathing, posture) to other programs, such as a Godot game, over WebSocket. A browser dashboard shows the live signals and records, replays and exports sessions.
Requirements
- Linux with a working Bluetooth adapter. For Windows/macOS, manually setup the config file is mandatory.
- A Polar H10, worn (the electrodes need skin contact)
- uv (it installs Python 3.13 by itself)
Setup and run
Wear the strap, then:
./setup.sh
It installs the Python environment, finds your H10 over Bluetooth (pick it
from the list), writes config.toml after a few questions, and offers to
start the dashboard. Finished steps are skipped when you run it again, so
./setup.sh is also the everyday way to start.
To do it by hand instead: uv sync, cp config.example.toml config.toml,
set [sensor] address in config.toml, then run the dashboard as below.
Configuration
config.toml holds the local settings and is not committed. config.example.toml
is the template, with every option and its default:
| Setting | Default | What it does |
|---|---|---|
[sensor] address |
none | Bluetooth address of the H10 |
[hub] host / port |
127.0.0.1 / 8765 |
Where programs connect to the data. 0.0.0.0 also accepts other machines (e.g. the lab network) |
[dashboard] host / port |
127.0.0.1 / 8080 |
Where the dashboard is served. It has no login, so use 0.0.0.0 only on trusted networks |
[hub] record_dir |
recordings |
Where recordings are saved |
Command-line flags override the file (--address, --host, --port, or
--lan as a shortcut for --host 0.0.0.0). To use another file, pass
--config other.toml or set H10_CONFIG=other.toml.
Dashboard
uv run scripts/h10_dashboard.py --show
This opens the dashboard (http://127.0.0.1:8080 by default) and starts the hub in the background. The first Bluetooth connection can take about 30 seconds. Ctrl+C stops both.
From the dashboard you can:
- Record a session to
recordings/<date_time>/(same-second sessions get a numeric suffix; existing sessions are never overwritten). - Replay a recording: pick it in the Source menu, then use play, pause, seek and loop
- Export a recording as a CSV bundle (.zip) or a single JSON file
- Send markers that are timestamped alongside the data
Resuming a paused replay starts a fresh signal-processing timeline and clears the dashboard charts. Derived measures warm up again, as they do after seeking; this keeps sample timestamps aligned with the current host clock. The dashboard also clears cached data when its connection to the hub is lost.
Use the data in another program
Clients connect to the hub (ws://127.0.0.1:8765 by default) and receive
one JSON object per message, for example:
{"type": "hr", "t": 1790116624.5, "bpm": 72, "rr_ms": [830], "quality": "good"}
Other types: ecg, acc, beat, resp, metrics, status, marker, and
reset, which means the timeline jumped (e.g. a replay was seeked): clear
anything you show. Clients can send {"type": "marker", "label": "trial_start"}.
The Godot client and embodiment experiment now live in the separate embodiment-study repository. This utility remains independent of Godot; any client can consume the WebSocket protocol above.
The hub also runs without the dashboard:
uv run scripts/h10_hub.py # live sensor
uv run scripts/h10_hub.py --lan # also reachable from the network
uv run scripts/h10_hub.py --replay recordings/20260922_183649 --loop
uv run scripts/h10_hub.py --help # all options
Development
uv run pre-commit install # run the checks on every commit
uv run pre-commit run --all-files # ruff, mypy (strict) and pytest
