Ant+ to bluetooth bridge
Go to file
2026-05-27 00:36:06 +02:00
.opencode refactor: remove init() and package-level rootCmd, add error logging 2026-05-27 00:36:06 +02:00
cmd/bridge refactor: replace magic hex constants with named constants 2026-05-27 00:36:06 +02:00
go.mod feat: add CLI with Cobra and timestamped logging 2026-05-27 00:36:06 +02:00
go.sum feat: add CLI with Cobra and timestamped logging 2026-05-27 00:36:06 +02:00
LICENSE Initial commit 2026-05-25 11:00:13 +02:00
Makefile removed unnecessary download. 2026-05-27 00:36:06 +02:00
out refactor: remove init() and package-level rootCmd, add error logging 2026-05-27 00:36:06 +02:00
README.md updated README 2026-05-27 00:36:06 +02:00
setup.md docs: add README with setup instructions and tested hardware 2026-05-27 00:36:06 +02:00

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.

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 bridge listens to ANT+ data from a wired trainer and re-broadcasts it as a standard Cycling Power Profile service over BLE.

How it works

  1. Opens a USB ANT+ dongle (vendor ID 0x0fcf) and listens for broadcast messages from a specific trainer device number.
  2. Parses power (Watts) and cadence (RPM) from the trainer's ANT+ data pages.
  3. Exposes a Cycling Power Measurement BLE service via the system's Bluetooth adapter, updating values as new ANT+ messages arrive.

Requirements

  • Linux
  • D-Bus (for BlueZ Bluetooth management)
  • A Bluetooth adapter
  • An ANT+ USB dongle
  • An ANT+ cycling power trainer

Note: This program must be run as root to access the USB dongle.

Tested hardware

  • USB dongle: ANT USBStick2 (Dynastream Innovations, vendor 0x0fcf, product 0x1008)

Setup

The Linux usbserial driver must be prevented from claiming the ANT+ dongle. Create the following udev rule:

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

The vendor id and product id above can be obtained from the dmesg output after inserting the USB dongle.

Then reload the rules and reconnect the dongle:

sudo modprobe -r usb_serial_simple
sudo udevadm control --reload-rules
sudo udevadm trigger

Verify the dongle is no longer claimed by usbserial:

dmesg | tail -5

Expected output:

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

Installation

make build

The binary is built to bin/bridge.

Usage

# Use defaults (device 3001)
./bin/bridge

# Custom trainer device
./bin/bridge --device 0xbb9

# Custom vendor/product IDs
./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

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 processingTime: 250us

Development

make build    # Build with ldflags (version, build time)
make clean    # Remove build artifacts

Known issues

It has been observed that during use the wattage sometimes drops briefly to 0 but then quickly recovers. Logging will hopefully pinpoint the issue should it occur again.