Cycling Power Service - StephenDone/kickr_bluetooth GitHub Wiki

Cycling Power Service

00001818-0000-1000-8000-00805f9b34fb                         Cycling Power
00002a63-0000-1000-8000-00805f9b34fb  ['notify']               Cycling Power Measurement
00002a65-0000-1000-8000-00805f9b34fb  ['read']                 Cycling Power Feature
00002a5d-0000-1000-8000-00805f9b34fb  ['read']                 Sensor Location
a026e005-0a7d-4ab3-97fa-f1500f9feb8b  ['write', 'indicate']    ### KICKR Cycling Power Extension
00002a66-0000-1000-8000-00805f9b34fb  ['write', 'indicate']    Cycling Power Control Point

All pretty standard stuff, apart from the extension characteristic, which provides some useful features.

For standard functionality, see https://www.bluetooth.com/specifications/specs/cycling-power-profile-1-1/

All characteristics supported by the KICKR are detailed below:

Cycling Power Feature

00002a65-0000-1000-8000-00805f9b34fb ['read']

Reading this characteristic returns a bitfield that indicates the features that the cycling power service on the device supports.

KICKR Read

  Feature: data [0e 00] -> bitfield 0x000e -> 0000000000001110b
    0x00000002 Accumulated_Torque
    0x00000004 Wheel_Revolution_Data
    0x00000008 Crank_Revolution_Data

Sensor Location

00002a5d-0000-1000-8000-00805f9b34fb ['read']

Reading this characteristic returns the location of the power sensor, such as left/right crank, pedal or hub.

KICKR Read

Sensor Location: [00] -> 0x00 -> Other

Not very exciting!

Cycling Power Measurement

00002a63-0000-1000-8000-00805f9b34fb ['notify']

This characteristic returns regular notifications of cycling power data. The 16-bit flags field contained in every notification specifies what cycling power data fields are in each notification. The flags field is present in each notification, since the data fields can vary with each notification when there are a lot of fields to send.

Wheel and crank data includes a revolution count and a last revolution time. So wheel rpm and crank rpm are calculated by dividing change in revolution count by change in revolution time. It is done this way so that missed notifications do not significantly affect RPM and distance calculations.

To calculate wheel speed, you must also know the wheel circumference - a wheel speed is not returned by this characteristic, only a wheel RPM.

Example KICKR Notification Data

[3c 00 00 00 40 a4 5a fc 00 00 98 89 e3 1f 22 61]
 3c 00                                            -> 0x003c                - Power Measurement Flags
       00 00                                      -> 0x0000                - Power
             40 a4                                -> 0xa440 / 32 = 1,314   - Acc. Torque
                   5a fc 00 00                    -> 0x0000fc5a = 64602    - Cumulative Wheel Revolutions
                               98 89              -> 0x8998 / 2048 = 17.2  - Last Wheel Event Time
                                     e3 1f        -> 0x1fe3 = 8163         - Cumulative Crank Revolutions
                                           22 61  -> 0x6122 / 1024 = 24.28 - Last Crank Event Time

Flags: ['Accumulated_torque_present', 'Accumulated_torque_source_crank_based', 'Wheel_revolution_data_present', 'Crank_revolution_data_present']
Power:0
AccumulatedTorque:1314.0
CumulativeWheelRevolutions:64602
LastWheelEventTime:17.20
CumulativeCrankRevolutions:8163
LastCrankEventTime:24.28

The flag field in each KICKR notification is the same, since the bike returning very few data fields, and they can all fit in one notification.

Cycling Power Control Point

00002a66-0000-1000-8000-00805f9b34fb ['write', 'indicate']

Cycling Power Wahoo Extension

a026e005-0a7d-4ab3-97fa-f1500f9feb8b ['write', 'indicate']

This characteristic is a secondary, custom control point for the cycling power service. It controls erg, sim and level modes, as well as allowing setting of bike parameters, such as rolling resistance and drag coefficient. Commands are 'written' to the characteristic. Results of the commands are then 'indicated' back.

Some of the commands return strange results. This may be because the commands are not supported by the KICKR bike. These commands might be supported by the KICRK 'turbo trainer' variants. These commands include 'Cadence from ANT+', 'Control with ANT+ Power Meter' and 'Erg Mode Speed Simulation', which probably don't make sense for an indoor trainer bike.

Command/Result Data Notes
09 ec fc Unknown
01 09 02
0a ec fc Unknown
01 0a 01 ff 90 8b ad 0c a8 69
54 01 00/01 Cadence from ANT+. 00=off, 01=on
01 54 40 Result: Not supported?
55 06 ?
01 55 01 00 06 00
55 05 ?
01 55 40 00
54 02 00/01 Control with ANT+ Power Meter. 00=off, 01=on
01 54 40 Result: Not supported?
0d 02 ce 04 Write ANT+ ID. [ce 04] -> 0x04ce -> 1230 dec = ANT+ ID example
01 0d 40 ?
54 03 00/01 Erg Mode Speed Simulation. 00=off, 01=on
01 54 40 Result: Not supported?
55 06 ?
01 55 01 00 06 00
55 05 ?
01 55 40 00
54 06 00/01 Erg Mode Power Smoothing. 00=off, 01=on
01 54 01 00 06 00/01 Result
41 01-09 Set Level 1-9
01 41 01 00 01-09 Result
42 64 00 Set Erg Power. [64 00] -> [0x0064] -> 100 dec = 100 Watts
01 42 01 00 64 00 Result
43 34 21 28 00 58 02 Set SIM Mode( Weight, CRR, Drag )...
34 21 -> 0x2134 = 8500 dec = Weight * 100 -> 85kg
28 00 -> 0x0028 = 40 dec = CRR * 1000 -> 0.040
58 02 -> 0x0258 = 600 dec = Drag * 1000 -> 0.6
01 43 01 00 Result
44 21 00 Set Rolling Resistance (CRR). 21 00 -> 0x0021 = 33 dec = CRR * 1000 -> 0.033
01 44 01 00 21 00 Result
45 a0 01 Set Drag Coefficient. a0 01 -> 0x01a0 = 416 dec = C * 1000 -> 0.416
01 45 01 00 a0 01 Result
46 5c 7f Set SIM Mode Slope. Slope = (Value - 0x8000) * 100 / 0x8000
5c 7f -> 0x7f5c -> (0x7f5c - 0x8000) * 100 / 0x8000 = 0.5%
01 46 01 00 5c 7f Result
47 Examples
15 81
ea 7e
Set Wind Speed. Speed(m/s) = (Value - 0x8000)/1000
15 81 -> 0x8115 -> (0x8115 - 0x8000)/1000 = 0.277 m/s = 1 km/h
ea 7e -> 0x7eea -> (0x7eea - 0x8000)/1000 = -0.277 m/s = -1 km/h
01 47 01 00 15 81 Result
⚠️ **GitHub.com Fallback** ⚠️