feat(train): a ride reads the bike's speed and cadence sensor and power meter (ADR 0030, D49)

11d, its sensors: a ride's Record sheet offers the CSC sensor (0x1816)
and the power meter (0x1818), found nearby and remembered as the strap
is; the person's devices are now one map of DeviceKind to DeviceStore.
The service parses CSC and Cycling Power measurements (JVM-tested,
counters' rollover, coasting), writes the wheel's revolutions, the
crank's cadence and the watts to the file and to series of their own.
The recording screen shows cadence and watts; the page the power's
chart, average, highest and normalised power and the cadence's chart and
average; GPX, TCX and FIT carry them. A plan's watts target reads the
power meter too.

The wheel's speed and distance follow. Not tried with a real sensor.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-29 15:11:20 +01:00
commit 5c13e6f3c5
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -3141,6 +3141,132 @@ abstract class AppLocalizations {
/// In en, this message translates to:
/// **'What Strava, Garmin and intervals.icu read best'**
String get workoutExportFitHint;
/// No description provided for @recordSpeedSensor.
///
/// In en, this message translates to:
/// **'Speed and cadence sensor'**
String get recordSpeedSensor;
/// No description provided for @recordNoSpeedSensor.
///
/// In en, this message translates to:
/// **'None chosen'**
String get recordNoSpeedSensor;
/// No description provided for @recordPowerMeter.
///
/// In en, this message translates to:
/// **'Power meter'**
String get recordPowerMeter;
/// No description provided for @recordNoPowerMeter.
///
/// In en, this message translates to:
/// **'None chosen'**
String get recordNoPowerMeter;
/// No description provided for @speedSensorSheetTitle.
///
/// In en, this message translates to:
/// **'Speed and cadence sensor'**
String get speedSensorSheetTitle;
/// No description provided for @speedSensorSearching.
///
/// In en, this message translates to:
/// **'Looking for speed and cadence sensors nearby…'**
String get speedSensorSearching;
/// No description provided for @speedSensorSearchingHint.
///
/// In en, this message translates to:
/// **'Turn the wheel or the crank to wake it. One another app holds can\'t be found: close that app first.'**
String get speedSensorSearchingHint;
/// No description provided for @speedSensorUnnamed.
///
/// In en, this message translates to:
/// **'Unnamed sensor'**
String get speedSensorUnnamed;
/// No description provided for @speedSensorForget.
///
/// In en, this message translates to:
/// **'Forget sensor'**
String get speedSensorForget;
/// No description provided for @speedSensorRefused.
///
/// In en, this message translates to:
/// **'Train needs nearby devices to find your sensor. You can allow it in the system\'s settings.'**
String get speedSensorRefused;
/// No description provided for @powerMeterSheetTitle.
///
/// In en, this message translates to:
/// **'Power meter'**
String get powerMeterSheetTitle;
/// No description provided for @powerMeterSearching.
///
/// In en, this message translates to:
/// **'Looking for power meters nearby…'**
String get powerMeterSearching;
/// No description provided for @powerMeterSearchingHint.
///
/// In en, this message translates to:
/// **'Turn the crank to wake it. One another app holds can\'t be found: close that app first.'**
String get powerMeterSearchingHint;
/// No description provided for @powerMeterUnnamed.
///
/// In en, this message translates to:
/// **'Unnamed power meter'**
String get powerMeterUnnamed;
/// No description provided for @powerMeterForget.
///
/// In en, this message translates to:
/// **'Forget power meter'**
String get powerMeterForget;
/// No description provided for @powerMeterRefused.
///
/// In en, this message translates to:
/// **'Train needs nearby devices to find your power meter. You can allow it in the system\'s settings.'**
String get powerMeterRefused;
/// No description provided for @recordingCadence.
///
/// In en, this message translates to:
/// **'turns a minute'**
String get recordingCadence;
/// No description provided for @workoutPedalling.
///
/// In en, this message translates to:
/// **'Cadence'**
String get workoutPedalling;
/// No description provided for @workoutAverageCadence.
///
/// In en, this message translates to:
/// **'average cadence'**
String get workoutAverageCadence;
/// No description provided for @workoutNormalisedPower.
///
/// In en, this message translates to:
/// **'normalised power'**
String get workoutNormalisedPower;
/// No description provided for @workoutRpmValue.
///
/// In en, this message translates to:
/// **'{rpm} rpm'**
String workoutRpmValue(int rpm);
}
class _AppLocalizationsDelegate