Skip to content

Repository files navigation

TrainerBridge BLE

Corrects the power your smart trainer (or bike) reports and makes the corrected value available to your apps and head units. It sits between the trainer and everything else, applies a linear calibration to power, and passes everything else through untouched.

It runs the same on a phone and on a Hammerhead Karoo — the difference is only in how you use it, described below.


⚠️ About the permission prompts (the app does NOT track you)

TrainerBridge needs to scan for your trainer over Bluetooth to connect to it. There is no GPS, no tracking, and no data ever leaves the device — it looks for exactly one thing, your trainer.

  • On the Karoo (Android 12) and modern phones: the app asks for the "Nearby devices" permission (Bluetooth). Android may file this under a location-related category, but it is not location — the app declares neverForLocation and holds no location permission at all.
  • On older phones (Android 11 and earlier) only: Android itself refuses to let any app scan for Bluetooth without the Location permission (a BLE scan could in theory reveal position from nearby beacons). So on those phones the prompt says "Location" — again, only to scan for the trainer.

Either prompt is safe to grant. The app requests nothing beyond Bluetooth (+ a foreground service so it keeps running with the screen off during a ride).


What it does

The app connects to your trainer over Bluetooth (as the "receiver") and can then make the corrected data available three ways:

  1. To training apps over Bluetooth (e.g. Bestcycling): it mirrors the trainer 1:1 — same name, same controls (ERG / resistance, buttons) — but reports corrected power. The app behaves exactly as if talking to the trainer directly, and records corrected watts.
  2. To a head unit over ANT+ (e.g. a Garmin): it broadcasts an ANT+ smart trainer with corrected power.
  3. To a Karoo, natively: it publishes a virtual sensor called TrainerBridge that the Karoo pairs like any other sensor and records for indoor training — no ANT, no cables, no second device.

The three controls

The Monitor screen has three independent switches — this is the key to understanding the app:

Control What it does
App active (master) The on/off of the whole app. Off = nothing runs, zero battery. Turn it on to use the app.
Trainer enabled Connect to your trainer (the "receiving" side). On by default. While on, the app is connected and the tiles show live power/cadence/speed/resistance — you do not need to press Broadcast for this.
Broadcast (the big button) Start/stop emitting to the outside: the Bluetooth mirror for training apps + the ANT+ output.

Receiving is always available (whenever App active + Trainer enabled are on). Broadcast is only for sending to external apps / ANT+. So the Karoo virtual sensor works without ever pressing Broadcast.


Using it on a Karoo (indoor training)

This is where it's most useful: indoor training on the Karoo. Indoors you have no GPS and rely on the trainer for power, speed and cadence — so recording the corrected power matters. The Karoo runs the app and records the ride from it, all on the one device, with no ANT dongle.

  1. Install the app and open it. Turn App active on. Make sure Trainer enabled is on.
  2. The app connects to your trainer; the Monitor tiles show corrected power/cadence/speed.
  3. On the Karoo, go to Sensors → Add sensor and pair "TrainerBridge". The Karoo now records the corrected power, cadence and speed for your indoor ride.
  4. That's it — you don't need to press Broadcast. Turn App active off when you're done so it stops consuming battery.

The Karoo shows speed in km/h or mph according to your profile automatically.

Note: Karoo extensions auto-start, so the app is always loaded on the Karoo — the App active switch is how you make sure it isn't consuming anything when you're not using it.


Using it on a phone

The phone acts as the bridge between the trainer and your training app (and, optionally, a Garmin).

  1. Install and open the app. Turn App active on; keep Trainer enabled on — it connects to the trainer and the tiles show corrected power.
  2. Press Broadcast. The phone advertises the mirrored trainer over Bluetooth while it is connected to your trainer — if the trainer sleeps, the mirror goes off the air until it wakes (otherwise two devices with the same name would be advertising and your app could bind to the trainer directly). In your training app (e.g. Bestcycling) pair the trainer as usual — it works exactly as before, but records corrected power, and you can control it (ERG / resistance) normally.
  3. For a Garmin over ANT+ (optional): plug in an ANT USB dongle (with the ANT Radio Service installed), enable ANT+ output in Config, and pair the trainer on the Garmin. Give the phone and a Karoo different ANT+ ids (in Config) if you run both, so they don't collide.
  4. Keep the phone exempt from battery optimisation (the app asks once) so it keeps running screen-off.

Configuration

Open Configuración from the Monitor:

  • Correctioncorrected = raw × (1 + scale%/100) + offset. Enter the scale (%) and offset (W) from your calibration.
  • ERG floor (W, 0 = off) — a hardware floor, not a correction fix: below this target the trainer can no longer hold the commanded resistance and ERG stops tracking, so the command is held at the floor's own raw target. The trade-off is explicit — every ERG target below the floor is ridden at the floor, so with the default 50 W a 40 W recovery interval is ridden at 50 W. Set it to 0 if your trainer holds low targets properly. Targets within the offset (≈ a stop) still command 0.
  • Trainer (BLE) — scan and pick your trainer to pair it. The scan lists only power sources (FTMS or Cycling Power) — heart-rate straps, phones and headphones are filtered out; if that filter finds nothing in the first few seconds it retries unfiltered, so a trainer that advertises its services unusually still shows up. A bare power meter can be paired too: its power is corrected and mirrored as usual, but ERG control needs a trainer (FTMS). With nothing paired, the bridge auto-connects to the first FTMS trainer it finds — pair yours explicitly if there may be another trainer in range. A trainer the bridge is already connected to can never appear in a scan (a connected BLE device stops advertising), so the screen offers it directly as Pair the trainer in use.
  • Saving applies immediately. Changing the paired trainer, simulation, the advertised name or the ANT+ settings re-derives the running bridge, which can briefly drop the apps connected to it — so avoid saving config mid-ride. The correction values (scale, offset, ERG floor) apply live with no interruption.
  • Advertised name — the name apps see in their device list. Leave it empty (the default) and the bridge advertises under the device's own Bluetooth name, which is the simplest thing and keeps it easy to tell apart from the trainer itself. The name is cosmetic: it does not affect what an app can do with the trainer (a captured session advertised under a different name and still completed the full FTMS control handshake). Only if you set a custom name does the bridge rename the device's Bluetooth adapter, because Android has no per-advertisement name — and then anything else the device advertises carries that name too, until it is restored on stop.
  • Options — save diagnostic log (CSV), simulation mode (a fake trainer for testing with no hardware), ANT+ output + its device id.

Notes & limitations

  • Simulation mode feeds a synthetic trainer through the whole pipeline (UI, correction, mirror, ANT+, virtual sensor) with no hardware — useful for testing. Two things behave differently from a real trainer:
    • The resistance arrows change the reported level, not the power. The synthetic trainer has no rider, so its power follows its own curve (or the app's ERG target) and ignores resistance entirely. On a real trainer, more resistance changes the rider's effort and the power follows; in simulation nothing downstream moves. The level itself is reported normally (FTMS Machine Status + Indoor Bike Data).
    • ERG does work: an app that writes Set Target Power drives the simulated power to that target.
  • A Garmin watch over Bluetooth: watches discover sensors by service UUID (which the mirror advertises), but Android can't set the advertising Appearance and uses a rotating random address — either can stop a picky watch from listing the Bluetooth mirror. The reliable path to a Garmin is the ANT+ output; on a Karoo, the native virtual sensor.
  • The UI is bilingual (English / Spanish), following the device language.

About

Transparent BLE proxy for a smart trainer (or indoor bike): corrects power and re-broadcasts it to training apps (BLE), head units (ANT+), and the Karoo (native virtual sensor). Runs on phone and Karoo; especially useful for indoor training on the Karoo.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages