# 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 1. **Set up the USB dongle** — Follow the [Setup instructions](#setup) to prevent the `usbserial` driver from claiming it 2. **Build:** ```bash make build ``` 3. **Run** (requires root): ```bash sudo ./bin/bridge ``` 4. **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 1. Opens a USB ANT+ dongle and listens for broadcast messages from a specific trainer device number. 2. Parses power (Watts) and cadence (RPM) from the trainer's ANT+ data. 3. 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`, product `0x1008`) - 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 the `bluez-utils` or `bluez-tools` package) **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. ### Find your dongle's USB IDs If you're not using the tested dongle, find your dongle's vendor and product IDs: ```bash 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: ```bash sudo tee /etc/udev/rules.d/99-ant-usb.rules > /dev/null <: power: ...`. Use `--device ` to filter for a specific trainer. 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](https://bluetooth.com/specifications/specs/cycling-power-service-1-0/) 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 1. Run the bridge: `sudo ./bin/bridge` 2. On your computer or phone, scan for BLE devices 3. Connect to the device named `LinuxAntBtBridge` 4. 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 usb: vendor: 0x0fcf/4047 2026-05-26 11:00:34 usb: product: 0x1008/4104 2026-05-26 11:00:34 ant: device: any 2026-05-26 11:00:34 ant: device opened 2026-05-26 11:00:34 bt: BLE advertising... 2026-05-26 11:00:34 ant: scan mode started 2026-05-26 11:00:34 ant: listening... 2026-05-26 11:00:35 ant: 3001: power: 150W cadence: 80 rpm ``` 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 time - `usb: vendor: ...` / `usb: product: ...` — USB dongle configuration - `ant: device: ...` — ANT+ device filter (or `any` if listening to all devices) - `ant: device opened` — USB dongle opened successfully - `bt: BLE advertising...` — BLE service is ready and visible to other devices - `ant: scan mode started` / `ant: listening...` — ANT+ receiver is active - `ant: : power: ...` — Power/cadence data with transmitting device ID - `bt: watts: ...` — Power/cadence data being broadcast over BLE - `ant: received msg from ignored device ...` — Message from non-matching device (when `--device` is specified) - `hciconfig ... failed` — Bluetooth adapter reset warnings (usually harmless) ## Development ```bash 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 `usbserial` driver is not claiming the dongle: `lsmod | grep usb_serial_simple` - Verify the udev rule was applied (see [Setup](#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. - The bridge listens to all devices by default. If multiple trainers are broadcasting, use `--device ` to filter for a specific one - Make sure the dongle is close enough to the trainer (within 1-2 meters) - Check the log output for the `listening...` message ### 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 characteristic` messages