mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2026-07-31 07:44:24 +02:00
Health Connect: Sync resting heart rate
This commit is contained in:
@@ -127,6 +127,7 @@
|
||||
<uses-permission android:name="android.permission.health.WRITE_POWER" />
|
||||
<uses-permission android:name="android.permission.health.WRITE_EXERCISE_ROUTE" />
|
||||
<uses-permission android:name="android.permission.health.WRITE_RESPIRATORY_RATE" />
|
||||
<uses-permission android:name="android.permission.health.WRITE_RESTING_HEART_RATE" />
|
||||
<uses-sdk tools:overrideLibrary="androidx.health.connect.client"/>
|
||||
|
||||
<uses-feature
|
||||
|
||||
+2
@@ -58,6 +58,7 @@ object HealthConnectPermissionManager {
|
||||
SPO2,
|
||||
TEMPERATURE,
|
||||
RESPIRATORY_RATE,
|
||||
RESTING_HEART_RATE,
|
||||
WORKOUTS
|
||||
}
|
||||
|
||||
@@ -77,6 +78,7 @@ object HealthConnectPermissionManager {
|
||||
HealthConnectDataType.WEIGHT -> setOf(HealthPermission.getWritePermission(WeightRecord::class))
|
||||
HealthConnectDataType.SPO2 -> setOf(HealthPermission.getWritePermission(OxygenSaturationRecord::class))
|
||||
HealthConnectDataType.RESPIRATORY_RATE -> setOf(HealthPermission.getWritePermission(RespiratoryRateRecord::class))
|
||||
HealthConnectDataType.RESTING_HEART_RATE -> setOf(HealthPermission.getWritePermission(RestingHeartRateRecord::class))
|
||||
HealthConnectDataType.TEMPERATURE -> setOf(
|
||||
HealthPermission.getWritePermission(BodyTemperatureRecord::class),
|
||||
HealthPermission.getWritePermission(SkinTemperatureRecord::class)
|
||||
|
||||
+5
@@ -600,6 +600,10 @@ class HealthConnectUtils {
|
||||
healthConnectClient, gbDevice, metadata, offset,
|
||||
currentSliceStartTs, currentSliceEndTs, grantedPermissions
|
||||
))
|
||||
HealthConnectPermissionManager.HealthConnectDataType.RESTING_HEART_RATE -> sliceStats.add(RestingHeartRateSyncer.sync(
|
||||
healthConnectClient, gbDevice, metadata, offset,
|
||||
currentSliceStartTs, currentSliceEndTs, grantedPermissions
|
||||
))
|
||||
HealthConnectPermissionManager.HealthConnectDataType.WORKOUTS -> {
|
||||
// Sync explicitly recorded workouts from BaseActivitySummary
|
||||
val coordinator = gbDevice.deviceCoordinator
|
||||
@@ -696,6 +700,7 @@ class HealthConnectUtils {
|
||||
HealthConnectPermissionManager.HealthConnectDataType.VO2MAX -> coordinator.getVo2MaxSampleProvider(device, db.daoSession)
|
||||
HealthConnectPermissionManager.HealthConnectDataType.HRV -> coordinator.getHrvValueSampleProvider(device, db.daoSession)
|
||||
HealthConnectPermissionManager.HealthConnectDataType.RESPIRATORY_RATE -> coordinator.getRespiratoryRateSampleProvider(device, db.daoSession)
|
||||
HealthConnectPermissionManager.HealthConnectDataType.RESTING_HEART_RATE -> coordinator.getHeartRateRestingSampleProvider(device, db.daoSession)
|
||||
HealthConnectPermissionManager.HealthConnectDataType.WEIGHT -> coordinator.getWeightSampleProvider(device, db.daoSession)
|
||||
// For SpO2 and Temperature, there might be a specific provider or fallback to general sample provider
|
||||
HealthConnectPermissionManager.HealthConnectDataType.SPO2 -> coordinator.getSpo2SampleProvider(device, db.daoSession) // Potentially add fallback if needed: ?: coordinator.getSampleProvider(device, db.daoSession)
|
||||
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/* Copyright (C) 2026 José Rebelo
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.util.healthconnect.syncers
|
||||
|
||||
import androidx.health.connect.client.records.RestingHeartRateRecord
|
||||
import androidx.health.connect.client.records.metadata.Metadata
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.HeartRateSample
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.time.Instant
|
||||
import java.time.ZoneOffset
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
internal object RestingHeartRateSyncer : AbstractTimeSampleSyncer<HeartRateSample, RestingHeartRateRecord>() {
|
||||
override val logger: Logger = LoggerFactory.getLogger(RestingHeartRateSyncer::class.java)
|
||||
override val recordClass: KClass<RestingHeartRateRecord> = RestingHeartRateRecord::class
|
||||
|
||||
override fun getSampleProvider(
|
||||
gbDevice: GBDevice,
|
||||
daoSession: DaoSession
|
||||
): TimeSampleProvider<out HeartRateSample>? {
|
||||
return gbDevice.deviceCoordinator.getHeartRateRestingSampleProvider(gbDevice, daoSession)
|
||||
}
|
||||
|
||||
override fun convertSample(
|
||||
sample: HeartRateSample,
|
||||
offset: ZoneOffset,
|
||||
metadata: Metadata,
|
||||
deviceName: String
|
||||
): RestingHeartRateRecord? {
|
||||
if (sample.heartRate !in 20..250) {
|
||||
return null
|
||||
}
|
||||
|
||||
return RestingHeartRateRecord(
|
||||
time = Instant.ofEpochMilli(sample.timestamp),
|
||||
zoneOffset = offset,
|
||||
beatsPerMinute = sample.heartRate.toLong(),
|
||||
metadata = metadata
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user