120 lines
3.4 KiB
Markdown
120 lines
3.4 KiB
Markdown
# 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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
sudo modprobe -r usb_serial_simple
|
|
sudo udevadm control --reload-rules
|
|
sudo udevadm trigger
|
|
```
|
|
|
|
Verify the dongle is no longer claimed by `usbserial`:
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
make build
|
|
```
|
|
|
|
The binary is built to `bin/bridge`.
|
|
|
|
## Usage
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
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.
|