Prefix log output with 'ant:', 'bt:', or 'usb:' to distinguish between ANT+, Bluetooth LE, and USB device messages. |
||
|---|---|---|
| cmd/bridge | ||
| .gitignore | ||
| bridge | ||
| go.mod | ||
| go.sum | ||
| LICENSE | ||
| Makefile | ||
| README.md | ||
ANT+ to Bluetooth LE Bridge
Bridge an ANT+ cycling power trainer over Bluetooth Low Energy, allowing modern devices that don't support ANT+ to receive power and cadence data.
Quick Start
- Set up the USB dongle — Follow the Setup instructions to prevent the
usbserialdriver from claiming it - Build:
make build - Run (requires root):
sudo ./bin/bridge - Connect — On your computer or phone, scan for BLE devices and connect to
LinuxAntBtBridge.
That's it. Your trainer's power and cadence data should now be available over BLE.
Why this exists
Modern training apps and devices (phone apps, many power meter displays) support Bluetooth LE but lack ANT+ radios. Previously, hardware-based Bluetooth-to-ANT+ bridges were available for this purpose, but these have now been discontinued. This project provides a simple, software-based alternative using a standard USB ANT+ dongle. This is useful if the hardware device breaks and cannot be replaced when the trainer is still functioning perfectly.
This bridge listens to ANT+ data from a trainer and re-broadcasts it as a standard Cycling Power Profile service over BLE.
How it works
- Opens a USB ANT+ dongle and listens for broadcast messages from a specific trainer device number.
- Parses power (Watts) and cadence (RPM) from the trainer's ANT+ data.
- Exposes a standard Cycling Power Profile BLE service via the system's Bluetooth adapter, updating values as new ANT+ messages arrive.
Requirements
Hardware
- A Bluetooth adapter (built-in or USB)
- An ANT+ USB dongle (tested: ANT USBStick2, vendor
0x0fcf, product0x1008) - An ANT+ cycling power trainer
Software
- Linux: tested on Debian 13.
- BlueZ 5.50+ (for Bluetooth management)
- D-Bus (for BlueZ communication)
hciconfig(usually part of thebluez-utilsorbluez-toolspackage)
Note: This program must be run as root to access the USB dongle.
Tested hardware
- USB dongle: ANT USBStick2 (Dynastream Innovations, vendor
0x0fcf, product0x1008)
Setup
The Linux usbserial driver must be prevented from claiming the ANT+ dongle.
Find your dongle's USB IDs
If you're not using the tested dongle, find your dongle's vendor and product IDs:
lsusb
Look for a line with "ANT" in the description. Note the vendor ID (e.g., 0fcf) and product ID (e.g., 1008).
Create the udev rule
Create the following udev rule to prevent usbserial from claiming the dongle:
sudo tee /etc/udev/rules.d/99-ant-usb.rules > /dev/null <<EOF
SUBSYSTEM=="usb", ATTRS{idVendor}=="0fcf", ATTRS{idProduct}=="1008", ENV{MODALIAS}="ignore"
EOF
Replace 0fcf and 1008 with your dongle's actual vendor and product IDs if different.
Reload the rules
sudo modprobe -r usb_serial_simple
sudo udevadm control --reload-rules
sudo udevadm trigger
Verify
Reconnect the dongle and check dmesg:
dmesg | tail -5
Expected output (no usbserial messages):
usb 3-1.2.1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 3-1.2.1: Product: ANT USBStick2
usb 3-1.2.1: Manufacturer: Dynastream Innovations
If you see a line like usb_serial converter now attached to ttyUSB0, the udev rule did not apply.
Installation
make build
The binary is built to bin/bridge.
Usage
# Use defaults (device 3001)
sudo ./bin/bridge
# Custom trainer device
sudo ./bin/bridge --device 0xbb9
# Custom vendor/product IDs
sudo ./bin/bridge --vendor 0x0fcf --product 0x1008 --device 3001
CLI Flags
| Flag | Default | Description |
|---|---|---|
--vendor |
0x0fcf |
USB vendor ID (hex or decimal, e.g. 0x0fcf or 4047) |
--product |
0x1008 |
USB product ID (hex or decimal) |
--device |
3001 |
ANT+ device number (hex or decimal, e.g. 3001 or 0xbb9) |
--help |
Show help | |
--version |
Show version info |
Finding your trainer's ANT+ device number
Most ANT+ cycling power trainers use device number 3001 (decimal) or 0xbb9 (hex). If that works, you can use the
bridge with default settings.
If you're unsure of your trainer's device number, you can discover it using another ANT+ device (e.g., a Garmin Edge head unit). Connect the Garmin to your trainer and look for the device number in the ANT+ sensor list.
You can also try common device numbers for your trainer brand — most manufacturers use predictable numbers for their devices.
Connecting
The bridge exposes a standard Cycling Power Profile service over BLE. Any app that supports this profile will work — no custom app required.
Tested with:
- Zwift
May also work with other Cycling Power Profile apps:
- TrainingPeaks
- Wahoo SYSTM
- TrainerRoad
- Rouvy
- Kinomap
- GoldenCheetah
Steps to connect
- Run the bridge:
sudo ./bin/bridge - On your computer or phone, scan for BLE devices
- Connect to the device named
LinuxAntBtBridge - Start training in your app
Your trainer's power and cadence data should now be available in the app.
Output
2026-05-26 11:00:34 ANT Bridge abc1234 built 2026-05-26T11:00:00
2026-05-26 11:00:34 vendor: 0x0fcf/4047
2026-05-26 11:00:34 product: 0x1008/4104
2026-05-26 11:00:34 device: 0xbb9/3001
2026-05-26 11:00:34 BLE advertising...
2026-05-26 11:00:34 bt: watts: 150 rpm: 80 completedRevs: 1234 lastRevTime: 4890
The bridge logs a lot of output during normal operation — this is expected and helpful for debugging during this early stage of development.
Key log lines:
ANT Bridge ...— Startup message with version and build timevendor: .../product: .../device: ...— Configuration being usedBLE advertising...— BLE service is ready and visible to other devicesbt: watts: ...— Power and cadence data being broadcasthciconfig ... failed— Bluetooth adapter reset warnings (usually harmless)
Development
make build # Build with ldflags (version, build time)
make clean # Remove build artifacts
Known issues
- Verbose logging: The bridge produces a lot of log output during normal operation. This is expected and helpful for debugging during this early stage of development.
- Wattage drops: The wattage sometimes drops briefly to 0 but then quickly recovers. If this happens frequently, please report it with your log output.
Troubleshooting
No BLE devices found
- Check that the Bluetooth adapter is enabled:
rfkill list bluetooth - Check that the bridge is advertising: look for
BLE advertising...in the log output - Make sure no other app is using the Bluetooth adapter
ANT+ dongle not found
- Check that the dongle is plugged in:
lsusb | grep 0fcf - Check that the
usbserialdriver is not claiming the dongle:lsmod | grep usb_serial_simple - Verify the udev rule was applied (see Setup)
- Make sure you're running with
sudo
No data from trainer
- Make sure the trainer is turned on and broadcasting
- Use another device (e.g. Garmin Edge) to verify it is broadcasting. This also provides a way to get the device id.
- Make sure the dongle is close enough to the trainer (within 1-2 meters)
- Verify the device number is correct (try
--device 3001) - Check the log output for the
listening...message - Try a different device number if available
BLE connection drops
- Make sure the bridge is within range of the receiving device (within 5-10 meters)
- Check for Bluetooth interference (other BLE devices, Wi-Fi, etc.)
- Check the log output for
failed to write power characteristicmessages