My Rower Doesn't Speak Garmin
BLE, ANT+, Connect IQ, and an engineer's stubbornness
I row. Not on water — on a Sportstech WRX1000 Waterrower. A solid machine with one problem: it speaks Bluetooth Low Energy. My Garmin Epix 2 Pro speaks ANT+. They don't talk to each other. And without Garmin pairing, there are no Training Metrics. No Training Effect. No VO2max update. No Training Load. Nothing.
Why imported activities aren't enough
Sure, you can import an activity as a FIT file. But Garmin Connect ignores imported data for everything that matters. The Firstbeat algorithms run on-device — on the watch itself. If the watch doesn't see heart rate live during the activity, there's no calculation. No Body Battery drain, no Intensity Minutes, no Recovery Time.
For someone who manages training by data, that's a dealbreaker. I want to see after rowing whether the session had Aerobic or Anaerobic Training Effect. I want Training Load to flow into my weekly overview. Without that, rowing is invisible to Garmin — as if I'd done nothing.
The bridge: BLE in, ANT+ out
The solution: a bridge. Software that receives BLE FTMS data from the WRX1000 and forwards it as ANT+ FE-C to the Garmin watch. So the watch "thinks" it's connected to a real fitness device. Hardware cost: an ANT+ USB dongle for 35 euros and a USB-OTG adapter for 10 euros. Runs on an Android phone in Chrome.
WRX1000 sends via BLE to the bridge. The bridge translates to ANT+ FE-C. The Garmin watch receives ANT+ and starts Indoor Rowing. Heart rate runs in parallel via chest strap. And suddenly: Training Effect. VO2max. Everything.
The Garmin app: WRX1000-IQ
But that wasn't enough for me. The standard Garmin display for Indoor Rowing is generic. So I wrote a Connect IQ Data Field — WRX1000-IQ. Monkey C, Garmin's own programming language. Zone-based pace display with color coding, four core metrics: pace, power, stroke rate, distance. AMOLED-optimized for black background and battery life.

The challenge with Connect IQ: every API call can crash. Bluetooth connections drop. Fields disappear. The Garmin watch then shows a blue square — the universal sign for "your code is broken." My solution: every API call in try-catch, null checks everywhere, minimal changes with tag-and-rollback workflow.
What an engineer does
Would it have been easier to buy a rower with native Garmin support? Of course. But the WRX1000 is a water rower — the rowing feel is unbeatable. And I'm a mechanical engineer. When a device doesn't do what I want, I build the interface myself.
The result: full Garmin integration for a device the manufacturer never intended for it. Training Metrics that were previously invisible. And a deploy script that pushes directly to the watch via MTP. Because even the last bit of friction is too much.
— Philipp