health_connector 1.0.0
health_connector: ^1.0.0 copied to clipboard
A Flutter plugin to access health data from Health Connect (Android) and HealthKit (iOS)
health_connector #
📖 Overview #
health_connector provides a unified, type-safe API for accessing health data across Android and
iOS platforms. It abstracts platform differences while exposing platform-specific features when
needed.
✨ Features #
| Feature | Description |
|---|---|
| 🔐 Permission Management | Request/check/revoke permissions |
| 📖 Reading Health Data | Read a single health record by ID or multiple health records within a specified date/time range with pagination |
| ✍️ Writing Health Data | Write health records |
| 🔄 Updating Health Records | Modify existing record |
| 🗑️ Deleting Health Records | Remove specific records by their IDs or within a date/time range |
| ➕ Aggregating Health Data | Sum/Avg/Min/Max Aggregation |
Explore the plugin's capabilities using the Health Connector Toolbox example app:
| Permission Request | Read Health Data | Write Health Data | Aggregate Health Data |
|---|---|---|---|
| [../../doc/assets/ios_permission_request.gif] [../../doc/assets/android_permission_request.gif] | [../../doc/assets/ios_read_health_data.gif] | [../../doc/assets/android_write_health_data.gif] | [../../doc/assets/ios_aggregate_health_data.gif] |
🎯 Requirements #
- Flutter >=3.3.0
- Dart >=3.9.2
- Android:
- minSdkVersion: 26 (Android 8.0)
- compileSdk: 34+
- iOS:
- iOS >=15.0
- Xcode >=14.0
🚀 Getting Started #
📦 Installation #
Add health_connector to your project:
flutter pub add health_connector
Or manually add to your pubspec.yaml:
dependencies:
health_connector: ^0.1.0
⚙️ Platform Setup #
For platform-specific setup instructions, see:
- Android: See health_connector_hc_android
- iOS: See health_connector_hk_ios
📚 Usage #
Import Package
import 'package:health_connector/health_connector.dart';
Check Platform Availability
final status = await HealthConnector.getHealthPlatformStatus();
switch (status) {
case HealthPlatformStatus.available:
print('Health platform ready');
break;
case HealthPlatformStatus.installationOrUpdateRequired:
print('Please install or update health platform');
break;
case HealthPlatformStatus.unavailable:
print('Health platform not supported');
break;
}
Create HealthConnector Instance
final connector = await HealthConnector.create(
HealthConnectorConfig(
isLoggerEnabled: true, // Enable debug logging
),
);
// Check which platform is being used
print('Platform: ${connector.healthPlatform.name}');
// Prints: "healthConnect" on Android, "appleHealth" on iOS
Permissions
Request Permissions
final permissions = [
HealthDataType.steps.readPermission,
HealthDataType.steps.writePermission,
HealthDataType.weight.readPermission,
HealthDataType.weight.writePermission,
// ...
];
final results = await connector.requestPermissions(permissions);
for (final result in results) {
print('${result.permission}: ${result.status}');
}
Important: On iOS, read permissions always return
PermissionStatus.unknownfor privacy reasons. This prevents apps from detecting if a user has any health data.
Read Health Records
Read Health Record by ID
final recordId = HealthRecordId('existing-record-id');
final readRequest = HealthDataType.steps.readRecord(recordId);
final record = await connector.readRecord(readRequest);
if (record != null) {
final stepRecord = record as StepRecord;
print('Steps: ${stepRecord.count.value}');
print('Time: ${stepRecord.startTime} to ${stepRecord.endTime}');
} else {
print('Record not found');
}
Read Multiple Health Records
// Read step records for the last 7 days
final request = HealthDataType.steps.readRecords(
startTime: DateTime.now().subtract(Duration(days: 7)),
endTime: DateTime.now(),
pageSize: 100,
);
final response = await connector.readRecords(request);
for (final record in response.records) {
final stepRecord = record as StepRecord;
print('Steps: ${stepRecord.count.value} '
'from ${stepRecord.startTime} to ${stepRecord.endTime}');
}
Read Multiple Health Records with Pagination
// Initialize pagination request
var request = HealthDataType.steps.readRecords(
startTime: DateTime.now().subtract(Duration(days: 30)),
endTime: DateTime.now(),
pageSize: 100, // Request 100 records per page
);
var allRecords = <StepRecord>[];
var pageNumber = 1;
print('Starting pagination with pageSize: 100');
// Paginate through all records
while (true) {
print('\n--- Page $pageNumber ---');
// Fetch the current page
final response = await connector.readRecords(request);
print('Records returned: ${response.records.length}');
print('Has nextPageRequest: ${response.nextPageRequest != null}');
// Add records to our collection
allRecords.addAll(response.records.cast<StepRecord>());
print('Total records collected so far: ${allRecords.length}');
// Platform-specific pagination handling
if (response.nextPageRequest == null) {
print('No nextPageRequest - pagination complete');
break;
}
// Move to next page
request = response.nextPageRequest!;
pageNumber++;
}
print('\n=== Pagination Complete ===');
print('Total records fetched: ${allRecords.length}');
print('Total pages processed: $pageNumber');
Write Health Records
Write Single Health Record
final stepRecord = StepRecord(
id: HealthRecordId.none, // Must be none for new records
startTime: DateTime.now().subtract(Duration(hours: 1)),
endTime: DateTime.now(),
count: Numeric(5000),
metadata: Metadata.automaticallyRecorded(
device: Device.fromType(DeviceType.phone),
),
);
final recordId = await connector.writeRecord(stepRecord);
print('Record written with ID: $recordId');
Write Multiple Health Records
final records = [
StepRecord(
id: HealthRecordId.none,
startTime: DateTime.now().subtract(Duration(hours: 2)),
endTime: DateTime.now().subtract(Duration(hours: 1)),
count: Numeric(3000),
metadata: Metadata.automaticallyRecorded(
device: Device.fromType(DeviceType.phone),
),
),
DistanceRecord(
id: HealthRecordId.none,
startTime: DateTime.now().subtract(Duration(hours: 1)),
endTime: DateTime.now(),
distance: Length(5000),
metadata: Metadata.automaticallyRecorded(
device: Device.fromType(DeviceType.phone),
),
),
// Other health records ...
];
final recordIds = await connector.writeRecords(records);
print('Wrote ${recordIds.length} records');
Update Health Records
// Read existing record
final recordId = HealthRecordId('existing-record-id');
final readRequest = HealthDataType.steps.readRecord(recordId);
final existingRecord = await connector.readRecord(readRequest);
if (existingRecord != null) {
// Create updated record
final updatedRecord = existingRecord.copyWith(
startTime: existingRecord.startTime,
endTime: existingRecord.endTime,
count: Numeric(existingRecord.count.value + 100),
metadata: existingRecord.metadata,
);
// Update returns ID (same on Android, new on iOS)
final newId = await connector.updateRecord(updatedRecord);
print('Original ID: $originalId');
print('New ID: $newId');
// originalId == newId on Android (originalId != newId on iOS)
}
Delete Health Records
Delete Health Records by IDs
await connector.deleteRecordsByIds(
dataType: HealthDataType.steps,
recordIds: [
HealthRecordId('id-1'),
HealthRecordId('id-2'),
],
);
print('Records deleted');
Delete Health Records by Date Range
await connector.deleteRecords(
dataType: HealthDataType.steps,
startTime: DateTime.now().subtract(Duration(days: 7)),
endTime: DateTime.now(),
);
print('Records deleted');
Aggregate Health Data
// Get total steps for today
final sumRequest = HealthDataType.steps.aggregateSum(
startTime: DateTime.now().startOfDay,
endTime: DateTime.now(),
);
final sumResponse = await connector.aggregate(sumRequest);
print('Total steps today: ${sumResponse.value.value}');
// Get average weight for the last month
final avgRequest = HealthDataType.weight.aggregateAvg(
startTime: DateTime.now().subtract(Duration(days: 30)),
endTime: DateTime.now(),
);
final avgResponse = await connector.aggregate(avgRequest);
print('Average weight: ${avgResponse.value.inKilograms} kg');
// Get min/max weight
final minRequest = HealthDataType.weight.aggregateMin(
startTime: DateTime.now().subtract(Duration(days: 30)),
endTime: DateTime.now(),
);
final minResponse = await connector.aggregate(minRequest);
print('Min weight: ${minResponse.value.inKilograms} kg');
final maxRequest = HealthDataType.weight.aggregateMax(
startTime: DateTime.now().subtract(Duration(days: 30)),
endTime: DateTime.now(),
);
final maxResponse = await connector.aggregate(maxRequest);
print('Max weight: ${maxResponse.value.inKilograms} kg');
⚒️ Platform Specific Features #
While health_connector provides a unified API across platforms, some features are only available
on specific platforms due to platform capabilities and limitations.
🤖 Android-only API #
Get All Granted Permissions
Retrieve a list of all permissions that have been granted to your app.
try {
final grantedPermissions = await connector.getGrantedPermissions();
print('Granted permissions: ${grantedPermissions.length}');
// Iterate through granted permissions
for (final permission in grantedPermissions) {
print('Permission: ${permission.permission} - Status: ${permission.status}');
}
} on HealthConnectorException catch (e) {
if (e.errorCode == HealthConnectorErrorCode.unsupportedHealthPlatformApi) {
print('This API is only available on Android');
} else {
print('Error: ${e.message}');
}
}
Revoke All Granted Permissions
Revoke all permissions that have been granted to your app.
try {
await connector.revokeAllPermissions();
print('All permissions revoked successfully');
} on HealthConnectorException catch (e) {
if (e.errorCode == HealthConnectorErrorCode.unsupportedHealthPlatformApi) {
print('This API is only available on Android');
} else {
print('Error: ${e.message}');
}
}
📋 Supported Health Data Types #
🏃 Activity #
| Data Type | Android | iOS | Documentation |
|---|---|---|---|
| Steps | ✅ | ✅ | • Android: StepsRecord• iOS: HKQuantityTypeIdentifier.stepCount |
| Distance | ✅ | ✅ | • Android: DistanceRecord• iOS: HKQuantityTypeIdentifier.distanceWalkingRunning |
| Active Calories Burned | ✅ | ✅ | • Android: ActiveCaloriesBurnedRecord• iOS: HKQuantityTypeIdentifier.activeEnergyBurned |
| Exercise Session / Workout | ❌ | ❌ | • Android: ExerciseSessionRecord• iOS: HKWorkoutTypeIdentifier |
| Floors Climbed | ✅ | ✅ | • Android: FloorsClimbedRecord• iOS: HKQuantityTypeIdentifier.flightsClimbed |
| Total Calories Burned | ❌ | ❌ | • Android: TotalCaloriesBurnedRecord• iOS: HKQuantityTypeIdentifier.basalEnergyBurned |
| Cycling Pedaling Cadence | ❌ | ❌ | • Android: CyclingPedalingCadenceRecord• iOS: Not available |
| Power | ❌ | ❌ | • Android: PowerRecord• iOS: HKQuantityTypeIdentifier.cyclingPower |
| Speed | ❌ | ❌ | • Android: SpeedRecord• iOS: HKQuantityTypeIdentifier.walkingSpeed, HKQuantityTypeIdentifier.runningSpeed |
| Wheelchair Pushes | ✅ | ✅ | • Android: WheelchairPushesRecord• iOS: HKQuantityTypeIdentifier.pushCount |
| Distance Cycling | ❌ | ❌ | • Android: Part of DistanceRecord• iOS: HKQuantityTypeIdentifier.distanceCycling |
| Distance Swimming | ❌ | ❌ | • Android: Part of DistanceRecord• iOS: HKQuantityTypeIdentifier.distanceSwimming |
| Distance Wheelchair | ❌ | ❌ | • Android: Part of DistanceRecord• iOS: HKQuantityTypeIdentifier.distanceWheelchair |
| Apple Exercise Time | ❌ | ❌ | • Android: Not available • iOS: HKQuantityTypeIdentifier.appleExerciseTime |
| Apple Stand Time | ❌ | ❌ | • Android: Not available • iOS: HKQuantityTypeIdentifier.appleStandTime |
| Nike Fuel | ❌ | ❌ | • Android: Not available • iOS: HKQuantityTypeIdentifier.nikeFuel |
| Swimming Stroke Count | ❌ | ❌ | • Android: Not available • iOS: HKQuantityTypeIdentifier.swimmingStrokeCount |
| Wheelchair Distance | ❌ | ❌ | • Android: Part of DistanceRecord• iOS: HKQuantityTypeIdentifier.distanceWheelchair |
📏 Body Measurements #
| Data Type | Android | iOS | Documentation |
|---|---|---|---|
| Weight | ✅ | ✅ | • Android: WeightRecord• iOS: HKQuantityTypeIdentifier.bodyMass |
| Height | ✅ | ✅ | • Android: HeightRecord• iOS: HKQuantityTypeIdentifier.height |
| Body Fat Percentage | ✅ | ✅ | • Android: BodyFatRecord• iOS: HKQuantityTypeIdentifier.bodyFatPercentage |
| Bone Mass | ❌ | ❌ | • Android: BoneMassRecord• iOS: Not available |
| Lean Body Mass | ✅ | ✅ | • Android: LeanBodyMassRecord• iOS: HKQuantityTypeIdentifier.leanBodyMass |
| Body Mass Index | ❌ | ❌ | • Android: Not available • iOS: HKQuantityTypeIdentifier.bodyMassIndex |
| Waist Circumference | ❌ | ❌ | • Android: Not available • iOS: HKQuantityTypeIdentifier.waistCircumference |
| Basal Metabolic Rate | ❌ | ❌ | • Android: BasalMetabolicRateRecord• iOS: Not available |
🩸 Cycle Tracking / Reproductive Health #
| Data Type | Android | iOS | Documentation |
|---|---|---|---|
| Menstruation Flow | ❌ | ❌ | • Android: MenstruationFlowRecord• iOS: HKCategoryTypeIdentifier.menstrualFlow |
| Cervical Mucus | ❌ | ❌ | • Android: CervicalMucusRecord• iOS: HKCategoryTypeIdentifier.cervicalMucusQuality |
| Ovulation Test | ❌ | ❌ | • Android: OvulationTestRecord• iOS: HKCategoryTypeIdentifier.ovulationTestResult |
| Basal Body Temperature | ❌ | ❌ | • Android: BasalBodyTemperatureRecord• iOS: HKQuantityTypeIdentifier.basalBodyTemperature |
| Sexual Activity | ❌ | ❌ | • Android: SexualActivityRecord• iOS: HKCategoryTypeIdentifier.sexualActivity |
| Intermenstrual Bleeding | ❌ | ❌ | • Android: Not available • iOS: HKCategoryTypeIdentifier.intermenstrualBleeding |
| Pregnancy Test Result | ❌ | ❌ | • Android: Not available • iOS: HKCategoryTypeIdentifier.pregnancyTestResult |
| Progesterone Test Result | ❌ | ❌ | • Android: Not available • iOS: HKCategoryTypeIdentifier.progesteroneTestResult |
🍎 Nutrition #
| Data Type | Android | iOS | Documentation |
|---|---|---|---|
| Hydration / Water | ✅ | ✅ | • Android: HydrationRecord• iOS: HKQuantityTypeIdentifier.dietaryWater |
| Nutrition / Dietary Energy | ❌ | ❌ | • Android: NutritionRecord• iOS: HKQuantityTypeIdentifier.dietaryEnergyConsumed |
| Macronutrients | ❌ | ❌ | • Android: Part of NutritionRecord• iOS: HKQuantityTypeIdentifier.dietaryProtein, HKQuantityTypeIdentifier.dietaryCarbohydrates, etc. |
| Vitamins & Minerals | ❌ | ❌ | • Android: Part of NutritionRecord• iOS: Multiple identifiers (Vitamin C, D, Iron, Calcium, etc.) |
| Dietary Protein | ❌ | ❌ | • Android: Part of NutritionRecord• iOS: HKQuantityTypeIdentifier.dietaryProtein |
| Dietary Carbohydrates | ❌ | ❌ | • Android: Part of NutritionRecord• iOS: HKQuantityTypeIdentifier.dietaryCarbohydrates |
| Dietary Fat Total | ❌ | ❌ | • Android: Part of NutritionRecord• iOS: HKQuantityTypeIdentifier.dietaryFatTotal |
| Dietary Fat Saturated | ❌ | ❌ | • Android: Part of NutritionRecord• iOS: HKQuantityTypeIdentifier.dietaryFatSaturated |
| Dietary Fat Polyunsaturated | ❌ | ❌ | • Android: Part of NutritionRecord• iOS: HKQuantityTypeIdentifier.dietaryFatPolyunsaturated |
| Dietary Fat Monounsaturated | ❌ | ❌ | • Android: Part of NutritionRecord• iOS: HKQuantityTypeIdentifier.dietaryFatMonounsaturated |
| Dietary Cholesterol | ❌ | ❌ | • Android: Part of NutritionRecord• iOS: HKQuantityTypeIdentifier.dietaryCholesterol |
| Dietary Sodium | ❌ | ❌ | • Android: Part of NutritionRecord• iOS: HKQuantityTypeIdentifier.dietarySodium |
| Dietary Fiber | ❌ | ❌ | • Android: Part of NutritionRecord• iOS: HKQuantityTypeIdentifier.dietaryFiber |
| Dietary Sugar | ❌ | ❌ | • Android: Part of NutritionRecord• iOS: HKQuantityTypeIdentifier.dietarySugar |
| Dietary Calcium | ❌ | ❌ | • Android: Part of NutritionRecord• iOS: HKQuantityTypeIdentifier.dietaryCalcium |
| Dietary Iron | ❌ | ❌ | • Android: Part of NutritionRecord• iOS: HKQuantityTypeIdentifier.dietaryIron |
| Dietary Vitamin C | ❌ | ❌ | • Android: Part of NutritionRecord• iOS: HKQuantityTypeIdentifier.dietaryVitaminC |
| Dietary Vitamin D | ❌ | ❌ | • Android: Part of NutritionRecord• iOS: HKQuantityTypeIdentifier.dietaryVitaminD |
| Dietary Vitamin E | ❌ | ❌ | • Android: Part of NutritionRecord• iOS: HKQuantityTypeIdentifier.dietaryVitaminE |
| Dietary Vitamin K | ❌ | ❌ | • Android: Part of NutritionRecord• iOS: HKQuantityTypeIdentifier.dietaryVitaminK |
| Dietary Vitamin B6 | ❌ | ❌ | • Android: Part of NutritionRecord• iOS: HKQuantityTypeIdentifier.dietaryVitaminB6 |
| Dietary Vitamin B12 | ❌ | ❌ | • Android: Part of NutritionRecord• iOS: HKQuantityTypeIdentifier.dietaryVitaminB12 |
| Dietary Thiamin (B1) | ❌ | ❌ | • Android: Part of NutritionRecord• iOS: HKQuantityTypeIdentifier.dietaryThiamin |
| Dietary Riboflavin (B2) | ❌ | ❌ | • Android: Part of NutritionRecord• iOS: HKQuantityTypeIdentifier.dietaryRiboflavin |
| Dietary Niacin (B3) | ❌ | ❌ | • Android: Part of NutritionRecord• iOS: HKQuantityTypeIdentifier.dietaryNiacin |
| Dietary Folate | ❌ | ❌ | • Android: Part of NutritionRecord• iOS: HKQuantityTypeIdentifier.dietaryFolate |
| Dietary Biotin | ❌ | ❌ | • Android: Part of NutritionRecord• iOS: HKQuantityTypeIdentifier.dietaryBiotin |
| Dietary Pantothenic Acid | ❌ | ❌ | • Android: Part of NutritionRecord• iOS: HKQuantityTypeIdentifier.dietaryPantothenicAcid |
| Caffeine | ❌ | ❌ | • Android: Part of NutritionRecord• iOS: HKQuantityTypeIdentifier.dietaryCaffeine |
😴 Sleep #
| Data Type | Android | iOS | Documentation |
|---|---|---|---|
| Sleep Session | ✅ | ❌ | • Android: SleepSessionRecord• iOS: Not available |
| Sleep Stage | ❌ | ✅ | • Android: Not available • iOS: HKCategoryTypeIdentifier.sleepAnalysis |
❤️ Vitals #
| Data Type | Android | iOS | Documentation |
|---|---|---|---|
| Heart Rate (Series) | ✅ | ❌ | • Android: HeartRateSeriesRecord• iOS: Not available |
| Heart Rate (Measurement) | ❌ | ✅ | • Android: Not available • iOS: HKQuantityTypeIdentifier.heartRate |
| Resting Heart Rate | ❌ | ❌ | • Android: RestingHeartRateRecord• iOS: HKQuantityTypeIdentifier.restingHeartRate |
| Blood Pressure | ❌ | ❌ | • Android: BloodPressureRecord• iOS: HKQuantityTypeIdentifier.bloodPressureSystolic, HKQuantityTypeIdentifier.bloodPressureDiastolic |
| Body Temperature | ✅ | ✅ | • Android: BodyTemperatureRecord• iOS: HKQuantityTypeIdentifier.bodyTemperature |
| Blood Glucose | ❌ | ❌ | • Android: BloodGlucoseRecord• iOS: HKQuantityTypeIdentifier.bloodGlucose |
| Oxygen Saturation | ❌ | ❌ | • Android: OxygenSaturationRecord• iOS: HKQuantityTypeIdentifier.oxygenSaturation |
| Respiratory Rate | ❌ | ❌ | • Android: RespiratoryRateRecord• iOS: HKQuantityTypeIdentifier.respiratoryRate |
| Vo2 Max | ❌ | ❌ | • Android: Vo2MaxRecord• iOS: HKQuantityTypeIdentifier.vo2Max |
| Walking Heart Rate Average | ❌ | ❌ | • Android: Not available • iOS: HKQuantityTypeIdentifier.walkingHeartRateAverage |
| Heart Rate Variability SDNN | ❌ | ❌ | • Android: Not available • iOS: HKQuantityTypeIdentifier.heartRateVariabilitySDNN |
| Peripheral Perfusion Index | ❌ | ❌ | • Android: Not available • iOS: HKQuantityTypeIdentifier.peripheralPerfusionIndex |
| Blood Alcohol Content | ❌ | ❌ | • Android: Not available • iOS: HKQuantityTypeIdentifier.bloodAlcoholContent |
| Forced Vital Capacity | ❌ | ❌ | • Android: Not available • iOS: HKQuantityTypeIdentifier.forcedVitalCapacity |
| Forced Expiratory Volume | ❌ | ❌ | • Android: Not available • iOS: HKQuantityTypeIdentifier.forcedExpiratoryVolume1 |
| Peak Expiratory Flow Rate | ❌ | ❌ | • Android: Not available • iOS: HKQuantityTypeIdentifier.peakExpiratoryFlowRate |
🧘 Wellness / Mental Health #
| Data Type | Android | iOS | Documentation |
|---|---|---|---|
| Mindfulness Session | ❌ | ❌ | • Android: MindfulnessSessionRecord• iOS: HKCategoryTypeIdentifier.mindfulSession |
🏥 Clinical Records #
| Data Type | Android | iOS | Documentation |
|---|---|---|---|
| Electrocardiogram (ECG) | ❌ | ❌ | • Android: Not available • iOS: HKElectrocardiogram |
| Vision Prescription | ❌ | ❌ | • Android: Not available • iOS: HKVisionPrescription |
🎧 Audio Exposure #
| Data Type | Android | iOS | Documentation |
|---|---|---|---|
| Headphone Audio Exposure | ❌ | ❌ | • Android: Not available • iOS: HKQuantityTypeIdentifier.headphoneAudioExposureEvent |
| Environmental Audio Exposure | ❌ | ❌ | • Android: Not available • iOS: HKQuantityTypeIdentifier.environmentalAudioExposureEvent |
🚶 Mobility & Gait Analysis #
| Data Type | Android | iOS | Documentation |
|---|---|---|---|
| Walking Speed | ❌ | ❌ | • Android: Not available • iOS: HKQuantityTypeIdentifier.walkingSpeed |
| Running Speed | ❌ | ❌ | • Android: Not available • iOS: HKQuantityTypeIdentifier.runningSpeed |
| Step Length | ❌ | ❌ | • Android: Not available • iOS: HKQuantityTypeIdentifier.stepLength |
| Walking Asymmetry Percentage | ❌ | ❌ | • Android: Not available • iOS: HKQuantityTypeIdentifier.walkingAsymmetryPercentage |
| Walking Double Support Percentage | ❌ | ❌ | • Android: Not available • iOS: HKQuantityTypeIdentifier.walkingDoubleSupportPercentage |
| Six Minute Walk Test Distance | ❌ | ❌ | • Android: Not available • iOS: HKQuantityTypeIdentifier.sixMinuteWalkTestDistance |
| Stair Ascent Speed | ❌ | ❌ | • Android: Not available • iOS: HKQuantityTypeIdentifier.stairAscentSpeed |
| Stair Descent Speed | ❌ | ❌ | • Android: Not available • iOS: HKQuantityTypeIdentifier.stairDescentSpeed |
🤝 Contributing #
Contributions are welcome!
To report issues or request features, please visit our GitHub Issues.