No description
  • Python 92.5%
  • JavaScript 4.9%
  • Shell 2.6%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-25 17:13:58 -04:00
scripts Recover R-peak detection after missed beats 2026-09-24 00:20:54 -04:00
tests Recover R-peak detection after missed beats 2026-09-24 00:20:54 -04:00
.gitignore Move Godot starter to dedicated embodiment study repository 2026-09-23 16:51:46 -04:00
.pre-commit-config.yaml Add H10 hub, NiceGUI dashboard and Godot clients 2026-09-22 18:27:35 -04:00
.python-version Add Polar H10 heart-rate streaming script with lint tooling 2026-09-22 17:11:06 -04:00
AGENTS.md Recover R-peak detection after missed beats 2026-09-24 00:20:54 -04:00
CLAUDE.md Add Polar H10 heart-rate streaming script with lint tooling 2026-09-22 17:11:06 -04:00
config.example.toml Add config file and setup script 2026-09-22 20:19:52 -04:00
pyproject.toml Add config file and setup script 2026-09-22 20:19:52 -04:00
README.md Update README and add a screenshot 2026-09-25 17:13:58 -04:00
screenshot.png Update README and add a screenshot 2026-09-25 17:13:58 -04:00
setup.sh Add config file and setup script 2026-09-22 20:19:52 -04:00
uv.lock Add derived measures, replay transport and export 2026-09-22 19:41:14 -04:00

Embodiment: Polar H10 hub

Screenshot

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