feat: make --device flag optional with 'any' default

When --device is omitted or set to 0, the bridge listens to all
broadcasting ANT+ trainers instead of filtering by a specific device.
The actual transmitting device ID is shown in data logs, allowing
users to discover and then filter specific trainers.

Also fix vendorID/productID not being assigned to config struct
which caused ListenForTrainer to receive 0 for both values.
This commit is contained in:
Erik Brakkee 2026-05-26 23:06:05 +00:00
parent 19e4e78c75
commit 7f52f0ff68
4 changed files with 43 additions and 28 deletions

View File

@ -119,13 +119,13 @@ The binary is built to `bin/bridge`.
## Usage ## Usage
```bash ```bash
# Use defaults (device 3001) # Listen to all trainers (default)
sudo ./bin/bridge sudo ./bin/bridge
# Custom trainer device # Filter for a specific trainer
sudo ./bin/bridge --device 0xbb9 sudo ./bin/bridge --device 0xbb9
# Custom vendor/product IDs # Custom vendor/product IDs with specific device
sudo ./bin/bridge --vendor 0x0fcf --product 0x1008 --device 3001 sudo ./bin/bridge --vendor 0x0fcf --product 0x1008 --device 3001
``` ```
@ -135,14 +135,14 @@ sudo ./bin/bridge --vendor 0x0fcf --product 0x1008 --device 3001
|------|---------|-------------| |------|---------|-------------|
| `--vendor` | `0x0fcf` | USB vendor ID (hex or decimal, e.g. `0x0fcf` or `4047`) | | `--vendor` | `0x0fcf` | USB vendor ID (hex or decimal, e.g. `0x0fcf` or `4047`) |
| `--product` | `0x1008` | USB product ID (hex or decimal) | | `--product` | `0x1008` | USB product ID (hex or decimal) |
| `--device` | `3001` | ANT+ device number (hex or decimal, e.g. `3001` or `0xbb9`) | | `--device` | `0 (any)` | ANT+ device number (hex or decimal). Use 0 or omit to listen to all devices |
| `--help` | | Show help | | `--help` | | Show help |
| `--version` | | Show version info | | `--version` | | Show version info |
## Finding your trainer's ANT+ device number ## 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 The bridge listens to all broadcasting devices by default. When multiple ANT+ trainers are nearby, each will appear in the
bridge with default settings. log output as `ant: <device_id>: power: ...`. Use `--device <id>` 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 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. head unit). Connect the Garmin to your trainer and look for the device number in the ANT+ sensor list.
@ -179,11 +179,14 @@ Your trainer's power and cadence data should now be available in the app.
``` ```
2026-05-26 11:00:34 ANT Bridge abc1234 built 2026-05-26T11:00:00 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 usb: vendor: 0x0fcf/4047
2026-05-26 11:00:34 product: 0x1008/4104 2026-05-26 11:00:34 usb: product: 0x1008/4104
2026-05-26 11:00:34 device: 0xbb9/3001 2026-05-26 11:00:34 ant: device: any
2026-05-26 11:00:34 BLE advertising... 2026-05-26 11:00:34 ant: device opened
2026-05-26 11:00:34 bt: watts: 150 rpm: 80 completedRevs: 1234 lastRevTime: 4890 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 The bridge logs a lot of output during normal operation — this is expected and helpful for debugging during this early
@ -191,9 +194,14 @@ stage of development.
Key log lines: Key log lines:
- `ANT Bridge ...` — Startup message with version and build time - `ANT Bridge ...` — Startup message with version and build time
- `vendor: ...` / `product: ...` / `device: ...` — Configuration being used - `usb: vendor: ...` / `usb: product: ...` — USB dongle configuration
- `BLE advertising...` — BLE service is ready and visible to other devices - `ant: device: ...` — ANT+ device filter (or `any` if listening to all devices)
- `bt: watts: ...` — Power and cadence data being broadcast - `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: <id>: 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) - `hciconfig ... failed` — Bluetooth adapter reset warnings (usually harmless)
## Development ## Development
@ -230,10 +238,10 @@ make clean # Remove build artifacts
- Make sure the trainer is turned on and broadcasting - 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 - Use another device (e.g. Garmin Edge) to verify it is broadcasting. This also provides a way
to get the device id. to get the device id.
- The bridge listens to all devices by default. If multiple trainers are broadcasting, use
`--device <id>` to filter for a specific one
- Make sure the dongle is close enough to the trainer (within 1-2 meters) - 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 - Check the log output for the `listening...` message
- Try a different device number if available
### BLE connection drops ### BLE connection drops

BIN
bridge

Binary file not shown.

View File

@ -56,8 +56,8 @@ func ListenForTrainer(vendorId uint16, productId uint16, deviceNumber uint32,
logMsg("ant: listening...") logMsg("ant: listening...")
for msg := range msgs { for msg := range msgs {
if msg.DeviceNumber() != deviceNumber { if deviceNumber != 0 && msg.DeviceNumber() != deviceNumber {
logPrintf("Received msg from ignored ant+ device %v\n", msg.DeviceNumber()) logPrintf("ant: received msg from ignored device %v\n", msg.DeviceNumber())
continue continue
} }
//fmt.Printf("raw msg: device type=0x%02x device number=%d content=%x\n", //fmt.Printf("raw msg: device type=0x%02x device number=%d content=%x\n",

View File

@ -52,19 +52,26 @@ This allows these trainers to be used with modern devices that don't support ANT
if err != nil { if err != nil {
return fmt.Errorf("invalid --product %q: %w", c.product, err) return fmt.Errorf("invalid --product %q: %w", c.product, err)
} }
deviceNumber, err := parseHex(c.device, 32) c.vendorID = uint64(vendorID)
if err != nil { c.productID = uint64(productID)
return fmt.Errorf("invalid --device %q: %w", c.device, err) if c.device != "" {
deviceNumber, err := parseHex(c.device, 32)
if err != nil {
return fmt.Errorf("invalid --device %q: %w", c.device, err)
}
c.deviceNumber = uint32(deviceNumber)
} }
c.vendorID = vendorID deviceNumber := c.deviceNumber
c.productID = productID
c.deviceNumber = uint32(deviceNumber)
logMsgf("ANT Bridge %s built %s", Version, BuildTime) logMsgf("ANT Bridge %s built %s", Version, BuildTime)
logMsgf("usb: vendor: 0x%04x/%d", vendorID, vendorID) logMsgf("usb: vendor: 0x%04x/%d", vendorID, vendorID)
logMsgf("usb: product: 0x%04x/%d", productID, productID) logMsgf("usb: product: 0x%04x/%d", productID, productID)
logMsgf("ant: device: 0x%03x/%d", deviceNumber, deviceNumber) if deviceNumber == 0 {
logMsgf("ant: device: any")
} else {
logMsgf("ant: device: 0x%03x/%d", deviceNumber, deviceNumber)
}
if err := exec.Command("hciconfig", "hci0", "down").Run(); err != nil { if err := exec.Command("hciconfig", "hci0", "down").Run(); err != nil {
logPrintf("bt: hciconfig down failed: %v\n", err) logPrintf("bt: hciconfig down failed: %v\n", err)
@ -83,7 +90,7 @@ This allows these trainers to be used with modern devices that don't support ANT
rootCmd.Flags().String("vendor", "0x0fcf", "USB vendor ID (hex, e.g. 0x0fcf)") rootCmd.Flags().String("vendor", "0x0fcf", "USB vendor ID (hex, e.g. 0x0fcf)")
rootCmd.Flags().String("product", "0x1008", "USB product ID (hex, e.g. 0x1008)") rootCmd.Flags().String("product", "0x1008", "USB product ID (hex, e.g. 0x1008)")
rootCmd.Flags().String("device", "3001", "ANT+ device number (hex or decimal, e.g. 3001 or 0xbb9)") rootCmd.Flags().String("device", "", "ANT+ device number (hex or decimal). Use 0 or omit to listen to all devices")
if err := rootCmd.Execute(); err != nil { if err := rootCmd.Execute(); err != nil {
os.Exit(1) os.Exit(1)
} }