OpenBikeControl Protocol Specification
Overview
OpenBikeControl is an open protocol for wireless input devices to control cycling trainer applications. It enables standardized communication between BLE controllers, apps, and the training app itself.
Motivation
Many cycling trainer apps support various actions that traditionally require:
- On-screen button clicks
- Keyboard input
- Proprietary BLE controllers
OpenBikeControl provides a unified, open protocol that:
- Easy to implement - Simple data format with minimal overhead
- Open standard - No licensing fees or proprietary restrictions
- Dual connectivity - Supports both BLE and network-based connections
- Already partially adopted - Similar technology as the existing "Direct Connect" implementations
- Apple-friendly - Does not rely on manufacturer data fields that cannot be emulated on iOS
Supported Actions
OpenBikeControl enables the following trainer app actions:
- Virtual gear shifting - Up/down shifting for smart trainer devices
- Navigation - Menu navigation, route selection, steering controls
- UI controls - Select, back, confirm buttons
- Social features - Emotes (wave, thumbs up, ride on, etc.)
- Training controls - ERG mode adjustments, workout skips
- Custom actions - App-specific features
Protocol Architecture
OpenBikeControl uses two transport mechanisms:
- BLE (Bluetooth Low Energy) - For direct device-to-app connections, or as a fallback for apps if mDNS is not possible
- mDNS (Multicast DNS) - For network-based connections ("Direct Connect")
Both transports use the identical binary message format (including the message type prefix byte), ensuring consistency across connection types.
Quick Reference
BLE Protocol:
- Service UUID:
d273f680-d548-419d-b9d1-fa0472345229 - Button State Characteristic (Read/Notify):
d273f681-d548-419d-b9d1-fa0472345229 - Haptic Feedback Characteristic (Write):
d273f682-d548-419d-b9d1-fa0472345229 - App Information Characteristic (Write):
d273f683-d548-419d-b9d1-fa0472345229 - Message types:
0x01(button state),0x03(haptic feedback),0x04(app info) - See BLE.md for complete specification
mDNS Protocol:
- Service Type:
_openbikecontrol._tcp.local. - TCP endpoint:
<device-ip>:<port> - Binary data format (identical to BLE)
- Message types:
0x01(button state),0x02(device status),0x03(haptic feedback),0x04(app info) - See MDNS.md for complete specification
Button Mapping
Standard Button IDs
OpenBikeControl defines standard button IDs for common actions. Device manufacturers should map their physical buttons to these standard IDs.
Gear Shifting (0x01-0x0F)
| Button ID | Action | Description |
|---|---|---|
0x01 | Shift Up | Increase virtual gear |
0x02 | Shift Down | Decrease virtual gear |
0x03 | Gear Set | Direct gear selection, flat index (use analog value) |
0x04 | Chainring Set | Direct front chainring selection (use analog value) |
0x05 | Cassette Set | Direct rear cassette selection (use analog value) |
Gear Selection Analog Values (0x03, 0x04, 0x05):
The analog value encodes a direct, 1-based gear position, offset by +1 to avoid
colliding with the standard released/pressed values 0x00 and 0x01:
0x00= Released / no change0x01= Not used for gear selection; receivers MUST treat it as a no-op (same as0x00)0x02-0xFF= Gear position + 1 (0x02= gear 1,0x03= gear 2, ..., up to 254 positions)
The value is a direct index, not a percentage. Apps MUST NOT scale it and SHOULD clamp values outside their supported gear range to the nearest valid gear.
Flat vs. front/rear gearing:
0x03 addresses gears as a single linear sequence (1..N), which is how most trainer
apps model virtual shifting. Devices emulating a front/rear (N×M) drivetrain SHOULD
use 0x04 (chainring) and 0x05 (cassette), and MAY additionally include a flattened
0x03 index in the same message for apps that only support the flat model (see
Multiple Actions Per Button). How an N×M drivetrain
flattens into a linear index (e.g. by concatenation, or ordered by effective gear
ratio) is the device's choice. Use the App Information message to determine which
button IDs the connected app supports.
Navigation (0x10-0x1F)
| Button ID | Action | Description |
|---|---|---|
0x10 | Up | Navigate up in menus |
0x11 | Down | Navigate down in menus |
0x12 | Left | Navigate left / Look left |
0x13 | Right | Navigate right / Look right |
0x14 | Select/Confirm | Confirm selection |
0x15 | Back/Cancel | Go back / Cancel |
0x16 | Menu | Open menu |
0x17 | Home | Return to home screen |
0x18 | Steer Left | Steer left in-game |
0x19 | Steer Right | Steer right in-game |
0x1A | Brake | Apply brake (use analog value for strength) |
0x1B | Steering Angle | Proportional steering (use analog value for angle) |
Brake Analog Values:
0x00= Released / no braking0x01= Full braking (digital button press, equivalent to 100%)0x02-0xC9= Braking strength in percent: value − 1 (0x02= 1%,0x65= 100%,0xC9= 200%)0xCA-0xFF= Reserved; apps SHOULD treat these as 200%
Braking is a single axis with a single button ID. 100% represents full application of one brake; devices with two brake levers MAY report a combined strength of up to 200%. Apps that do not model braking beyond a single brake SHOULD clamp values above 100%.
Steering Angle Analog Values:
0x1B reports the calibrated handlebar angle relative to straight ahead, so apps
can steer proportionally instead of only reacting to Steer Left / Steer Right.
0x00= No angle available (not calibrated, recalibrating, or sensor lost); apps SHOULD fall back to their own steering behavior0x01= Not used for steering angle; receivers MUST treat it as a no-op0x02-0xFE= Signed angle in 0.5° steps: (value −0x80) × 0.5°0x80= 0° (straight ahead)0x81-0xFE= Steering right,0x81= +0.5°,0xFE= +63°0x02-0x7F= Steering left,0x7F= −0.5°,0x02= −63°
0xFF= Reserved; receivers MUST treat it as a no-op
Positive angles steer right, negative angles steer left. Devices MUST clamp angles
outside ±63° to 0x02 / 0xFE. Apps SHOULD map the angle to their own steering
range and MAY apply their own dead zone and sensitivity.
The angle is the device's calibrated angle, before any dead zone or button
thresholding. Calibration (finding straight ahead) is the device's responsibility;
uncalibrated sensor values MUST NOT be sent on 0x1B.
Update behavior:
- Send a new value whenever the encoded value changes, but no more often than 30 times per second per device. When the angle settles, the last value MUST be sent so the app does not stay at a stale intermediate angle.
- When the handlebar returns to center, send
0x80. - When the angle becomes unavailable (e.g. recalibration or sensor loss), send
0x00. On disconnect, apps MUST treat the angle as unavailable.
Combining with Steer Left / Steer Right:
Devices MAY send 0x1B together with 0x18/0x19 in the same message (see
Multiple Actions Per Button), so apps without
proportional steering keep working. Apps that list 0x1B in their App Information
message signal that they steer from the angle; devices MAY then stop sending
0x18/0x19 for the same steering input. Apps that receive both SHOULD use 0x1B
and ignore 0x18/0x19 from that device while the angle is available.
Example:
// Handlebar turned 10° right
[0x01, 0x1B, 0x94]
// 4.5° left
[0x01, 0x1B, 0x77]
// Back to center
[0x01, 0x1B, 0x80]
Social/Emotes (0x20-0x2F)
| Button ID | Action | Description |
|---|---|---|
0x20 | Emote | Send social emote (use analog value to specify emote type) |
0x21 | Push to Talk | Activate microphone for voice input |
0x24 | Screenshot | Take an in-game screenshot |
Emote Analog Values:
0x00= No emote / Released0x01= Pressed (cycle through emotes)0x02-0x1F= Reserved for app-specific emotes
Training Controls (0x30-0x3F)
| Button ID | Action | Description |
|---|---|---|
0x30 | Increase Difficulty | Increase workout intensity / workout difficulty / increase ERG mode power |
0x31 | Decrease Difficulty | Decrease workout intensity / workout difficulty / decrease ERG mode power |
0x32 | Skip Interval | Skip to next workout interval |
0x33 | Pause | Pause workout |
0x34 | Resume | Resume workout |
0x35 | Lap | Mark lap |
0x36 | Previous Interval | Skip to previous workout interval |
0x37 | U-Turn | Perform U-Turn |
0x38 | Change Mode | Toggle between modes, e.g. ERG and others |
0x39 | Take a break | Take a break |
0x3A | Join another rider | "Teleport" to another rider |
0x3B | Change route | Show route change selection |
0x3C | Cruise Control | Toggle cruise control (use analog value for optional target power) |
Repeated Presses (0x30/0x31):
Apps MAY scale the adjustment step with the rate of repeated presses (e.g. slow presses adjust by ±1 W, faster presses by proportionally larger steps). To make this possible, devices MUST send every physical press as its own press/release transition and MUST NOT insert artificial cooldowns between presses or coalesce rapid presses into one. (Switch debouncing per the firmware guidelines is fine — it filters contact bounce, not distinct presses.)
Cruise Control Analog Values:
0x00= Released0x01= Pressed — toggle cruise control on/off, engaging at the rider's current power0x02-0x09= Reserved; receivers MUST treat these values as a no-op0x0A-0xFF= Engage cruise control with an absolute target power of value × 5 watts (0x64= 500 W,0xFF= 1275 W)
Most devices SHOULD simply send 0x01 and let the app capture the rider's current
power as the setpoint; subsequent adjustments use 0x30/0x31 (Increase/Decrease
Difficulty). The absolute form is intended for devices with their own target-power UI.
Apps SHOULD clamp target power values to the range they support.
View Controls (0x40-0x4F)
| Button ID | Action | Description |
|---|---|---|
0x40 | Camera View | Select camera view (use analog value to specify view) |
0x44 | HUD Toggle | Show/hide HUD |
0x45 | Map Toggle | Show/hide map |
0x46 | Spectate rider | Spectate another rider |
Camera View Analog Values:
0x00= No change / Released0x01= Pressed (cycle through camera views)0x02-0x1F= Reserved for app-specific camera views
Power-ups (0x50-0x5F)
| Button ID | Action | Description |
|---|---|---|
0x50 | Power-up 1 | Activate power-up slot 1 |
0x51 | Power-up 2 | Activate power-up slot 2 |
0x52 | Power-up 3 | Activate power-up slot 3 |
Custom/Reserved (0x60-0xFF)
| Range | Purpose |
|---|---|
0x60-0x7F | Reserved for future standard actions |
0x80-0x9F | App-specific custom actions |
0xA0-0xFF | Manufacturer-specific custom actions |
Multi-Button Combinations
Apps may implement multi-button combinations by detecting multiple simultaneous button presses. For example:
- Shift Up + Shift Down simultaneously = Reset gear to neutral
- Menu + Select = Quick settings
Multiple Actions Per Button
Hardware or software (such as BikeControl) can send multiple actions per button press to maximize flexibility and compatibility across different trainer apps. This allows a single physical button to trigger multiple related actions simultaneously, with the app deciding which action to respond to based on its capabilities.
Example Use Case:
A "Plus" button on a controller could send three different actions at once:
0x01(Shift Up) - For apps that support virtual gear shifting0x30(Increase Difficulty) - For apps that support ERG mode power adjustment0x14(Select/Confirm) - For apps that use it for menu navigation
Implementation:
When a button is pressed, send a single button state message containing all relevant action IDs:
[0x01, 0x01, 0x01, 0x30, 0x01, 0x14, 0x01]
This means: Shift Up pressed (0x01, 0x01), Increase Difficulty pressed (0x30, 0x01), and Select pressed (0x14, 0x01).
Benefits:
- Compatibility: Works with any app that supports at least one of the actions
- Flexibility: Easy to remap hardware buttons through software configuration
- Discovery: Apps communicate supported actions via the App Information Characteristic, allowing devices to optimize button mappings
- User Experience: Physical buttons can have consistent behavior across different apps
Guidelines for Device Manufacturers:
- Group related actions that make sense together (e.g., shift up, increase resistance, navigate up)
- Allow users to customize which actions are sent per button
- Use the App Information Characteristic to understand which actions the app supports
- Consider providing visual feedback on the device about which actions are active
Guidelines for App Developers:
- Process only the button IDs your app supports, ignoring others
- Send the App Information Characteristic after connecting to inform devices of supported actions
- Handle multiple simultaneous button presses gracefully
Implementation Guidelines
For App Developers
-
BLE Implementation:
- Scan for devices advertising service UUID
d273f680-d548-419d-b9d1-fa0472345229 - Connect and discover the Button State characteristic (
d273f681-d548-419d-b9d1-fa0472345229) - Discover the Haptic Feedback characteristic (
d273f682-d548-419d-b9d1-fa0472345229) - Subscribe to notifications for real-time button updates
- Send haptic feedback commands for tactile feedback
- Map button IDs to app-specific actions
- See BLE.md for detailed BLE implementation
- Scan for devices advertising service UUID
-
mDNS Implementation:
- Use Bonjour/Zeroconf libraries to discover
_openbikecontrol._tcp.local.services - Connect via TCP for real-time updates
- Parse TXT records to get device information and service UUIDs
- Use same binary format as BLE for button states and commands
- See MDNS.md for detailed mDNS implementation
- Use Bonjour/Zeroconf libraries to discover
-
Button Mapping:
- Provide user configuration for custom button mappings
- Use standard button IDs as defaults
- Allow users to override mappings for their workflow
-
Multi-Device Support:
- Support connecting multiple OpenBikeControl devices simultaneously
- Allow users to assign devices to specific action categories
For Device Manufacturers
-
Hardware:
- Use reliable button switches for digital inputs
- Consider hall-effect sensors for analog inputs
- Include vibration motor for haptic feedback (optional but recommended)
- Include battery monitoring circuitry for battery level reporting
-
Firmware:
- Implement efficient button debouncing (10-50ms)
- Only send notifications on state changes
- Batch multiple button changes in one notification
- Support both BLE and mDNS for maximum compatibility
- Use same binary data format for both BLE and TCP
- Implement haptic feedback if hardware supports it
-
Power Management:
- Implement BLE sleep modes when inactive
- Wake on button press
- Report accurate battery levels
-
Testing:
- Verify range and reliability
- Ensure no interference with other BLE devices (trainers, heart rate monitors)
Certification Program
To ensure quality and compatibility, OpenBikeControl offers a voluntary certification program for device manufacturers. See CERTIFICATION.md for details.
Certified devices receive:
- Official listing in the OpenBikeControl device directory
- Compatibility badge for marketing materials
- Technical support for implementation
- Button mapping presets included in participating apps
Version History
- Version 1 (Current)
- Initial protocol specification
- BLE and mDNS transport definitions
- Standard button mappings
- Certification program launch
References
- Bluetooth SIG - GATT Services
- Apple Core Bluetooth Programming Guide
- mDNS/Bonjour Specification (RFC 6762)
License
The OpenBikeControl Protocol specification is released under the MIT License, allowing free implementation in both commercial and open-source projects.
Contact & Contributions
For questions, suggestions, or contributions, please refer to the repository documentation.
The protocol is designed to evolve with community feedback while maintaining backward compatibility.