diff --git a/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java b/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java
index eb7210d08..2e8b101d6 100644
--- a/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java
+++ b/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java
@@ -45,7 +45,7 @@ public class GBDaoGenerator {
public static void main(String[] args) throws Exception {
- final Schema schema = new Schema(74, MAIN_PACKAGE + ".entities");
+ final Schema schema = new Schema(75, MAIN_PACKAGE + ".entities");
Entity userAttributes = addUserAttributes(schema);
Entity user = addUserInfo(schema, userAttributes);
@@ -113,6 +113,8 @@ public class GBDaoGenerator {
addGarminSpo2Sample(schema, user, device);
addGarminSleepStageSample(schema, user, device);
addGarminEventSample(schema, user, device);
+ addGarminHrvSummarySample(schema, user, device);
+ addGarminHrvValueSample(schema, user, device);
addWena3EnergySample(schema, user, device);
addWena3BehaviorSample(schema, user, device);
addWena3CaloriesSample(schema, user, device);
@@ -725,6 +727,26 @@ public class GBDaoGenerator {
return sleepStageSample;
}
+ private static Entity addGarminHrvSummarySample(Schema schema, Entity user, Entity device) {
+ Entity hrvSummarySample = addEntity(schema, "GarminHrvSummarySample");
+ addCommonTimeSampleProperties("AbstractHrvSummarySample", hrvSummarySample, user, device);
+ hrvSummarySample.addIntProperty("weeklyAverage").codeBeforeGetter(OVERRIDE);
+ hrvSummarySample.addIntProperty("lastNightAverage").codeBeforeGetter(OVERRIDE);
+ hrvSummarySample.addIntProperty("lastNight5MinHigh").codeBeforeGetter(OVERRIDE);
+ hrvSummarySample.addIntProperty("baselineLowUpper").codeBeforeGetter(OVERRIDE);
+ hrvSummarySample.addIntProperty("baselineBalancedLower").codeBeforeGetter(OVERRIDE);
+ hrvSummarySample.addIntProperty("baselineBalancedUpper").codeBeforeGetter(OVERRIDE);
+ hrvSummarySample.addIntProperty("statusNum").codeBeforeGetter(OVERRIDE);
+ return hrvSummarySample;
+ }
+
+ private static Entity addGarminHrvValueSample(Schema schema, Entity user, Entity device) {
+ Entity hrvValueSample = addEntity(schema, "GarminHrvValueSample");
+ addCommonTimeSampleProperties("AbstractHrvValueSample", hrvValueSample, user, device);
+ hrvValueSample.addIntProperty("value").notNull().codeBeforeGetter(OVERRIDE);
+ return hrvValueSample;
+ }
+
private static Entity addWatchXPlusHealthActivitySample(Schema schema, Entity user, Entity device) {
Entity activitySample = addEntity(schema, "WatchXPlusActivitySample");
activitySample.implementsSerializable();
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 2ed27c5c6..a229354b7 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/AbstractDeviceCoordinator.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/AbstractDeviceCoordinator.java
@@ -73,6 +73,8 @@ import nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryParser;
import nodomain.freeyourgadget.gadgetbridge.model.BatteryConfig;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
import nodomain.freeyourgadget.gadgetbridge.model.HeartRateSample;
+import nodomain.freeyourgadget.gadgetbridge.model.HrvSummarySample;
+import nodomain.freeyourgadget.gadgetbridge.model.HrvValueSample;
import nodomain.freeyourgadget.gadgetbridge.model.PaiSample;
import nodomain.freeyourgadget.gadgetbridge.model.SleepRespiratoryRateSample;
import nodomain.freeyourgadget.gadgetbridge.model.Spo2Sample;
@@ -208,6 +210,16 @@ public abstract class AbstractDeviceCoordinator implements DeviceCoordinator {
return null;
}
+ @Override
+ public TimeSampleProvider extends HrvSummarySample> getHrvSummarySampleProvider(GBDevice device, DaoSession session) {
+ return null;
+ }
+
+ @Override
+ public TimeSampleProvider extends HrvValueSample> getHrvValueSampleProvider(GBDevice device, DaoSession session) {
+ return null;
+ }
+
@Override
public int[] getStressRanges() {
// 0-39 = relaxed
@@ -442,6 +454,11 @@ public abstract class AbstractDeviceCoordinator implements DeviceCoordinator {
return false;
}
+ @Override
+ public boolean supportsHrvMeasurement() {
+ return false;
+ }
+
@Override
public boolean supportsActivityTabs() {
return supportsActivityTracking();
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 c58b6e0bb..fde5a3f18 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/DeviceCoordinator.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/DeviceCoordinator.java
@@ -52,6 +52,8 @@ import nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryParser;
import nodomain.freeyourgadget.gadgetbridge.model.BatteryConfig;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
import nodomain.freeyourgadget.gadgetbridge.model.HeartRateSample;
+import nodomain.freeyourgadget.gadgetbridge.model.HrvSummarySample;
+import nodomain.freeyourgadget.gadgetbridge.model.HrvValueSample;
import nodomain.freeyourgadget.gadgetbridge.model.PaiSample;
import nodomain.freeyourgadget.gadgetbridge.model.SleepRespiratoryRateSample;
import nodomain.freeyourgadget.gadgetbridge.model.Spo2Sample;
@@ -214,6 +216,8 @@ public interface DeviceCoordinator {
*/
boolean supportsStressMeasurement();
+ boolean supportsHrvMeasurement();
+
boolean supportsSleepMeasurement();
boolean supportsStepCounter();
boolean supportsSpeedzones();
@@ -283,6 +287,16 @@ public interface DeviceCoordinator {
*/
TimeSampleProvider extends StressSample> getStressSampleProvider(GBDevice device, DaoSession session);
+ /**
+ * Returns the sample provider for HRV summary, for the device being supported.
+ */
+ TimeSampleProvider extends HrvSummarySample> getHrvSummarySampleProvider(GBDevice device, DaoSession session);
+
+ /**
+ * Returns the sample provider for HRV values, for the device being supported.
+ */
+ TimeSampleProvider extends HrvValueSample> getHrvValueSampleProvider(GBDevice device, DaoSession session);
+
/**
* Returns the stress ranges (relaxed, mild, moderate, high), so that stress can be categorized.
*/
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 ffe959c2c..546ca95f6 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
@@ -24,6 +24,8 @@ import nodomain.freeyourgadget.gadgetbridge.entities.GarminSpo2SampleDao;
import nodomain.freeyourgadget.gadgetbridge.entities.GarminStressSampleDao;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
+import nodomain.freeyourgadget.gadgetbridge.model.HrvSummarySample;
+import nodomain.freeyourgadget.gadgetbridge.model.HrvValueSample;
import nodomain.freeyourgadget.gadgetbridge.model.Spo2Sample;
import nodomain.freeyourgadget.gadgetbridge.model.StressSample;
import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport;
@@ -96,6 +98,16 @@ public abstract class GarminCoordinator extends AbstractBLEDeviceCoordinator {
return new GarminStressSampleProvider(device, session);
}
+ @Override
+ public TimeSampleProvider extends HrvSummarySample> getHrvSummarySampleProvider(final GBDevice device, final DaoSession session) {
+ return new GarminHrvSummarySampleProvider(device, session);
+ }
+
+ @Override
+ public TimeSampleProvider extends HrvValueSample> getHrvValueSampleProvider(final GBDevice device, final DaoSession session) {
+ return new GarminHrvValueSampleProvider(device, session);
+ }
+
@Override
public TimeSampleProvider extends Spo2Sample> getSpo2SampleProvider(final GBDevice device, final DaoSession session) {
return new GarminSpo2SampleProvider(device, session);
@@ -162,6 +174,11 @@ public abstract class GarminCoordinator extends AbstractBLEDeviceCoordinator {
return true;
}
+ @Override
+ public boolean supportsHrvMeasurement() {
+ return true;
+ }
+
@Override
public int[] getStressRanges() {
// 1-25 = relaxed
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/garmin/GarminHrvSummarySampleProvider.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/garmin/GarminHrvSummarySampleProvider.java
new file mode 100644
index 000000000..90537472c
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/garmin/GarminHrvSummarySampleProvider.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.GarminHrvSummarySample;
+import nodomain.freeyourgadget.gadgetbridge.entities.GarminHrvSummarySampleDao;
+import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
+
+public class GarminHrvSummarySampleProvider extends AbstractTimeSampleProvider {
+ public GarminHrvSummarySampleProvider(final GBDevice device, final DaoSession session) {
+ super(device, session);
+ }
+
+ @NonNull
+ @Override
+ public AbstractDao getSampleDao() {
+ return getSession().getGarminHrvSummarySampleDao();
+ }
+
+ @NonNull
+ @Override
+ protected Property getTimestampSampleProperty() {
+ return GarminHrvSummarySampleDao.Properties.Timestamp;
+ }
+
+ @NonNull
+ @Override
+ protected Property getDeviceIdentifierSampleProperty() {
+ return GarminHrvSummarySampleDao.Properties.DeviceId;
+ }
+
+ @Override
+ public GarminHrvSummarySample createSample() {
+ return new GarminHrvSummarySample();
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/garmin/GarminHrvValueSampleProvider.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/garmin/GarminHrvValueSampleProvider.java
new file mode 100644
index 000000000..de6d88b10
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/garmin/GarminHrvValueSampleProvider.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.GarminHrvValueSample;
+import nodomain.freeyourgadget.gadgetbridge.entities.GarminHrvValueSampleDao;
+import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
+
+public class GarminHrvValueSampleProvider extends AbstractTimeSampleProvider {
+ public GarminHrvValueSampleProvider(final GBDevice device, final DaoSession session) {
+ super(device, session);
+ }
+
+ @NonNull
+ @Override
+ public AbstractDao getSampleDao() {
+ return getSession().getGarminHrvValueSampleDao();
+ }
+
+ @NonNull
+ @Override
+ protected Property getTimestampSampleProperty() {
+ return GarminHrvValueSampleDao.Properties.Timestamp;
+ }
+
+ @NonNull
+ @Override
+ protected Property getDeviceIdentifierSampleProperty() {
+ return GarminHrvValueSampleDao.Properties.DeviceId;
+ }
+
+ @Override
+ public GarminHrvValueSample createSample() {
+ return new GarminHrvValueSample();
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/entities/AbstractHrvSummarySample.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/entities/AbstractHrvSummarySample.java
new file mode 100644
index 000000000..1c4ba5637
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/entities/AbstractHrvSummarySample.java
@@ -0,0 +1,50 @@
+/* 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.entities;
+
+import androidx.annotation.NonNull;
+
+import nodomain.freeyourgadget.gadgetbridge.model.HrvSummarySample;
+import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
+
+public abstract class AbstractHrvSummarySample extends AbstractTimeSample implements HrvSummarySample {
+ public Integer getStatusNum() {
+ return Status.NONE.getNum();
+ }
+
+ @Override
+ public Status getStatus() {
+ return Status.fromNum(getStatusNum());
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "{" +
+ "timestamp=" + DateTimeUtils.formatDateTime(DateTimeUtils.parseTimestampMillis(getTimestamp())) +
+ ", weeklyAverage=" + getWeeklyAverage() +
+ ", lastNightAverage=" + getLastNightAverage() +
+ ", lastNight5MinHigh=" + getLastNight5MinHigh() +
+ ", baselineLowUpper=" + getBaselineLowUpper() +
+ ", baselineBalancedLower=" + getBaselineBalancedLower() +
+ ", baselineBalancedUpper=" + getBaselineBalancedUpper() +
+ ", status=" + getStatus() +
+ ", userId=" + getUserId() +
+ ", deviceId=" + getDeviceId() +
+ "}";
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/entities/AbstractHrvValueSample.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/entities/AbstractHrvValueSample.java
new file mode 100644
index 000000000..8e80e94ad
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/entities/AbstractHrvValueSample.java
@@ -0,0 +1,35 @@
+/* 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.entities;
+
+import androidx.annotation.NonNull;
+
+import nodomain.freeyourgadget.gadgetbridge.model.HrvValueSample;
+import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
+
+public abstract class AbstractHrvValueSample extends AbstractTimeSample implements HrvValueSample {
+ @NonNull
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "{" +
+ "timestamp=" + DateTimeUtils.formatDateTime(DateTimeUtils.parseTimestampMillis(getTimestamp())) +
+ ", value=" + getValue() +
+ ", userId=" + getUserId() +
+ ", deviceId=" + getDeviceId() +
+ "}";
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/HrvSummarySample.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/HrvSummarySample.java
new file mode 100644
index 000000000..82a9d17f3
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/HrvSummarySample.java
@@ -0,0 +1,80 @@
+/* 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.model;
+
+public interface HrvSummarySample extends TimeSample {
+ enum Status {
+ NONE(0),
+ POOR(1),
+ LOW(2),
+ UNBALANCED(3),
+ BALANCED(4),
+ ;
+
+ private final int num;
+
+ Status(final int num) {
+ this.num = num;
+ }
+
+ public int getNum() {
+ return num;
+ }
+
+ public static Status fromNum(final int num) {
+ for (Status value : Status.values()) {
+ if (value.getNum() == num) {
+ return value;
+ }
+ }
+
+ throw new IllegalArgumentException("Unknown hrv status num " + num);
+ }
+ }
+
+ /**
+ * Weekly average, in milliseconds.
+ */
+ Integer getWeeklyAverage();
+
+ /**
+ * Last night average, in milliseconds.
+ */
+ Integer getLastNightAverage();
+
+ /**
+ * Last night 5-min high, in milliseconds.
+ */
+ Integer getLastNight5MinHigh();
+
+ /**
+ * Baseline low upper, in milliseconds.
+ */
+ Integer getBaselineLowUpper();
+
+ /**
+ * Baseline balanced lower, in milliseconds.
+ */
+ Integer getBaselineBalancedLower();
+
+ /**
+ * Baseline balanced upper, in milliseconds.
+ */
+ Integer getBaselineBalancedUpper();
+
+ Status getStatus();
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/HrvValueSample.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/HrvValueSample.java
new file mode 100644
index 000000000..153c70b2a
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/HrvValueSample.java
@@ -0,0 +1,24 @@
+/* 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.model;
+
+public interface HrvValueSample extends TimeSample {
+ /**
+ * HRV value, in milliseconds.
+ */
+ int getValue();
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/FieldDefinitionFactory.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/FieldDefinitionFactory.java
index 497d3c637..640a95d0c 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/FieldDefinitionFactory.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/FieldDefinitionFactory.java
@@ -6,6 +6,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefi
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionFileType;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionGoalSource;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionGoalType;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionHrvStatus;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionLanguage;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionMeasurementSystem;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionSleepStage;
@@ -30,6 +31,8 @@ public class FieldDefinitionFactory {
return new FieldDefinitionGoalSource(localNumber, size, baseType, name);
case GOAL_TYPE:
return new FieldDefinitionGoalType(localNumber, size, baseType, name);
+ case HRV_STATUS:
+ return new FieldDefinitionHrvStatus(localNumber, size, baseType, name);
case MEASUREMENT_SYSTEM:
return new FieldDefinitionMeasurementSystem(localNumber, size, baseType, name);
case TEMPERATURE:
@@ -55,6 +58,7 @@ public class FieldDefinitionFactory {
FILE_TYPE,
GOAL_SOURCE,
GOAL_TYPE,
+ HRV_STATUS,
MEASUREMENT_SYSTEM,
TEMPERATURE,
TIMESTAMP,
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 36e6edf4c..dec55c37c 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
@@ -32,6 +32,8 @@ import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminActivitySampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminEventSampleProvider;
+import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminHrvSummarySampleProvider;
+import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminHrvValueSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminSleepStageSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminSpo2SampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminStressSampleProvider;
@@ -40,6 +42,8 @@ import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
import nodomain.freeyourgadget.gadgetbridge.entities.GarminActivitySample;
import nodomain.freeyourgadget.gadgetbridge.entities.GarminEventSample;
+import nodomain.freeyourgadget.gadgetbridge.entities.GarminHrvSummarySample;
+import nodomain.freeyourgadget.gadgetbridge.entities.GarminHrvValueSample;
import nodomain.freeyourgadget.gadgetbridge.entities.GarminSleepStageSample;
import nodomain.freeyourgadget.gadgetbridge.entities.GarminSpo2Sample;
import nodomain.freeyourgadget.gadgetbridge.entities.GarminStressSample;
@@ -51,9 +55,12 @@ import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryData;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.GarminTimeUtils;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.enums.GarminSport;
+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.messages.FitEvent;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitFileId;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitHrvSummary;
+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.FitRecord;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitSession;
@@ -75,6 +82,8 @@ public class FitImporter {
private final List spo2samples = new ArrayList<>();
private final List events = new ArrayList<>();
private final List sleepStageSamples = new ArrayList<>();
+ private final List hrvSummarySamples = new ArrayList<>();
+ private final List hrvValueSamples = new ArrayList<>();
private final List timesInZone = new ArrayList<>();
private final List activityPoints = new ArrayList<>();
private final Map unknownRecords = new HashMap<>();
@@ -179,6 +188,34 @@ public class FitImporter {
} else if (record instanceof FitTimeInZone) {
LOG.trace("Time in zone: {}", record);
timesInZone.add((FitTimeInZone) record);
+ } else if (record instanceof FitHrvSummary) {
+ final FitHrvSummary hrvSummary = (FitHrvSummary) record;
+ final FieldDefinitionHrvStatus.HrvStatus status = hrvSummary.getStatus();
+ if (status == null) {
+ continue;
+ }
+ LOG.trace("HRV summary at {}: {}", ts, record);
+ final GarminHrvSummarySample sample = new GarminHrvSummarySample( );
+ sample.setTimestamp(ts * 1000L);
+ sample.setWeeklyAverage(hrvSummary.getWeeklyAverage());
+ sample.setLastNightAverage(hrvSummary.getLastNightAverage());
+ sample.setLastNight5MinHigh(hrvSummary.getLastNight5MinHigh());
+ sample.setBaselineLowUpper(hrvSummary.getBaselineLowUpper());
+ sample.setBaselineBalancedLower(hrvSummary.getBaselineBalancedLower());
+ sample.setBaselineBalancedUpper(hrvSummary.getBaselineBalancedUpper());
+ sample.setStatusNum(status.getId());
+ hrvSummarySamples.add(sample);
+ } else if (record instanceof FitHrvValue) {
+ final FitHrvValue hrvValue = (FitHrvValue) record;
+ if (hrvValue.getValue() == null) {
+ LOG.warn("HRV value at {} is null", ts);
+ continue;
+ }
+ LOG.trace("HRV value at {}: {}", ts, hrvValue.getValue());
+ final GarminHrvValueSample sample = new GarminHrvValueSample();
+ sample.setTimestamp(ts * 1000L);
+ sample.setValue(hrvValue.getValue());
+ hrvValueSamples.add(sample);
} else {
LOG.trace("Unknown record: {}", record);
@@ -202,18 +239,22 @@ public class FitImporter {
}
switch (fileId.getType()) {
- case activity:
+ case ACTIVITY:
persistWorkout(file);
break;
- case monitor:
+ case MONITOR:
persistActivitySamples();
persistSpo2Samples();
persistStressSamples();
break;
- case sleep:
+ case SLEEP:
persistEvents();
persistSleepStageSamples();
break;
+ case HRV_STATUS:
+ persistHrvSummarySamples();
+ persistHrvValueSamples();
+ break;
default:
LOG.warn("Unable to handle fit file of type {}", fileId.getType());
}
@@ -512,6 +553,58 @@ public class FitImporter {
}
}
+ private void persistHrvSummarySamples() {
+ if (hrvSummarySamples.isEmpty()) {
+ return;
+ }
+
+ LOG.debug("Will persist {} HRV summary samples", hrvSummarySamples.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 GarminHrvSummarySampleProvider sampleProvider = new GarminHrvSummarySampleProvider(gbDevice, session);
+
+ for (final GarminHrvSummarySample sample : hrvSummarySamples) {
+ sample.setDevice(device);
+ sample.setUser(user);
+ }
+
+ sampleProvider.addSamples(hrvSummarySamples);
+ } catch (final Exception e) {
+ GB.toast(context, "Error saving HRV summary samples", Toast.LENGTH_LONG, GB.ERROR, e);
+ }
+ }
+
+ private void persistHrvValueSamples() {
+ if (hrvValueSamples.isEmpty()) {
+ return;
+ }
+
+ LOG.debug("Will persist {} HRV value samples", hrvValueSamples.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 GarminHrvValueSampleProvider sampleProvider = new GarminHrvValueSampleProvider(gbDevice, session);
+
+ for (final GarminHrvValueSample sample : hrvValueSamples) {
+ sample.setDevice(device);
+ sample.setUser(user);
+ }
+
+ sampleProvider.addSamples(hrvValueSamples);
+ } catch (final Exception e) {
+ GB.toast(context, "Error saving HRV value samples", Toast.LENGTH_LONG, GB.ERROR, e);
+ }
+ }
+
private void persistSpo2Samples() {
if (spo2samples.isEmpty()) {
return;
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/GlobalFITMessage.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/GlobalFITMessage.java
index ce021ccf0..4399745ce 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/GlobalFITMessage.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/GlobalFITMessage.java
@@ -253,6 +253,22 @@ public class GlobalFITMessage {
public static GlobalFITMessage SLEEP_STATS = new GlobalFITMessage(346, "SLEEP_STATS", Arrays.asList(
));
+ public static GlobalFITMessage HRV_SUMMARY = new GlobalFITMessage(370, "HRV_SUMMARY", Arrays.asList(
+ new FieldDefinitionPrimitive(0, BaseType.UINT16, "weekly_average", 128, 0), // milliseconds, scaled by 128
+ new FieldDefinitionPrimitive(1, BaseType.UINT16, "last_night_average", 128, 0), // milliseconds, scaled by 128
+ new FieldDefinitionPrimitive(2, BaseType.UINT16, "last_night_5_min_high", 128, 0), // milliseconds, scaled by 128
+ new FieldDefinitionPrimitive(3, BaseType.UINT16, "baseline_low_upper", 128, 0), // milliseconds, scaled by 128
+ new FieldDefinitionPrimitive(4, BaseType.UINT16, "baseline_balanced_lower", 128, 0), // milliseconds, scaled by 128
+ new FieldDefinitionPrimitive(5, BaseType.UINT16, "baseline_balanced_upper", 128, 0), // milliseconds, scaled by 128
+ new FieldDefinitionPrimitive(6, BaseType.ENUM, "status", FieldDefinitionFactory.FIELD.HRV_STATUS),
+ new FieldDefinitionPrimitive(253, BaseType.UINT32, "timestamp", FieldDefinitionFactory.FIELD.TIMESTAMP)
+ ));
+
+ public static GlobalFITMessage HRV_VALUE = new GlobalFITMessage(371, "HRV_VALUE", Arrays.asList(
+ new FieldDefinitionPrimitive(0, BaseType.UINT16, "value", 128, 0), // milliseconds, scaled by 128
+ new FieldDefinitionPrimitive(253, BaseType.UINT32, "timestamp", FieldDefinitionFactory.FIELD.TIMESTAMP)
+ ));
+
public static Map KNOWN_MESSAGES = new HashMap() {{
put(0, FILE_ID);
put(2, DEVICE_SETTINGS);
@@ -280,6 +296,8 @@ public class GlobalFITMessage {
put(275, SLEEP_STAGE);
put(297, RESPIRATION_RATE);
put(346, SLEEP_STATS);
+ put(370, HRV_SUMMARY);
+ put(371, HRV_VALUE);
}};
private final int number;
private final String name;
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/codegen/FitCodeGen.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/codegen/FitCodeGen.java
index a3caa5d34..e324bea48 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/codegen/FitCodeGen.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/codegen/FitCodeGen.java
@@ -22,13 +22,14 @@ import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.FileType;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.GlobalFITMessage;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordData;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordDefinition;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordHeader;
-import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionFileType;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionGoalSource;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionGoalType;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionHrvStatus;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionLanguage;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionMeasurementSystem;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionSleepStage;
@@ -230,11 +231,13 @@ public class FitCodeGen {
case DAY_OF_WEEK:
return DayOfWeek.class;
case FILE_TYPE:
- return FieldDefinitionFileType.Type.class;
+ return FileType.FILETYPE.class;
case GOAL_SOURCE:
return FieldDefinitionGoalSource.Source.class;
case GOAL_TYPE:
return FieldDefinitionGoalType.Type.class;
+ case HRV_STATUS:
+ return FieldDefinitionHrvStatus.HrvStatus.class;
case MEASUREMENT_SYSTEM:
return FieldDefinitionMeasurementSystem.Type.class;
case TEMPERATURE:
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/fieldDefinitions/FieldDefinitionFileType.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/fieldDefinitions/FieldDefinitionFileType.java
index d443647b7..2d21453b6 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/fieldDefinitions/FieldDefinitionFileType.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/fieldDefinitions/FieldDefinitionFileType.java
@@ -1,9 +1,8 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions;
-import androidx.annotation.Nullable;
-
import java.nio.ByteBuffer;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.FileType;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.FieldDefinition;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.baseTypes.BaseType;
@@ -16,47 +15,16 @@ public class FieldDefinitionFileType extends FieldDefinition {
@Override
public Object decode(ByteBuffer byteBuffer) {
int raw = (int) baseType.decode(byteBuffer, scale, offset);
- return Type.fromId(raw) == null ? raw : Type.fromId(raw);
+ final FileType.FILETYPE fileType = FileType.FILETYPE.fromDataTypeSubType(128, raw);
+ return fileType == null ? raw : fileType;
}
@Override
public void encode(ByteBuffer byteBuffer, Object o) {
- if (o instanceof Type) {
- baseType.encode(byteBuffer, (((Type) o).getId()), scale, offset);
+ if (o instanceof FileType.FILETYPE) {
+ baseType.encode(byteBuffer, (((FileType.FILETYPE) o).getSubType()), scale, offset);
return;
}
baseType.encode(byteBuffer, o, scale, offset);
}
-
- public enum Type {
- settings(2),
- activity(4), //FIT_TYPE_4 stands for activity directory
- goals(11),
- monitor(32), //FIT_TYPE_32
- changelog(41), // FIT_TYPE_41 stands for changelog directory
- metrics(44), //FIT_TYPE_41
- sleep(49), //FIT_TYPE_49
- ;
-
- private final int id;
-
- Type(int i) {
- this.id = i;
- }
-
- @Nullable
- public static Type fromId(int id) {
- for (Type type :
- Type.values()) {
- if (id == type.getId()) {
- return type;
- }
- }
- return null;
- }
-
- public int getId() {
- return this.id;
- }
- }
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/fieldDefinitions/FieldDefinitionHrvStatus.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/fieldDefinitions/FieldDefinitionHrvStatus.java
new file mode 100644
index 000000000..459154c65
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/fieldDefinitions/FieldDefinitionHrvStatus.java
@@ -0,0 +1,58 @@
+package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions;
+
+import androidx.annotation.Nullable;
+
+import java.nio.ByteBuffer;
+
+import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.FieldDefinition;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.baseTypes.BaseType;
+
+public class FieldDefinitionHrvStatus extends FieldDefinition {
+ public FieldDefinitionHrvStatus(final int localNumber, final int size, final BaseType baseType, final String name) {
+ super(localNumber, size, baseType, name, 1, 0);
+ }
+
+ @Override
+ public Object decode(final ByteBuffer byteBuffer) {
+ final int raw = (int) baseType.decode(byteBuffer, scale, offset);
+ return HrvStatus.fromId(raw);
+ }
+
+ @Override
+ public void encode(final ByteBuffer byteBuffer, final Object o) {
+ if (o instanceof HrvStatus) {
+ baseType.encode(byteBuffer, (((HrvStatus) o).getId()), scale, offset);
+ return;
+ }
+ baseType.encode(byteBuffer, o, scale, offset);
+ }
+
+ public enum HrvStatus {
+ NONE(0),
+ POOR(1),
+ LOW(2),
+ UNBALANCED(3),
+ BALANCED(4),
+ ;
+
+ private final int id;
+
+ HrvStatus(final int i) {
+ id = i;
+ }
+
+ @Nullable
+ public static HrvStatus fromId(final int id) {
+ for (HrvStatus stage : HrvStatus.values()) {
+ if (id == stage.getId()) {
+ return stage;
+ }
+ }
+ return null;
+ }
+
+ public int getId() {
+ return id;
+ }
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitFileId.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitFileId.java
index 191e658fb..01c89058d 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitFileId.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitFileId.java
@@ -2,10 +2,10 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages
import androidx.annotation.Nullable;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.FileType.FILETYPE;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordData;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordDefinition;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordHeader;
-import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionFileType.Type;
//
// WARNING: This class was auto-generated, please avoid modifying it directly.
@@ -22,8 +22,8 @@ public class FitFileId extends RecordData {
}
@Nullable
- public Type getType() {
- return (Type) getFieldByNumber(0);
+ public FILETYPE getType() {
+ return (FILETYPE) getFieldByNumber(0);
}
@Nullable
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitHrvSummary.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitHrvSummary.java
new file mode 100644
index 000000000..ea6023428
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitHrvSummary.java
@@ -0,0 +1,63 @@
+package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages;
+
+import androidx.annotation.Nullable;
+
+import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordData;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordDefinition;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordHeader;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionHrvStatus.HrvStatus;
+
+//
+// WARNING: This class was auto-generated, please avoid modifying it directly.
+// See nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.codegen.FitCodeGen
+//
+public class FitHrvSummary extends RecordData {
+ public FitHrvSummary(final RecordDefinition recordDefinition, final RecordHeader recordHeader) {
+ super(recordDefinition, recordHeader);
+
+ final int globalNumber = recordDefinition.getGlobalFITMessage().getNumber();
+ if (globalNumber != 370) {
+ throw new IllegalArgumentException("FitHrvSummary expects global messages of " + 370 + ", got " + globalNumber);
+ }
+ }
+
+ @Nullable
+ public Integer getWeeklyAverage() {
+ return (Integer) getFieldByNumber(0);
+ }
+
+ @Nullable
+ public Integer getLastNightAverage() {
+ return (Integer) getFieldByNumber(1);
+ }
+
+ @Nullable
+ public Integer getLastNight5MinHigh() {
+ return (Integer) getFieldByNumber(2);
+ }
+
+ @Nullable
+ public Integer getBaselineLowUpper() {
+ return (Integer) getFieldByNumber(3);
+ }
+
+ @Nullable
+ public Integer getBaselineBalancedLower() {
+ return (Integer) getFieldByNumber(4);
+ }
+
+ @Nullable
+ public Integer getBaselineBalancedUpper() {
+ return (Integer) getFieldByNumber(5);
+ }
+
+ @Nullable
+ public HrvStatus getStatus() {
+ return (HrvStatus) getFieldByNumber(6);
+ }
+
+ @Nullable
+ public Long getTimestamp() {
+ return (Long) getFieldByNumber(253);
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitHrvValue.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitHrvValue.java
new file mode 100644
index 000000000..c04d3a57b
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitHrvValue.java
@@ -0,0 +1,32 @@
+package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages;
+
+import androidx.annotation.Nullable;
+
+import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordData;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordDefinition;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordHeader;
+
+//
+// WARNING: This class was auto-generated, please avoid modifying it directly.
+// See nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.codegen.FitCodeGen
+//
+public class FitHrvValue extends RecordData {
+ public FitHrvValue(final RecordDefinition recordDefinition, final RecordHeader recordHeader) {
+ super(recordDefinition, recordHeader);
+
+ final int globalNumber = recordDefinition.getGlobalFITMessage().getNumber();
+ if (globalNumber != 371) {
+ throw new IllegalArgumentException("FitHrvValue expects global messages of " + 371 + ", got " + globalNumber);
+ }
+ }
+
+ @Nullable
+ public Integer getValue() {
+ return (Integer) getFieldByNumber(0);
+ }
+
+ @Nullable
+ public Long getTimestamp() {
+ return (Long) getFieldByNumber(253);
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitRecordDataFactory.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitRecordDataFactory.java
index 2ee6b976b..0ce3b1821 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitRecordDataFactory.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitRecordDataFactory.java
@@ -67,6 +67,10 @@ public class FitRecordDataFactory {
return new FitRespirationRate(recordDefinition, recordHeader);
case 346:
return new FitSleepStats(recordDefinition, recordHeader);
+ case 370:
+ return new FitHrvSummary(recordDefinition, recordHeader);
+ case 371:
+ return new FitHrvValue(recordDefinition, recordHeader);
}
return new RecordData(recordDefinition, recordHeader);