Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .coveragerc

This file was deleted.

2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@ config.json
.coverage
htmlcov/
coverage.xml

data/
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,21 @@ All notable changes to WalkingDad will be documented in this file.

## [Unreleased]

### Added

- **Add to Home Screen opens WalkingDad full-screen** (ROADMAP 3.19), like an app, without the browser's address and tool bars.
- **Log to Apple Health from the iPhone or iPad running WalkingDad.** A phone can't scan its own screen, so on iPhone/iPad the per-session QR code is now a **Log to Apple Health** button, and the setup QR on the Settings page is an **Install Shortcut** button. Computers still show the QR codes, since a Mac can't write to Apple Health.
- **The Log to Apple Health prompt clears itself once the workout is logged**, on every open WalkingDad page. After the Shortcut finishes, the phone opens WalkingDad in Safari, which marks that session as logged. Dismissing the prompt is now recorded separately from logging. The installed Shortcut doesn't need to change.
- **See which sessions were logged to Apple Health, and log missed ones later.** With Apple Health export on, each session in Recent Sessions shows a filled heart once logged and an outline heart if not. **Edit** adds a **Log** button to each unlogged session.
- **Apple Health export logs steps.** WalkingDad now sends the session's step count to the Shortcut, which logs it as a Steps sample alongside the workout. Reinstall the Shortcut from Settings to pick this up; the old one keeps working without steps.
- **Delete individual sessions.** **Edit** also adds a delete button to each session in Recent Sessions, handy for removing test walks without clearing everything.
- **The screen stays on during an active session** (ROADMAP 3.12), and returns to normal on Pause or End. Browsers only allow this on `localhost` or HTTPS, so it works on the computer running WalkingDad but not on a phone connecting over your network.

### Changed

- **WalkingDad now has a real phone layout** (ROADMAP 3.19). Phones previously showed a shrunken desktop page. Now the speed reading fills the screen, the preset and Pause/End buttons sit full-width at the bottom within thumb reach, every button is large enough to tap while walking, the header controls fold into one menu button, and Recent Sessions shows as cards instead of a wide table. The desktop layout is unchanged.
- **Buttons show a pressed state when clicked or tapped**, instead of fading to transparent while held.
- **Everything WalkingDad writes now lives in a `data/` folder** instead of next to the code: settings (`data/config.json`), the session database, crash-recovery state, and the old JSON-migration backups (`data/backups/`). Existing files move there automatically the first time you start this version; nothing is overwritten. To edit settings by hand, use `data/config.json`.
- **`/reconnect` is now POST-only**, like the belt-control routes. The Connect and Try Again buttons on the connecting screen look and work the same.

### Fixed
Expand All @@ -19,6 +32,7 @@ All notable changes to WalkingDad will be documented in this file.
- **Tests now cover nearly all of the Python code** (ROADMAP 2.5): routes, Bluetooth sequences against a fake treadmill, status-packet math, persistence, and `run.py`'s launcher. The suite runs in about a second.
- **Continuous integration** (ROADMAP 2.7): `ruff` lint and the test suite run on pull/merge requests and on pushes to `main`/`development` via GitHub Actions (Python 3.10 and 3.13) and GitLab CI (Python 3.12, with coverage shown in merge requests). `ruff` is pinned in `requirements-dev.txt`, and lint fixes in `app.py` (imports sorted, unused `global` declarations removed) have no behavior change.
- **Importing `app.py` with `WALKINGDAD_NO_STARTUP=1` no longer installs the Ctrl+C/SIGTERM handlers or the `atexit` hook**, so pressing Ctrl+C during a test run interrupts pytest instead of killing the process two seconds later. Running the app normally is unchanged.
- **pytest, ruff, and coverage settings merged into `pyproject.toml`**, replacing `pytest.ini`, `ruff.toml`, and `.coveragerc`. `requirements-dev.txt` adds `coverage[toml]` so coverage reads it on Python 3.10.
- **`run.py`'s launcher logic moved into a `main()` function** so it can be tested. `python run.py` behaves the same.

---
Expand Down
23 changes: 14 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ The official WalkingPad experience is a bloated mobile app that wants your email
- **Smart pause & resume**: Auto-detects when you step off; remembers your speed; configurable grace period prevents re-triggering on restart; a session left paused too long (default 30 min) is ended and saved automatically
- **Speed presets**: Slow (speed floor), Moderate, and Max buttons, plus incremental increase/decrease steppers
- **Console-style interface**: Active, Paused, and Start screens read like the WalkingPad's own onboard display, with one large tabular-digit reading up top and secondary stats in a compact readout strip below
- **Session history**: Sessions saved to a local SQLite database (`walkingdad.db`) with full stats, pauses, and per-second speed/distance/steps samples; last 10 shown on the start screen. Includes CSV export and history clearing. An existing `session_history.json` from an older version is imported automatically on first launch (the original is kept as `session_history.json.bak-<timestamp>`).
- **Session history**: Sessions saved to a local SQLite database (`data/walkingdad.db`) with full stats, pauses, and per-second speed/distance/steps samples; last 10 shown on the start screen. Includes CSV export, history clearing, and an **Edit** mode for deleting individual sessions. An existing `session_history.json` from an older version is imported automatically on first launch (the original is kept as `data/backups/session_history.json.bak-<timestamp>`).
- **Crash recovery**: If the server crashes or restarts mid-session, your stats aren't lost. The start screen offers to restore the interrupted session (paused, ready to resume) or discard it.
- **Settings page**: Gear icon in the header lets you change settings (device name, speed limits, port, and more) from the browser without editing files
- **Dark mode**: Three-state toggle (Light → Dark → System) with localStorage persistence
Expand All @@ -39,7 +39,7 @@ The official WalkingPad experience is a bloated mobile app that wants your email
- ![Tide](https://img.shields.io/badge/Tide-11818c) summer, turquoise/sand, Pacifico headings, crabs scuttling along the bottom
- ![Harvest](https://img.shields.io/badge/Harvest-c2410c) mode-aware: cozy autumn (falling leaves) in Light, spooky Halloween (glowing eyes) in Dark
- ![Frost](https://img.shields.io/badge/Frost-b91c1c) winter, falling snow
- **Apple Health export**: Scan a QR code after a session ends to log it as a Workout on your iPhone, no manual re-entry. Runs entirely through a Shortcut on your own device; no Apple Developer account, no cloud service. See [Apple Health Export](#apple-health-export) below.
- **Apple Health export**: After a session ends, scan a QR code (or, on an iPhone/iPad running WalkingDad, tap a button) to log it as a Workout on your iPhone, no manual re-entry. Runs entirely through a Shortcut on your own device; no Apple Developer account, no cloud service. See [Apple Health Export](#apple-health-export) below.
- **Cross-platform BLE**: Tested on Windows, macOS, and Linux with retry logic and event loop cleanup
- **Graceful shutdown**: Stops the belt, switches to standby, and disconnects BLE whether you click Close in the UI, press Ctrl+C, or kill the process. Web UI shows "Server is shutting down" notification so you know what happened. Includes an `atexit` safety net as a last resort.
- **No account. No cloud. No phone required.**
Expand Down Expand Up @@ -93,28 +93,33 @@ The app opens your browser automatically at `http://127.0.0.1:5001`. A console w

Logs a completed session to Apple Health as a Workout, without typing anything in by hand. This only works on an iPhone (or iPad/Apple Watch). The Health app doesn't exist on macOS, so the Mac running WalkingDad can hand off the data but can't write it itself. No Apple Developer account is needed; this is a personal Shortcut on your own device, never distributed through the App Store.

**Off by default.** Turn it on first: Settings page (gear icon) → **Apple Health** → the **Enable Apple Health export** toggle. The rest of the section (Shortcut Name field, setup QR) only appears once it's on.
**Off by default.** Turn it on first: Settings page (gear icon) → **Apple Health** → the **Enable Apple Health export** toggle. The rest of the section (Shortcut Name field, setup QR or, on an iPhone/iPad, an **Install Shortcut** button) only appears once it's on.

**One-time setup:**

1. With the toggle on, scan the QR code shown there with your iPhone's Camera app. It opens Apple's own "Get Shortcut" page for a Shortcut that reads the workout data WalkingDad hands it and logs it via the built-in **Log Workout** action.
1. With the toggle on, scan the QR code shown there with your iPhone's Camera app, or tap **Install Shortcut** if you're on the iPhone/iPad itself. Either opens Apple's own "Get Shortcut" page for a Shortcut that reads the workout data WalkingDad hands it and logs it via the built-in **Log Workout** action.
2. Tap **Add Shortcut**. That's it. This only needs to happen once per phone.

If you'd rather build the Shortcut by hand (e.g. you're maintaining a fork and want your own copy rather than relying on a link tied to someone else's iCloud account), it's three actions:
If you'd rather build the Shortcut by hand (e.g. you're maintaining a fork and want your own copy rather than relying on a link tied to someone else's iCloud account), it's four steps:

1. `Get Dictionary from Input` (reads the JSON handed to the Shortcut).
2. `Log Workout`, with **Type** set to **Walking**, and **Date** / **Duration** / **Calories** / **Distance** each bound via Magic Variable to the matching key from the dictionary above (`start_time`+`date`, `duration_seconds`, `calories`, `distance_km` or `distance_mi`).
3. Name the Shortcut to match the **Shortcut Name** setting on the Settings page (default `Log WalkingDad Workout`) exactly. This is how WalkingDad's QR code knows which Shortcut to run.
3. `Log Health Sample`, with **Type** set to **Steps**, **Value** bound to `steps`, and **Date** to the same start date. The Value field only appears once Shortcuts is allowed to write Steps to Health.
4. Name the Shortcut to match the **Shortcut Name** setting on the Settings page (default `Log WalkingDad Workout`) exactly. This is how WalkingDad's QR code knows which Shortcut to run.

Then Share → Copy iCloud Link in the Shortcuts app, and swap `_APPLE_HEALTH_SHORTCUT_ICLOUD_LINK` in `app.py` for your own link.

**Every session after that:** when a session ends, the start screen shows a **Log to Apple Health** prompt. Tap it, scan the QR with your iPhone, done. The prompt sticks around (across reloads, navigating elsewhere, closing the browser) until you either scan it or tap **Dismiss**. It isn't a one-shot toast you can miss.
**Every session after that:** when a session ends, the start screen shows a **Log to Apple Health** prompt. On a computer, tap it and scan the QR with your iPhone. On an iPhone/iPad, it's a button that runs the Shortcut directly. Once the Shortcut finishes, the phone switches back to WalkingDad in Safari and the prompt clears on every open WalkingDad page, including the computer's. Until then it sticks around (across reloads, navigating elsewhere, closing the browser), or until you tap **Dismiss**. It isn't a one-shot toast you can miss.

**Missed one?** With export on, each session in **Recent Sessions** shows a filled heart once it's been logged and an outline heart if it hasn't (including dismissed ones). Tap **Edit** to get a **Log** button on each unlogged session, which works the same as the prompt (QR on a computer, button on iPhone/iPad), plus a delete button on every session. Only the sessions shown there can be logged this way; raise `history_display_limit` to reach older ones.

The phone reaches WalkingDad at the computer's network address, so this needs WalkingDad listening on the network (`host` `0.0.0.0`, the default), even if the computer itself uses `localhost`. If the phone can't reach it, the workout is still logged; only the prompt stays until you **Dismiss** it.

**Known issue:** older reports describe a Shortcuts bug where the `Log Workout` action's Duration field doesn't bind correctly to a variable. It bound correctly (raw seconds, no conversion needed) in hands-on testing while building this feature, but if your logged workouts ever show the wrong duration, check the Shortcut's Duration field is still wired to the dictionary value rather than a hardcoded default before assuming it's a WalkingDad-side bug.

## Configuration

Every setting except `database_path` can be changed from the **Settings page** (gear icon in the header); all of them can be set by editing `config.json` directly. Copy `config.json.example` to `config.json` to get started; running without the file uses the built-in defaults shown below.
Every setting except `database_path` can be changed from the **Settings page** (gear icon in the header); all of them can be set by editing `data/config.json` directly. Copy `config.json.example` to `data/config.json` to get started; running without the file uses the built-in defaults shown below. Everything WalkingDad writes (settings, database, crash-recovery state, backups) lives in `data/`; files that older versions kept in the app folder are moved there automatically on first start.

| Key | Default | Description |
|---|---|---|
Expand All @@ -132,7 +137,7 @@ Every setting except `database_path` can be changed from the **Settings page** (
| `waitress_threads` | `16` | Server worker thread count (4-128) |
| `apple_health_export_enabled` | `false` | Shows the Log to Apple Health prompt after each session; see [Apple Health Export](#apple-health-export) |
| `apple_health_shortcut_name` | `"Log WalkingDad Workout"` | Must match the installed Shortcut's name exactly; see [Apple Health Export](#apple-health-export) |
| `database_path` | `"walkingdad.db"` | SQLite database file (relative to the app directory) |
| `database_path` | `"walkingdad.db"` | SQLite database file (relative to `data/`) |

Changes to most settings take effect immediately via the Settings page. `host`, `port`, `waitress_threads`, and `database_path` require restarting the app.

Expand Down
Loading
Loading