Now built into the Stages SB200, the first hardware with OpenBikeControl in its firmware.Announcement

On this page
  1. Overview
  2. Motivation
  3. Supported Actions
  4. Protocol Architecture
  5. Quick Reference
  6. Button Mapping
  7. Standard Button IDs
  8. Multi-Button Combinations
  9. Multiple Actions Per Button
  10. Implementation Guidelines
  11. For App Developers
  12. For Device Manufacturers
  13. Certification Program
  14. Version History
  15. References
  16. License
  17. Contact & Contributions

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:

  1. BLE (Bluetooth Low Energy) - For direct device-to-app connections, or as a fallback for apps if mDNS is not possible
  2. 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 IDActionDescription
0x01Shift UpIncrease virtual gear
0x02Shift DownDecrease virtual gear
0x03Gear SetDirect gear selection, flat index (use analog value)
0x04Chainring SetDirect front chainring selection (use analog value)
0x05Cassette SetDirect 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 change
  • 0x01 = Not used for gear selection; receivers MUST treat it as a no-op (same as 0x00)
  • 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.

Button IDActionDescription
0x10UpNavigate up in menus
0x11DownNavigate down in menus
0x12LeftNavigate left / Look left
0x13RightNavigate right / Look right
0x14Select/ConfirmConfirm selection
0x15Back/CancelGo back / Cancel
0x16MenuOpen menu
0x17HomeReturn to home screen
0x18Steer LeftSteer left in-game
0x19Steer RightSteer right in-game
0x1ABrakeApply brake (use analog value for strength)
0x1BSteering AngleProportional steering (use analog value for angle)

Brake Analog Values:

  • 0x00 = Released / no braking
  • 0x01 = 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 behavior
  • 0x01 = Not used for steering angle; receivers MUST treat it as a no-op
  • 0x02-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 IDActionDescription
0x20EmoteSend social emote (use analog value to specify emote type)
0x21Push to TalkActivate microphone for voice input
0x24ScreenshotTake an in-game screenshot

Emote Analog Values:

  • 0x00 = No emote / Released
  • 0x01 = Pressed (cycle through emotes)
  • 0x02-0x1F = Reserved for app-specific emotes

Training Controls (0x30-0x3F)

Button IDActionDescription
0x30Increase DifficultyIncrease workout intensity / workout difficulty / increase ERG mode power
0x31Decrease DifficultyDecrease workout intensity / workout difficulty / decrease ERG mode power
0x32Skip IntervalSkip to next workout interval
0x33PausePause workout
0x34ResumeResume workout
0x35LapMark lap
0x36Previous IntervalSkip to previous workout interval
0x37U-TurnPerform U-Turn
0x38Change ModeToggle between modes, e.g. ERG and others
0x39Take a breakTake a break
0x3AJoin another rider"Teleport" to another rider
0x3BChange routeShow route change selection
0x3CCruise ControlToggle 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 = Released
  • 0x01 = Pressed — toggle cruise control on/off, engaging at the rider's current power
  • 0x02-0x09 = Reserved; receivers MUST treat these values as a no-op
  • 0x0A-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 IDActionDescription
0x40Camera ViewSelect camera view (use analog value to specify view)
0x44HUD ToggleShow/hide HUD
0x45Map ToggleShow/hide map
0x46Spectate riderSpectate another rider

Camera View Analog Values:

  • 0x00 = No change / Released
  • 0x01 = Pressed (cycle through camera views)
  • 0x02-0x1F = Reserved for app-specific camera views

Power-ups (0x50-0x5F)

Button IDActionDescription
0x50Power-up 1Activate power-up slot 1
0x51Power-up 2Activate power-up slot 2
0x52Power-up 3Activate power-up slot 3

Custom/Reserved (0x60-0xFF)

RangePurpose
0x60-0x7FReserved for future standard actions
0x80-0x9FApp-specific custom actions
0xA0-0xFFManufacturer-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 shifting
  • 0x30 (Increase Difficulty) - For apps that support ERG mode power adjustment
  • 0x14 (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

  1. 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
  2. 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
  3. Button Mapping:

    • Provide user configuration for custom button mappings
    • Use standard button IDs as defaults
    • Allow users to override mappings for their workflow
  4. Multi-Device Support:

    • Support connecting multiple OpenBikeControl devices simultaneously
    • Allow users to assign devices to specific action categories

For Device Manufacturers

  1. 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
  2. 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
  3. Power Management:

    • Implement BLE sleep modes when inactive
    • Wake on button press
    • Report accurate battery levels
  4. 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


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.