Summary
Simplicity Connect fails to parse valid Cycling Power Measurement (0x2A63) notifications when only a subset of optional fields are present.
The app reports:
expected data length is 280-bit (35 bytes), read data length is 112-bit (14 bytes)
However, the exact same packet structure is accepted by Garmin devices and conforms to the Bluetooth CPS specification.
Interestingly, FTMS Rower Data parsing works correctly with dynamic optional fields, which suggests the issue is specific to the CPS XML metadata / conditional field handling rather than the generic parser itself.
Reproduction
CPS Measurement packet
Stationary:
30 00 00 00 00 00 00 00 00 00 00 00 00 00
Active:
30 00 1B 00 2B 09 00 00 93 6D 04 00 D1 12
Flags
0x0030
Which means:
- Bit 4: Wheel Revolution Data Present
- Bit 5: Crank Revolution Data Present
No other optional fields are present.
This produces a valid 14-byte payload:
| Field |
Size |
| Flags |
2 |
| Instantaneous Power |
2 |
| Wheel Revolution Data |
6 |
| Crank Revolution Data |
4 |
| Total |
14 |
Expected behavior
The packet should parse correctly, similarly to FTMS variable-length characteristics.
Actual behavior
The parser throws:
expected data length is 280-bit (35 bytes), read data length is 112-bit (14 bytes)
and falls back to raw-byte rendering.
Investigation
The issue appears to originate from the XML-driven conditional field parser.
Relevant code:
BluetoothXmlParser
FieldViewHelper.isFieldPresent()
FragmentCharacteristicDetail
The FTMS rower_data.xml contains requires="C1" style metadata on flag enumerations and dependent fields, allowing the parser to correctly determine which optional fields are present.
However, org.bluetooth.characteristic.cycling_power_measurement.xml in this repository appears not to expose the conditional metadata in the same way, so the parser cannot correctly map CPS flags to optional fields.
As a result, the parser appears to assume the maximum possible CPS payload size (35 bytes) instead of the actual dynamic size derived from the flags.
Reference
The CPS XML from the oesmith/gatt-xml project includes the required conditional metadata and appears to model the characteristic correctly:
https://github.com/oesmith/gatt-xml/blob/master/org.bluetooth.characteristic.cycling_power_measurement.xml
Specifically, that XML includes the requires="C1" / requires="C2" style requirement tags used by the parser logic.
This is consistent with how FTMS rower data XML is structured in this repository.
Suggested fix
Either:
- Update the CPS XML metadata to expose conditional requirements similarly to FTMS, or
- Make the generic parser more tolerant of CPS optional-field resolution failures.
Additional note
The CPS Feature characteristic is correctly exposed as a 32-bit value and parses properly in the app, so this issue seems isolated to the Measurement characteristic decoder.
Summary
Simplicity Connect fails to parse valid
Cycling Power Measurement(0x2A63) notifications when only a subset of optional fields are present.The app reports:
However, the exact same packet structure is accepted by Garmin devices and conforms to the Bluetooth CPS specification.
Interestingly, FTMS
Rower Dataparsing works correctly with dynamic optional fields, which suggests the issue is specific to the CPS XML metadata / conditional field handling rather than the generic parser itself.Reproduction
CPS Measurement packet
Stationary:
Active:
Flags
0x0030Which means:
No other optional fields are present.
This produces a valid 14-byte payload:
Expected behavior
The packet should parse correctly, similarly to FTMS variable-length characteristics.
Actual behavior
The parser throws:
and falls back to raw-byte rendering.
Investigation
The issue appears to originate from the XML-driven conditional field parser.
Relevant code:
BluetoothXmlParserFieldViewHelper.isFieldPresent()FragmentCharacteristicDetailThe FTMS
rower_data.xmlcontainsrequires="C1"style metadata on flag enumerations and dependent fields, allowing the parser to correctly determine which optional fields are present.However,
org.bluetooth.characteristic.cycling_power_measurement.xmlin this repository appears not to expose the conditional metadata in the same way, so the parser cannot correctly map CPS flags to optional fields.As a result, the parser appears to assume the maximum possible CPS payload size (35 bytes) instead of the actual dynamic size derived from the flags.
Reference
The CPS XML from the oesmith/gatt-xml project includes the required conditional metadata and appears to model the characteristic correctly:
https://github.com/oesmith/gatt-xml/blob/master/org.bluetooth.characteristic.cycling_power_measurement.xml
Specifically, that XML includes the
requires="C1"/requires="C2"style requirement tags used by the parser logic.This is consistent with how FTMS rower data XML is structured in this repository.
Suggested fix
Either:
Additional note
The CPS Feature characteristic is correctly exposed as a 32-bit value and parses properly in the app, so this issue seems isolated to the Measurement characteristic decoder.