mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2026-07-31 07:44:24 +02:00
Health Connect: Sync blood glucose
This commit is contained in:
@@ -128,6 +128,7 @@
|
||||
<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-permission android:name="android.permission.health.WRITE_BLOOD_GLUCOSE" />
|
||||
<uses-sdk tools:overrideLibrary="androidx.health.connect.client"/>
|
||||
|
||||
<uses-feature
|
||||
|
||||
+2
@@ -59,6 +59,7 @@ object HealthConnectPermissionManager {
|
||||
TEMPERATURE,
|
||||
RESPIRATORY_RATE,
|
||||
RESTING_HEART_RATE,
|
||||
BLOOD_GLUCOSE,
|
||||
WORKOUTS
|
||||
}
|
||||
|
||||
@@ -79,6 +80,7 @@ object HealthConnectPermissionManager {
|
||||
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.BLOOD_GLUCOSE -> setOf(HealthPermission.getWritePermission(BloodGlucoseRecord::class))
|
||||
HealthConnectDataType.TEMPERATURE -> setOf(
|
||||
HealthPermission.getWritePermission(BodyTemperatureRecord::class),
|
||||
HealthPermission.getWritePermission(SkinTemperatureRecord::class)
|
||||
|
||||
+6
-6
@@ -35,6 +35,7 @@ import nodomain.freeyourgadget.gadgetbridge.database.DBHandler
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractSampleProvider
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.GlucoseSampleProvider
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummaryDao
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HealthConnectSyncState
|
||||
@@ -530,12 +531,6 @@ class HealthConnectUtils {
|
||||
}
|
||||
|
||||
val initialSyncPrefs = context.getSharedPreferences(GBPrefs.HEALTH_CONNECT_SETTINGS, Context.MODE_PRIVATE)
|
||||
val initialSyncStartTs = initialSyncPrefs.getLong(GBPrefs.HEALTH_CONNECT_INITIAL_SYNC_START_TS, -1L)
|
||||
|
||||
if (initialSyncStartTs != -1L) {
|
||||
CompanionLogger.info("$HC_SYNC_TAG Using initial sync start timestamp for {}({}): {} ({})", gbDevice.aliasOrName, dataType.name, initialSyncStartTs, Instant.ofEpochSecond(initialSyncStartTs))
|
||||
return Instant.ofEpochSecond(initialSyncStartTs)
|
||||
}
|
||||
|
||||
val firstTs = getFirstSampleTimestamp(deviceCoordinator, gbDevice, db, dataType)
|
||||
if (firstTs != null) {
|
||||
@@ -610,6 +605,10 @@ class HealthConnectUtils {
|
||||
healthConnectClient, gbDevice, metadata, offset,
|
||||
currentSliceStartTs, currentSliceEndTs, grantedPermissions
|
||||
))
|
||||
HealthConnectPermissionManager.HealthConnectDataType.BLOOD_GLUCOSE -> sliceStats.add(BloodGlucoseSyncer.sync(
|
||||
healthConnectClient, gbDevice, metadata, offset,
|
||||
currentSliceStartTs, currentSliceEndTs, grantedPermissions
|
||||
))
|
||||
HealthConnectPermissionManager.HealthConnectDataType.WORKOUTS -> {
|
||||
// Sync explicitly recorded workouts from BaseActivitySummary
|
||||
val coordinator = gbDevice.deviceCoordinator
|
||||
@@ -707,6 +706,7 @@ class HealthConnectUtils {
|
||||
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.BLOOD_GLUCOSE -> GlucoseSampleProvider(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)
|
||||
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/* 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.BloodGlucoseRecord
|
||||
import androidx.health.connect.client.records.metadata.Metadata
|
||||
import androidx.health.connect.client.units.BloodGlucose
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.GlucoseSampleProvider
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.GlucoseSample
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.time.Instant
|
||||
import java.time.ZoneOffset
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
internal object BloodGlucoseSyncer : AbstractTimeSampleSyncer<GlucoseSample, BloodGlucoseRecord>() {
|
||||
override val logger: Logger = LoggerFactory.getLogger(BloodGlucoseSyncer::class.java)
|
||||
override val recordClass: KClass<BloodGlucoseRecord> = BloodGlucoseRecord::class
|
||||
|
||||
override fun getSampleProvider(
|
||||
gbDevice: GBDevice,
|
||||
daoSession: DaoSession
|
||||
): TimeSampleProvider<out GlucoseSample> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return GlucoseSampleProvider(gbDevice, daoSession) as TimeSampleProvider<out GlucoseSample>
|
||||
}
|
||||
|
||||
override fun convertSample(
|
||||
sample: GlucoseSample,
|
||||
offset: ZoneOffset,
|
||||
metadata: Metadata,
|
||||
deviceName: String
|
||||
): BloodGlucoseRecord {
|
||||
return BloodGlucoseRecord(
|
||||
time = Instant.ofEpochMilli(sample.timestamp),
|
||||
zoneOffset = offset,
|
||||
level = BloodGlucose.milligramsPerDeciliter(sample.valueMgDl),
|
||||
metadata = metadata
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user