diff --git a/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java b/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java
index d29953ac7..cf6c34216 100644
--- a/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java
+++ b/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java
@@ -127,6 +127,7 @@ public class GBDaoGenerator {
addGarminHrvValueSample(schema, user, device);
addGarminRespiratoryRateSample(schema, user, device);
addGarminHeartRateRestingSample(schema, user, device);
+ addGarminRestingMetabolicRateSample(schema, user, device);
addPendingFile(schema, user, device);
addWena3EnergySample(schema, user, device);
addWena3BehaviorSample(schema, user, device);
@@ -870,6 +871,14 @@ public class GBDaoGenerator {
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) {
Entity pendingFile = addEntity(schema, "PendingFile");
pendingFile.setJavaDoc(
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/AbstractDeviceCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/AbstractDeviceCoordinator.java
index 78201df3f..8458f89a3 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/AbstractDeviceCoordinator.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/AbstractDeviceCoordinator.java
@@ -77,6 +77,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.HrvSummarySample;
import nodomain.freeyourgadget.gadgetbridge.model.HrvValueSample;
import nodomain.freeyourgadget.gadgetbridge.model.PaiSample;
import nodomain.freeyourgadget.gadgetbridge.model.RespiratoryRateSample;
+import nodomain.freeyourgadget.gadgetbridge.model.RestingMetabolicRateSample;
import nodomain.freeyourgadget.gadgetbridge.model.Spo2Sample;
import nodomain.freeyourgadget.gadgetbridge.model.StressSample;
import nodomain.freeyourgadget.gadgetbridge.model.TemperatureSample;
@@ -280,6 +281,11 @@ public abstract class AbstractDeviceCoordinator implements DeviceCoordinator {
return null;
}
+ @Override
+ public TimeSampleProvider extends RestingMetabolicRateSample> getRestingMetabolicRateProvider(final GBDevice device, final DaoSession session) {
+ return null; // FIXME return new DefaultRestingMetabolicRateProvider(device, session);
+ }
+
@Override
@Nullable
public ActivitySummaryParser getActivitySummaryParser(final GBDevice device, final Context context) {
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/DeviceCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/DeviceCoordinator.java
index 19e218866..813bd8527 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/DeviceCoordinator.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/DeviceCoordinator.java
@@ -57,6 +57,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.HrvSummarySample;
import nodomain.freeyourgadget.gadgetbridge.model.HrvValueSample;
import nodomain.freeyourgadget.gadgetbridge.model.PaiSample;
import nodomain.freeyourgadget.gadgetbridge.model.RespiratoryRateSample;
+import nodomain.freeyourgadget.gadgetbridge.model.RestingMetabolicRateSample;
import nodomain.freeyourgadget.gadgetbridge.model.Spo2Sample;
import nodomain.freeyourgadget.gadgetbridge.model.StressSample;
import nodomain.freeyourgadget.gadgetbridge.model.TemperatureSample;
@@ -372,6 +373,8 @@ public interface DeviceCoordinator {
*/
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.
*
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/garmin/GarminCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/garmin/GarminCoordinator.java
index 23b090dab..8de544a70 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/garmin/GarminCoordinator.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/garmin/GarminCoordinator.java
@@ -20,6 +20,7 @@ import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpec
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsScreen;
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractBLEDeviceCoordinator;
+import nodomain.freeyourgadget.gadgetbridge.devices.DefaultRestingMetabolicRateProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.WorkoutVo2MaxSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
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.HrvValueSample;
import nodomain.freeyourgadget.gadgetbridge.model.RespiratoryRateSample;
+import nodomain.freeyourgadget.gadgetbridge.model.RestingMetabolicRateSample;
import nodomain.freeyourgadget.gadgetbridge.model.Spo2Sample;
import nodomain.freeyourgadget.gadgetbridge.model.StressSample;
import nodomain.freeyourgadget.gadgetbridge.model.Vo2MaxSample;
@@ -153,6 +155,11 @@ public abstract class GarminCoordinator extends AbstractBLEDeviceCoordinator {
return new GarminRespiratoryRateSampleProvider(device, session);
}
+ @Override
+ public TimeSampleProvider extends RestingMetabolicRateSample> getRestingMetabolicRateProvider(final GBDevice device, final DaoSession session) {
+ return new GarminRestingMetabolicRateSampleProvider(device, session);
+ }
+
@Override
public GarminHeartRateRestingSampleProvider getHeartRateRestingSampleProvider(final GBDevice device, final DaoSession session) {
return new GarminHeartRateRestingSampleProvider(device, session);
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/garmin/GarminRestingMetabolicRateSampleProvider.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/garmin/GarminRestingMetabolicRateSampleProvider.java
new file mode 100644
index 000000000..969f6e444
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/garmin/GarminRestingMetabolicRateSampleProvider.java
@@ -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 . */
+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 {
+ public GarminRestingMetabolicRateSampleProvider(final GBDevice device, final DaoSession session) {
+ super(device, session);
+ }
+
+ @NonNull
+ @Override
+ public AbstractDao 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();
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/RestingMetabolicRateSample.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/RestingMetabolicRateSample.java
new file mode 100644
index 000000000..bfd4f1d95
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/RestingMetabolicRateSample.java
@@ -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 . */
+package nodomain.freeyourgadget.gadgetbridge.model;
+
+import nodomain.freeyourgadget.gadgetbridge.entities.AbstractTimeSample;
+
+public abstract class RestingMetabolicRateSample extends AbstractTimeSample {
+ public abstract int getRestingMetabolicRate();
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/FitImporter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/FitImporter.java
index 54703bb71..2f97dbf34 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/FitImporter.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/FitImporter.java
@@ -26,6 +26,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminHeartRateRestin
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminHrvSummarySampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminHrvValueSampleProvider;
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.GarminSpo2SampleProvider;
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.GarminEventSample;
import nodomain.freeyourgadget.gadgetbridge.entities.GarminHeartRateRestingSample;
+import nodomain.freeyourgadget.gadgetbridge.entities.GarminRestingMetabolicRateSample;
import nodomain.freeyourgadget.gadgetbridge.entities.GarminHrvSummarySample;
import nodomain.freeyourgadget.gadgetbridge.entities.GarminHrvValueSample;
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.ActivitySample;
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.fit.fieldDefinitions.FieldDefinitionHrvStatus;
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.FitMonitoring;
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.FitRecord;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitRespirationRate;
@@ -86,6 +90,7 @@ public class FitImporter {
private final List sleepStageSamples = new ArrayList<>();
private final List hrvSummarySamples = new ArrayList<>();
private final List hrvValueSamples = new ArrayList<>();
+ private final List restingMetabolicRateSamples = new ArrayList<>();
private final Map unknownRecords = new HashMap<>();
private FitSleepDataInfo fitSleepDataInfo = null;
private final List fitSleepDataRawSamples = new ArrayList<>();
@@ -264,6 +269,16 @@ public class FitImporter {
sample.setTimestamp(ts * 1000L);
sample.setValue(Math.round(hrvValue.getValue()));
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) {
final FitMonitoringHrData monitoringHrData = (FitMonitoringHrData) record;
if (monitoringHrData.getRestingHeartRate() == null) {
@@ -308,6 +323,7 @@ public class FitImporter {
persistRestingHrSamples();
persistStressSamples();
persistBodyEnergySamples();
+ persistRestingMetabolicRateSamples();
break;
case SLEEP:
persistEvents();
@@ -374,6 +390,7 @@ public class FitImporter {
sleepStageSamples.clear();
hrvSummarySamples.clear();
hrvValueSamples.clear();
+ restingMetabolicRateSamples.clear();
unknownRecords.clear();
fitSleepDataInfo = null;
fitSleepDataRawSamples.clear();
@@ -801,4 +818,30 @@ public class FitImporter {
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);
+ }
+ }
}