1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-12-28 11:35:48 +01:00

Garmin: Resting metabolic rate

This commit is contained in:
José Rebelo 2024-10-18 00:03:32 +01:00
parent 78d6ad3a1f
commit 60ab38db57
7 changed files with 147 additions and 0 deletions

View File

@ -127,6 +127,7 @@ public class GBDaoGenerator {
addGarminHrvValueSample(schema, user, device); addGarminHrvValueSample(schema, user, device);
addGarminRespiratoryRateSample(schema, user, device); addGarminRespiratoryRateSample(schema, user, device);
addGarminHeartRateRestingSample(schema, user, device); addGarminHeartRateRestingSample(schema, user, device);
addGarminRestingMetabolicRateSample(schema, user, device);
addPendingFile(schema, user, device); addPendingFile(schema, user, device);
addWena3EnergySample(schema, user, device); addWena3EnergySample(schema, user, device);
addWena3BehaviorSample(schema, user, device); addWena3BehaviorSample(schema, user, device);
@ -870,6 +871,14 @@ public class GBDaoGenerator {
return hrRestingSample; return hrRestingSample;
} }
private static Entity addGarminRestingMetabolicRateSample(Schema schema, Entity user, Entity device) {
Entity sample = addEntity(schema, "GarminRestingMetabolicRateSample");
sample.addImport(MAIN_PACKAGE + ".model.RestingMetabolicRateSample");
addCommonTimeSampleProperties("RestingMetabolicRateSample", sample, user, device);
sample.addIntProperty("restingMetabolicRate").notNull().codeBeforeGetter(OVERRIDE);
return sample;
}
private static Entity addPendingFile(Schema schema, Entity user, Entity device) { private static Entity addPendingFile(Schema schema, Entity user, Entity device) {
Entity pendingFile = addEntity(schema, "PendingFile"); Entity pendingFile = addEntity(schema, "PendingFile");
pendingFile.setJavaDoc( pendingFile.setJavaDoc(

View File

@ -77,6 +77,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.HrvSummarySample;
import nodomain.freeyourgadget.gadgetbridge.model.HrvValueSample; import nodomain.freeyourgadget.gadgetbridge.model.HrvValueSample;
import nodomain.freeyourgadget.gadgetbridge.model.PaiSample; import nodomain.freeyourgadget.gadgetbridge.model.PaiSample;
import nodomain.freeyourgadget.gadgetbridge.model.RespiratoryRateSample; import nodomain.freeyourgadget.gadgetbridge.model.RespiratoryRateSample;
import nodomain.freeyourgadget.gadgetbridge.model.RestingMetabolicRateSample;
import nodomain.freeyourgadget.gadgetbridge.model.Spo2Sample; import nodomain.freeyourgadget.gadgetbridge.model.Spo2Sample;
import nodomain.freeyourgadget.gadgetbridge.model.StressSample; import nodomain.freeyourgadget.gadgetbridge.model.StressSample;
import nodomain.freeyourgadget.gadgetbridge.model.TemperatureSample; import nodomain.freeyourgadget.gadgetbridge.model.TemperatureSample;
@ -280,6 +281,11 @@ public abstract class AbstractDeviceCoordinator implements DeviceCoordinator {
return null; return null;
} }
@Override
public TimeSampleProvider<? extends RestingMetabolicRateSample> getRestingMetabolicRateProvider(final GBDevice device, final DaoSession session) {
return null; // FIXME return new DefaultRestingMetabolicRateProvider(device, session);
}
@Override @Override
@Nullable @Nullable
public ActivitySummaryParser getActivitySummaryParser(final GBDevice device, final Context context) { public ActivitySummaryParser getActivitySummaryParser(final GBDevice device, final Context context) {

View File

@ -57,6 +57,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.HrvSummarySample;
import nodomain.freeyourgadget.gadgetbridge.model.HrvValueSample; import nodomain.freeyourgadget.gadgetbridge.model.HrvValueSample;
import nodomain.freeyourgadget.gadgetbridge.model.PaiSample; import nodomain.freeyourgadget.gadgetbridge.model.PaiSample;
import nodomain.freeyourgadget.gadgetbridge.model.RespiratoryRateSample; import nodomain.freeyourgadget.gadgetbridge.model.RespiratoryRateSample;
import nodomain.freeyourgadget.gadgetbridge.model.RestingMetabolicRateSample;
import nodomain.freeyourgadget.gadgetbridge.model.Spo2Sample; import nodomain.freeyourgadget.gadgetbridge.model.Spo2Sample;
import nodomain.freeyourgadget.gadgetbridge.model.StressSample; import nodomain.freeyourgadget.gadgetbridge.model.StressSample;
import nodomain.freeyourgadget.gadgetbridge.model.TemperatureSample; import nodomain.freeyourgadget.gadgetbridge.model.TemperatureSample;
@ -372,6 +373,8 @@ public interface DeviceCoordinator {
*/ */
TimeSampleProvider<? extends WeightSample> getWeightSampleProvider(GBDevice device, DaoSession session); TimeSampleProvider<? extends WeightSample> getWeightSampleProvider(GBDevice device, DaoSession session);
TimeSampleProvider<? extends RestingMetabolicRateSample> getRestingMetabolicRateProvider(GBDevice device, DaoSession session);
/** /**
* Returns the {@link ActivitySummaryParser} for the device being supported. * Returns the {@link ActivitySummaryParser} for the device being supported.
* *

View File

@ -20,6 +20,7 @@ import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpec
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer; import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsScreen; import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsScreen;
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractBLEDeviceCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.AbstractBLEDeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.DefaultRestingMetabolicRateProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.WorkoutVo2MaxSampleProvider; import nodomain.freeyourgadget.gadgetbridge.devices.WorkoutVo2MaxSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler; import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider; import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
@ -45,6 +46,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.BodyEnergySample;
import nodomain.freeyourgadget.gadgetbridge.model.HrvSummarySample; import nodomain.freeyourgadget.gadgetbridge.model.HrvSummarySample;
import nodomain.freeyourgadget.gadgetbridge.model.HrvValueSample; import nodomain.freeyourgadget.gadgetbridge.model.HrvValueSample;
import nodomain.freeyourgadget.gadgetbridge.model.RespiratoryRateSample; import nodomain.freeyourgadget.gadgetbridge.model.RespiratoryRateSample;
import nodomain.freeyourgadget.gadgetbridge.model.RestingMetabolicRateSample;
import nodomain.freeyourgadget.gadgetbridge.model.Spo2Sample; import nodomain.freeyourgadget.gadgetbridge.model.Spo2Sample;
import nodomain.freeyourgadget.gadgetbridge.model.StressSample; import nodomain.freeyourgadget.gadgetbridge.model.StressSample;
import nodomain.freeyourgadget.gadgetbridge.model.Vo2MaxSample; import nodomain.freeyourgadget.gadgetbridge.model.Vo2MaxSample;
@ -153,6 +155,11 @@ public abstract class GarminCoordinator extends AbstractBLEDeviceCoordinator {
return new GarminRespiratoryRateSampleProvider(device, session); return new GarminRespiratoryRateSampleProvider(device, session);
} }
@Override
public TimeSampleProvider<? extends RestingMetabolicRateSample> getRestingMetabolicRateProvider(final GBDevice device, final DaoSession session) {
return new GarminRestingMetabolicRateSampleProvider(device, session);
}
@Override @Override
public GarminHeartRateRestingSampleProvider getHeartRateRestingSampleProvider(final GBDevice device, final DaoSession session) { public GarminHeartRateRestingSampleProvider getHeartRateRestingSampleProvider(final GBDevice device, final DaoSession session) {
return new GarminHeartRateRestingSampleProvider(device, session); return new GarminHeartRateRestingSampleProvider(device, session);

View File

@ -0,0 +1,56 @@
/* Copyright (C) 2024 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.devices.garmin;
import androidx.annotation.NonNull;
import de.greenrobot.dao.AbstractDao;
import de.greenrobot.dao.Property;
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractTimeSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
import nodomain.freeyourgadget.gadgetbridge.entities.GarminRestingMetabolicRateSample;
import nodomain.freeyourgadget.gadgetbridge.entities.GarminRestingMetabolicRateSampleDao;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
public class GarminRestingMetabolicRateSampleProvider extends AbstractTimeSampleProvider<GarminRestingMetabolicRateSample> {
public GarminRestingMetabolicRateSampleProvider(final GBDevice device, final DaoSession session) {
super(device, session);
}
@NonNull
@Override
public AbstractDao<GarminRestingMetabolicRateSample, ?> getSampleDao() {
return getSession().getGarminRestingMetabolicRateSampleDao();
}
@NonNull
@Override
protected Property getTimestampSampleProperty() {
return GarminRestingMetabolicRateSampleDao.Properties.Timestamp;
}
@NonNull
@Override
protected Property getDeviceIdentifierSampleProperty() {
return GarminRestingMetabolicRateSampleDao.Properties.DeviceId;
}
@Override
public GarminRestingMetabolicRateSample createSample() {
return new GarminRestingMetabolicRateSample();
}
}

View File

@ -0,0 +1,23 @@
/* Copyright (C) 2024 Severin von Wnuck-Lipinski
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.model;
import nodomain.freeyourgadget.gadgetbridge.entities.AbstractTimeSample;
public abstract class RestingMetabolicRateSample extends AbstractTimeSample {
public abstract int getRestingMetabolicRate();
}

View File

@ -26,6 +26,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminHeartRateRestin
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminHrvSummarySampleProvider; import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminHrvSummarySampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminHrvValueSampleProvider; import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminHrvValueSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminRespiratoryRateSampleProvider; import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminRespiratoryRateSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminRestingMetabolicRateSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminSleepStageSampleProvider; import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminSleepStageSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminSpo2SampleProvider; import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminSpo2SampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminStressSampleProvider; import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminStressSampleProvider;
@ -37,6 +38,7 @@ import nodomain.freeyourgadget.gadgetbridge.entities.GarminActivitySample;
import nodomain.freeyourgadget.gadgetbridge.entities.GarminBodyEnergySample; import nodomain.freeyourgadget.gadgetbridge.entities.GarminBodyEnergySample;
import nodomain.freeyourgadget.gadgetbridge.entities.GarminEventSample; import nodomain.freeyourgadget.gadgetbridge.entities.GarminEventSample;
import nodomain.freeyourgadget.gadgetbridge.entities.GarminHeartRateRestingSample; import nodomain.freeyourgadget.gadgetbridge.entities.GarminHeartRateRestingSample;
import nodomain.freeyourgadget.gadgetbridge.entities.GarminRestingMetabolicRateSample;
import nodomain.freeyourgadget.gadgetbridge.entities.GarminHrvSummarySample; import nodomain.freeyourgadget.gadgetbridge.entities.GarminHrvSummarySample;
import nodomain.freeyourgadget.gadgetbridge.entities.GarminHrvValueSample; import nodomain.freeyourgadget.gadgetbridge.entities.GarminHrvValueSample;
import nodomain.freeyourgadget.gadgetbridge.entities.GarminRespiratoryRateSample; import nodomain.freeyourgadget.gadgetbridge.entities.GarminRespiratoryRateSample;
@ -48,6 +50,7 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind; import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample; import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryParser; import nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryParser;
import nodomain.freeyourgadget.gadgetbridge.model.RestingMetabolicRateSample;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.FileType; import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.FileType;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionHrvStatus; import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionHrvStatus;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionSleepStage; import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionSleepStage;
@ -57,6 +60,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitHrvValue; import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitHrvValue;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitMonitoring; import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitMonitoring;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitMonitoringHrData; import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitMonitoringHrData;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitMonitoringInfo;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitPhysiologicalMetrics; import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitPhysiologicalMetrics;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitRecord; import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitRecord;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitRespirationRate; import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitRespirationRate;
@ -86,6 +90,7 @@ public class FitImporter {
private final List<GarminSleepStageSample> sleepStageSamples = new ArrayList<>(); private final List<GarminSleepStageSample> sleepStageSamples = new ArrayList<>();
private final List<GarminHrvSummarySample> hrvSummarySamples = new ArrayList<>(); private final List<GarminHrvSummarySample> hrvSummarySamples = new ArrayList<>();
private final List<GarminHrvValueSample> hrvValueSamples = new ArrayList<>(); private final List<GarminHrvValueSample> hrvValueSamples = new ArrayList<>();
private final List<GarminRestingMetabolicRateSample> restingMetabolicRateSamples = new ArrayList<>();
private final Map<Integer, Integer> unknownRecords = new HashMap<>(); private final Map<Integer, Integer> unknownRecords = new HashMap<>();
private FitSleepDataInfo fitSleepDataInfo = null; private FitSleepDataInfo fitSleepDataInfo = null;
private final List<FitSleepDataRaw> fitSleepDataRawSamples = new ArrayList<>(); private final List<FitSleepDataRaw> fitSleepDataRawSamples = new ArrayList<>();
@ -264,6 +269,16 @@ public class FitImporter {
sample.setTimestamp(ts * 1000L); sample.setTimestamp(ts * 1000L);
sample.setValue(Math.round(hrvValue.getValue())); sample.setValue(Math.round(hrvValue.getValue()));
hrvValueSamples.add(sample); hrvValueSamples.add(sample);
} else if (record instanceof FitMonitoringInfo) {
final FitMonitoringInfo monitoringInfo = (FitMonitoringInfo) record;
if (monitoringInfo.getRestingMetabolicRate() == null) {
continue;
}
LOG.trace("Monitoring info at {}: {}", ts, record);
final GarminRestingMetabolicRateSample sample = new GarminRestingMetabolicRateSample();
sample.setTimestamp(ts * 1000L);
sample.setRestingMetabolicRate(monitoringInfo.getRestingMetabolicRate());
restingMetabolicRateSamples.add(sample);
} else if (record instanceof FitMonitoringHrData) { } else if (record instanceof FitMonitoringHrData) {
final FitMonitoringHrData monitoringHrData = (FitMonitoringHrData) record; final FitMonitoringHrData monitoringHrData = (FitMonitoringHrData) record;
if (monitoringHrData.getRestingHeartRate() == null) { if (monitoringHrData.getRestingHeartRate() == null) {
@ -308,6 +323,7 @@ public class FitImporter {
persistRestingHrSamples(); persistRestingHrSamples();
persistStressSamples(); persistStressSamples();
persistBodyEnergySamples(); persistBodyEnergySamples();
persistRestingMetabolicRateSamples();
break; break;
case SLEEP: case SLEEP:
persistEvents(); persistEvents();
@ -374,6 +390,7 @@ public class FitImporter {
sleepStageSamples.clear(); sleepStageSamples.clear();
hrvSummarySamples.clear(); hrvSummarySamples.clear();
hrvValueSamples.clear(); hrvValueSamples.clear();
restingMetabolicRateSamples.clear();
unknownRecords.clear(); unknownRecords.clear();
fitSleepDataInfo = null; fitSleepDataInfo = null;
fitSleepDataRawSamples.clear(); fitSleepDataRawSamples.clear();
@ -801,4 +818,30 @@ public class FitImporter {
GB.toast(context, "Error saving body energy samples", Toast.LENGTH_LONG, GB.ERROR, e); GB.toast(context, "Error saving body energy samples", Toast.LENGTH_LONG, GB.ERROR, e);
} }
} }
private void persistRestingMetabolicRateSamples() {
if (restingMetabolicRateSamples.isEmpty()) {
return;
}
LOG.debug("Will persist {} resting metabolic rate samples", restingMetabolicRateSamples.size());
try (DBHandler handler = GBApplication.acquireDB()) {
final DaoSession session = handler.getDaoSession();
final Device device = DBHelper.getDevice(gbDevice, session);
final User user = DBHelper.getUser(session);
final GarminRestingMetabolicRateSampleProvider sampleProvider = new GarminRestingMetabolicRateSampleProvider(gbDevice, session);
for (final GarminRestingMetabolicRateSample sample : restingMetabolicRateSamples) {
sample.setDevice(device);
sample.setUser(user);
}
sampleProvider.addSamples(restingMetabolicRateSamples);
} catch (final Exception e) {
GB.toast(context, "Error saving body energy samples", Toast.LENGTH_LONG, GB.ERROR, e);
}
}
} }