No description
  • Kotlin 73.1%
  • C 21.1%
  • Python 4.3%
  • JavaScript 0.7%
  • Dockerfile 0.6%
  • Other 0.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-27 23:05:43 +00:00
.claude/agents Add Bastion, a security engineer persona, to the team 2026-09-03 23:35:28 +02:00
.forgejo/workflows Fix: android-assemble-release's 5-minute budget too tight for a full release build 2026-09-28 01:03:16 +02:00
companion Fix: top-level :companion module's first-ever compile -- missing return, Float/Double mismatch, wrong Android APIs 2026-09-28 00:29:23 +02:00
docs ci: ratchet coverage floor [skip ci] 2026-09-27 23:05:43 +00:00
gradle Fix: companion:map's first-ever compile -- missing GeoBox type, wrong APIs, and real logic bugs 2026-09-28 00:28:58 +02:00
shared shared/message_keys.json plus C and Kotlin codegen (#7) 2026-09-04 16:54:50 +02:00
tooling/docker Fix: android-toolchain image lacked jq, needed by slow-lane's jvm-coverage job 2026-09-28 00:40:13 +02:00
tools Add comprehensive API reference documentation 2026-09-22 17:03:04 +02:00
watchapp Fix: CI pipeline infrastructure and watchapp compile errors 2026-09-25 14:26:29 +02:00
.editorconfig Fix: top-level :companion module's first-ever compile -- missing return, Float/Double mismatch, wrong Android APIs 2026-09-28 00:29:23 +02:00
.gitignore Add the Android companion project skeleton 2026-09-03 22:32:05 +02:00
build.gradle.kts Route library: storage, list UI, distance and elevation profile (#25) 2026-09-04 10:47:35 +02:00
gradle.properties Add the Android companion project skeleton 2026-09-03 22:32:05 +02:00
gradlew Add the Android companion project skeleton 2026-09-03 22:32:05 +02:00
gradlew.bat Add the Android companion project skeleton 2026-09-03 22:32:05 +02:00
LICENSE Add project documentation and 2026-09-02 design review 2026-09-02 15:06:46 +02:00
README.md Add FAQ covering architecture, testing, performance, and design 2026-09-21 20:26:58 +02:00
settings.gradle.kts Settings: units, wheel circumference, HR alerts, auto-pause, vibration (#44) 2026-09-04 14:34:32 +02:00

PedalPebble

A cycling computer for the Pebble Time 2 and Pebble Round 2, paired with an Android phone.

Shows speed, average speed and heart rate on the wrist; later, turn-by-turn navigation for routes planned in komoot, and a map view.

fast-lane slow-lane dev build

Latest installable build (debug .pbw + .apk, updated on every push): the "dev build" badge above, or docs/CI.md if it hasn't gone green yet.

Status

Planning complete and closed. Development has started: the Pebble toolchain is installed and verified end to end (#2, D54), and watchapp/ holds a scaffolded project that builds for emery, gabbro and basalt and runs on both emulators. See docs/DEV.md for the local setup.

No further planning rounds happen until the two blocker spikes below have run — see D48. Their findings reopen the documents; nothing else does.

Installing

Two halves, both required: a watchapp on the Pebble and a companion app on the phone. There is no Rebble store or Core Devices store listing — distribution is Forgejo releases on this repo (see docs/DEV.md#releasing for the full scheme):

  1. Companion: install the .apk from the dev build (updated on every push) or a tagged release — Android will ask for an "install unknown apps" grant the first time.
  2. Watchapp: sideload the .pbw from the same release page onto emery and/or gabbro — one .pbw contains both platforms.

If you only update one half: the watch and phone compare a protocol contract version the instant they connect, and refuse to start a ride on a mismatch rather than run with plausible-looking wrong numbers (PROTOCOL.md §6, #53). Both sides show which one is stale. Most releases bump the app version without touching this contract at all — the watchapp/companion version strings (kept identical between the two) and the protocol contract version are deliberately two different numbers; see docs/DEV.md#releasing.

Hardware and platform

Watches Pebble Time 2 — emery, 200×228 rectangular, 64-colour e-paper, 4 buttons
Pebble Round 2 — gabbro, 260×260 round, colour e-paper at 283 DPI, 4 buttons
Heart rate The watch's own optical sensor — Time 2 only; the Round 2 has no HRM, so the field is simply absent there
Phone Android — supplies GPS, navigation and the map
Speed Phone GPS, with an optional BLE wheel sensor (Cycling Speed & Cadence, 0x1816)
Routes GPX, imported through the Android share sheet — komoot, bikerouter.de, RideWithGPS, Strava
Turn cues Read from the GPX where the planner provides them; otherwise derived on the phone at import

The Pebble has no GPS of its own, and iOS is not supported: Core Devices discontinued PebbleKit iOS, so a companion app is only possible on Android.

Documentation

Start here: docs/QUICK-REF.md — one-page reference for common tasks

Document What it covers
docs/QUICK-REF.md One-page reference for build, test, debug, git, code review, and release checklists
docs/FAQ.md Answers to common questions about architecture, testing, performance, security, and routing
docs/DECISIONS.md Every significant decision, with its rationale and the options rejected
docs/ARCHITECTURE.md Module layout, data flow, dependencies, and where code belongs for each feature
docs/DESIGN.md Watch display: page descriptors, templates, default pages, button model
docs/REQUIREMENTS.md Functional and non-functional requirements, and what is still open
docs/PROTOCOL.md The message contract — every AppMessage key, both directions, and the update-rate policy
docs/TEAM.md Who works on the project, what each persona owns, when to call which
docs/PROCESS.md How work flows: the two decoupled CI lanes, release gates, execution order
docs/TESTING.md The test strategy: every NFR classified, the 15 release gates, coverage policy
docs/TESTING-PATTERNS.md How to write tests the PedalPebble way: patterns, fixtures, edge cases, and examples
docs/PERFORMANCE.md Battery and performance budgets, measurement tools, optimization strategies, common pitfalls
docs/READINESS.md The 2026-09-03 readiness review: what was verified before the first commit
docs/DEV.md Local setup: installing the Pebble toolchain, building and running on the emulators
docs/DEV-SETUP.md IDE setup (Android Studio, VS Code, IntelliJ), build system, testing, debugging, git workflow, and external resources
docs/TROUBLESHOOTING.md Solutions for common problems: build failures, test issues, emulator problems, performance debugging
docs/CI.md The four workflow files: what each lane actually runs, the pinned toolchain images, and what's still a manual step for Robert
docs/CONTRIBUTING.md How to understand the codebase and add features: code organization, testing patterns, and a walk-through example
docs/CHECKLISTS.md Practical checklists for feature development, bug fixes, code review, releases, and troubleshooting
docs/SECURITY.md Secrets management, input validation, permissions, privacy, and secure transport (PebbleKit 2 config)
companion/README.md The Android Gradle project: module layout, building, and Gradle-for-.NET-developers notes

docs/archive/PLAN.md is the original 2026-08-31 plan. It is kept for the reasoning, not for the content: its architecture, message contract and Spike C definition are all overtaken, and its issue table stops at #47 of 70. Start with DECISIONS.md instead.

Planning routes

Any GPX works, but where you plan the route decides how good the turn instructions are.

Planner Turn cues in its GPX? What PedalPebble does
bikerouter.de Yes — enable turn instructions on export Reads them directly. Exact, offline, nothing else needed. Recommended
cycle.travel, RideWithGPS, Garmin Usually Reads them directly
komoot No — geometry only Derives cues at import, via BRouter if installed, otherwise a geometric guess

bikerouter.de is BRouter's own web front end, so its exported cues are the same quality as an on-device BRouter enrichment — without installing BRouter or downloading segment files. When a geometry-only file arrives, the import says so and names a planner that would not have. See D40.

Issue tracker

All work is tracked as issues in this repository:

https://git.butzei.de/robert/PedalPebble/issues

73 issues across 8 milestones, one milestone per phase. Issues carry blocked-by dependencies, so the issue list shows what is actually startable. The graph — 91 edges, entered 2026-09-03 from the bodies of all 73 issues — is re-derivable from docs/DECISIONS.md (D57) if the tracker is ever rebuilt. Its finding: the true roots are #14, #2 and #24, not the two labelled blockers; six issues (#1, #2, #6, #14, #23, #48) are startable today.

Milestone Issues What it delivers
Bootstrap 2 Docs and MIT licence on main, repo pushable
Phase 0 — Toolchain & spikes 8 SDK working; CI; the three spikes that de-risk everything else
Phase 1 — Ride view 11 Watch-only build on emery: page system, speed, heart rate, ride timer
Phase 1b — Generalise the display 2 HERO1, GRID6, German, and the round Pebble Round 2
Phase 2 — Companion & speed 16 Android app: background GPS, speed/cadence/power sensors, GPX recording
Phase 3 — Navigation 23 Turn-by-turn from an imported GPX
Phase 4 — Map view 4 Vector map on the watch
Phase 5 — Polish 7 Settings, laps, export, distribution, re-routing

Phase 1 deliberately stops at emery with two templates, so the first rideable build lands before the display work is generalised — see D32.

Labels are area:* (watchapp, companion, shared, tooling, docs), kind:* (feature, spike, chore, test) and blocker.

The tracker reflects the 2026-09-02 review (D37–D48). Twenty-three issues carry a dated Update — 2026-09-02 section recording what changed and why, in the same style as the two earlier review rounds; three issues are new (#71 voice announcements, #72 route-source guidance, #73 the deferred re-route splice).

Start here

Two issues are labelled blocker, and between them they gate most of the project.

#4 — Spike A: PebbleKit Android round-trip decides the transport, and almost all of Phases 2–4 depends on it. It tries PebbleKit Android 2 first — a maintained Kotlin library that replaces the 2016 bridge's broadcast intents with bound services — and 4.0.1 second. The most likely failure of either is Android 11+ package visibility, not the bridge, so the spike must rule that out before reporting anything broken.

It also has to verify the fallback, which was as unverified as the thing it backs up, and measure what 1 Hz of link traffic costs the watch battery — the one number that could invalidate the whole architecture. See D37, D38 and D36.

#6 — Spike C: BRouter AIDL enrichment decides the komoot path. BRouter is a router, not a map-matcher: it computes its own route between the via points, which can diverge from the route you imported. Voice hints coming back is not a pass — the spike has to measure geometric fidelity, per leg rather than per route. See D25 and D41.

Its stakes are lower than they were. A route planned on bikerouter.de already carries cues (D40), and off-route guidance is a bearing arrow rather than a mid-ride re-route (D42), so BRouter is no longer on the mid-ride critical path at all.

Repository layout (partly built, mostly planned)

watchapp/    Pebble C project, targets emery and gabbro — scaffolded, see docs/DEV.md
companion/   Android app, Kotlin — scaffolded ([#14](https://git.butzei.de/robert/PedalPebble/issues/14)), see companion/README.md
shared/      message_keys.json — the AppMessage contract, generated into both sides
tools/       gpx_replay.py and other dev utilities
docs/        this documentation

Licence

MIT — see LICENSE.

Routing and turn instructions are derived from OpenStreetMap data via BRouter and, when the rider opts in, online map-matching services. OpenStreetMap data is © OpenStreetMap contributors, available under the Open Database Licence.