diff --git a/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java b/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java index 7a3b2e5ac..a6925c99c 100644 --- a/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java +++ b/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java @@ -54,7 +54,7 @@ public class GBDaoGenerator { public static void main(String[] args) throws Exception { - final Schema schema = new Schema(83, MAIN_PACKAGE + ".entities"); + final Schema schema = new Schema(84, MAIN_PACKAGE + ".entities"); Entity userAttributes = addUserAttributes(schema); Entity user = addUserInfo(schema, userAttributes); @@ -1372,6 +1372,21 @@ public class GBDaoGenerator { workoutSummary.addStringProperty("gpxFileLocation"); + workoutSummary.addIntProperty("maxAltitude"); + workoutSummary.addIntProperty("minAltitude"); + workoutSummary.addIntProperty("elevationGain"); + workoutSummary.addIntProperty("elevationLoss"); + + workoutSummary.addIntProperty("workoutLoad").notNull(); + workoutSummary.addIntProperty("workoutAerobicEffect").notNull(); + workoutSummary.addByteProperty("workoutAnaerobicEffect").notNull(); + workoutSummary.addShortProperty("recoveryTime").notNull(); + + workoutSummary.addByteProperty("minHeartRatePeak").notNull(); + workoutSummary.addByteProperty("maxHeartRatePeak").notNull(); + + workoutSummary.addByteArrayProperty("recoveryHeartRates"); + return workoutSummary; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/GadgetbridgeUpdate_84.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/GadgetbridgeUpdate_84.java new file mode 100644 index 000000000..22ffd9f5c --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/GadgetbridgeUpdate_84.java @@ -0,0 +1,79 @@ +package nodomain.freeyourgadget.gadgetbridge.database.schema; + +import android.database.sqlite.SQLiteDatabase; + +import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; +import nodomain.freeyourgadget.gadgetbridge.database.DBUpdateScript; +import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSummarySampleDao; + +public class GadgetbridgeUpdate_84 implements DBUpdateScript { + @Override + public void upgradeSchema(final SQLiteDatabase db) { + if (!DBHelper.existsColumn(HuaweiWorkoutSummarySampleDao.TABLENAME, HuaweiWorkoutSummarySampleDao.Properties.MaxAltitude.columnName, db)) { + final String statement = "ALTER TABLE " + HuaweiWorkoutSummarySampleDao.TABLENAME + " ADD COLUMN \"" + + HuaweiWorkoutSummarySampleDao.Properties.MaxAltitude.columnName + "\" INTEGER"; + db.execSQL(statement); + } + + if (!DBHelper.existsColumn(HuaweiWorkoutSummarySampleDao.TABLENAME, HuaweiWorkoutSummarySampleDao.Properties.MinAltitude.columnName, db)) { + final String statement = "ALTER TABLE " + HuaweiWorkoutSummarySampleDao.TABLENAME + " ADD COLUMN \"" + + HuaweiWorkoutSummarySampleDao.Properties.MinAltitude.columnName + "\" INTEGER"; + db.execSQL(statement); + } + + if (!DBHelper.existsColumn(HuaweiWorkoutSummarySampleDao.TABLENAME, HuaweiWorkoutSummarySampleDao.Properties.ElevationGain.columnName, db)) { + final String statement = "ALTER TABLE " + HuaweiWorkoutSummarySampleDao.TABLENAME + " ADD COLUMN \"" + + HuaweiWorkoutSummarySampleDao.Properties.ElevationGain.columnName + "\" INTEGER"; + db.execSQL(statement); + } + + if (!DBHelper.existsColumn(HuaweiWorkoutSummarySampleDao.TABLENAME, HuaweiWorkoutSummarySampleDao.Properties.ElevationLoss.columnName, db)) { + final String statement = "ALTER TABLE " + HuaweiWorkoutSummarySampleDao.TABLENAME + " ADD COLUMN \"" + + HuaweiWorkoutSummarySampleDao.Properties.ElevationLoss.columnName + "\" INTEGER"; + db.execSQL(statement); + } + + if (!DBHelper.existsColumn(HuaweiWorkoutSummarySampleDao.TABLENAME, HuaweiWorkoutSummarySampleDao.Properties.WorkoutLoad.columnName, db)) { + final String statement = "ALTER TABLE " + HuaweiWorkoutSummarySampleDao.TABLENAME + " ADD COLUMN \"" + + HuaweiWorkoutSummarySampleDao.Properties.WorkoutLoad.columnName + "\" INTEGER NOT NULL DEFAULT 0;"; + db.execSQL(statement); + } + if (!DBHelper.existsColumn(HuaweiWorkoutSummarySampleDao.TABLENAME, HuaweiWorkoutSummarySampleDao.Properties.WorkoutAerobicEffect.columnName, db)) { + final String statement = "ALTER TABLE " + HuaweiWorkoutSummarySampleDao.TABLENAME + " ADD COLUMN \"" + + HuaweiWorkoutSummarySampleDao.Properties.WorkoutAerobicEffect.columnName + "\" INTEGER NOT NULL DEFAULT 0;"; + db.execSQL(statement); + } + if (!DBHelper.existsColumn(HuaweiWorkoutSummarySampleDao.TABLENAME, HuaweiWorkoutSummarySampleDao.Properties.WorkoutAnaerobicEffect.columnName, db)) { + final String statement = "ALTER TABLE " + HuaweiWorkoutSummarySampleDao.TABLENAME + " ADD COLUMN \"" + + HuaweiWorkoutSummarySampleDao.Properties.WorkoutAnaerobicEffect.columnName + "\" INTEGER NOT NULL DEFAULT -1;"; + db.execSQL(statement); + } + if (!DBHelper.existsColumn(HuaweiWorkoutSummarySampleDao.TABLENAME, HuaweiWorkoutSummarySampleDao.Properties.RecoveryTime.columnName, db)) { + final String statement = "ALTER TABLE " + HuaweiWorkoutSummarySampleDao.TABLENAME + " ADD COLUMN \"" + + HuaweiWorkoutSummarySampleDao.Properties.RecoveryTime.columnName + "\" INTEGER NOT NULL DEFAULT 0;"; + db.execSQL(statement); + } + + if (!DBHelper.existsColumn(HuaweiWorkoutSummarySampleDao.TABLENAME, HuaweiWorkoutSummarySampleDao.Properties.MinHeartRatePeak.columnName, db)) { + final String statement = "ALTER TABLE " + HuaweiWorkoutSummarySampleDao.TABLENAME + " ADD COLUMN \"" + + HuaweiWorkoutSummarySampleDao.Properties.MinHeartRatePeak.columnName + "\" INTEGER NOT NULL DEFAULT 0;"; + db.execSQL(statement); + } + + if (!DBHelper.existsColumn(HuaweiWorkoutSummarySampleDao.TABLENAME, HuaweiWorkoutSummarySampleDao.Properties.MaxHeartRatePeak.columnName, db)) { + final String statement = "ALTER TABLE " + HuaweiWorkoutSummarySampleDao.TABLENAME + " ADD COLUMN \"" + + HuaweiWorkoutSummarySampleDao.Properties.MaxHeartRatePeak.columnName + "\" INTEGER NOT NULL DEFAULT 0;"; + db.execSQL(statement); + } + + if (!DBHelper.existsColumn(HuaweiWorkoutSummarySampleDao.TABLENAME, HuaweiWorkoutSummarySampleDao.Properties.RecoveryHeartRates.columnName, db)) { + final String statement = "ALTER TABLE " + HuaweiWorkoutSummarySampleDao.TABLENAME + " ADD COLUMN \"" + + HuaweiWorkoutSummarySampleDao.Properties.RecoveryHeartRates.columnName + "\" BLOB"; + db.execSQL(statement); + } + } + + @Override + public void downgradeSchema(final SQLiteDatabase db) { + } +} \ No newline at end of file diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/Workout.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/Workout.java index 1ed3e6dfb..b0879026a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/Workout.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/Workout.java @@ -128,6 +128,22 @@ public class Workout { public short laps = -1; public short avgSwolf = -1; + public Integer maxAltitude = null; + public Integer minAltitude = null; + public Integer elevationGain = null; + public Integer elevationLoss = null; + + public int workoutLoad = 0; + public int workoutAerobicEffect = 0; + public byte workoutAnaerobicEffect = -1; + public short recoveryTime = 0; + + public byte minHeartRatePeak = 0; + public byte maxHeartRatePeak = 0; + + public byte[] recoveryHeartRates = null; + + public Response(ParamsProvider paramsProvider) { super(paramsProvider); } @@ -151,6 +167,19 @@ public class Workout { this.stepCount = container.getInteger(0x08); if (container.contains(0x09)) this.totalTime = container.getInteger(0x09); + if (container.contains(0x0b)) + this.elevationGain = container.getInteger(0x0b); + if (container.contains(0x0c)) { + byte[] hrData = container.getBytes(0x0c); + minHeartRatePeak = hrData[0]; + maxHeartRatePeak = hrData[1]; + } + if (container.contains(0x0d)) + this.workoutLoad = container.getInteger(0x0d); + if (container.contains(0x0e)) + this.workoutAerobicEffect = container.getInteger(0x0e); + if (container.contains(0x11)) + this.recoveryTime = container.getShort(0x11); if (container.contains(0x12)) this.duration = container.getInteger(0x12); if (container.contains(0x14)) @@ -166,6 +195,17 @@ public class Workout { this.laps = container.getShort(0x19); if (container.contains(0x1a)) this.avgSwolf = container.getShort(0x1a); + if (container.contains(0x1b)) + this.elevationLoss = container.getInteger(0x1b); + if (container.contains(0x1c)) + this.maxAltitude = container.getInteger(0x1c); + if (container.contains(0x1d)) + this.minAltitude = container.getInteger(0x1d); + if (container.contains(0x20)) + this.workoutAnaerobicEffect = container.getByte(0x20); + if (container.contains(0x66)) + this.recoveryHeartRates = container.getBytes(0x66); + } } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java index 9acb23186..a881e7061 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java @@ -1597,6 +1597,13 @@ public class HuaweiSupportProvider { else raw = StringUtils.bytesToHex(packet.rawData).getBytes(StandardCharsets.UTF_8); + + byte[] recoveryHeartRates; + if (packet.recoveryHeartRates == null) + recoveryHeartRates = null; + else + recoveryHeartRates = StringUtils.bytesToHex(packet.recoveryHeartRates).getBytes(StandardCharsets.UTF_8); + HuaweiWorkoutSummarySample summarySample = new HuaweiWorkoutSummarySample( workoutId, deviceId, @@ -1617,7 +1624,18 @@ public class HuaweiSupportProvider { packet.laps, packet.avgSwolf, raw, - null + null, + packet.maxAltitude, + packet.minAltitude, + packet.elevationGain, + packet.elevationLoss, + packet.workoutLoad, + packet.workoutAerobicEffect, + packet.workoutAnaerobicEffect, + packet.recoveryTime, + packet.minHeartRatePeak, + packet.maxHeartRatePeak, + recoveryHeartRates ); db.getDaoSession().getHuaweiWorkoutSummarySampleDao().insertOrReplace(summarySample); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiWorkoutGbParser.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiWorkoutGbParser.java index 2e98d73d9..efaf501ef 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiWorkoutGbParser.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiWorkoutGbParser.java @@ -393,6 +393,30 @@ public class HuaweiWorkoutGbParser implements ActivitySummaryParser { summaryData.add(ActivitySummaryEntries.SWOLF_AVG, summary.getAvgSwolf(), ActivitySummaryEntries.UNIT_NONE); } + if(summary.getWorkoutLoad() > 0) { + summaryData.add(ActivitySummaryEntries.WORKOUT_LOAD, summary.getWorkoutLoad(), ActivitySummaryEntries.UNIT_NONE); + } + + if(summary.getWorkoutAerobicEffect() > 0) { + summaryData.add(ActivitySummaryEntries.TRAINING_EFFECT_AEROBIC, summary.getWorkoutAerobicEffect() / 10.0, ActivitySummaryEntries.UNIT_NONE); + } + + if(summary.getWorkoutAnaerobicEffect() >= 0) { + summaryData.add(ActivitySummaryEntries.TRAINING_EFFECT_ANAEROBIC, summary.getWorkoutAnaerobicEffect() / 10.0, ActivitySummaryEntries.UNIT_NONE); + } + + if(summary.getRecoveryTime() > 0) { + summaryData.add(ActivitySummaryEntries.RECOVERY_TIME, summary.getRecoveryTime() / 60.0, ActivitySummaryEntries.UNIT_HOURS); + } + + Integer summaryMinAltitude = summary.getMinAltitude(); + Integer summaryMaxAltitude = summary.getMaxAltitude(); + Integer elevationGain = summary.getElevationGain(); + Integer elevationLoss = summary.getElevationLoss(); + + int minHeartRatePeak = summary.getMinHeartRatePeak() & 0xff; + int maxHeartRatePeak = summary.getMaxHeartRatePeak() & 0xff; + boolean unknownData = false; if (!dataSamples.isEmpty()) { int speed = 0; @@ -631,8 +655,13 @@ public class HuaweiWorkoutGbParser implements ActivitySummaryParser { if (heartRateCount > 0) { summaryData.add(ActivitySummaryEntries.HR_AVG, heartRate, ActivitySummaryEntries.UNIT_BPM); - summaryData.add(ActivitySummaryEntries.HR_MAX, maxHeartRate, ActivitySummaryEntries.UNIT_BPM); - summaryData.add(ActivitySummaryEntries.HR_MIN, minHeartRate, ActivitySummaryEntries.UNIT_BPM); + if(minHeartRatePeak == 0) { + minHeartRatePeak = minHeartRate; + } + + if(maxHeartRatePeak == 0) { + maxHeartRatePeak = maxHeartRate; + } } if (sumCalories > 0) { @@ -647,13 +676,46 @@ public class HuaweiWorkoutGbParser implements ActivitySummaryParser { if (altitudeCount > 0) { summaryData.add(ActivitySummaryEntries.ALTITUDE_AVG, avgAltitude / 10.0f, ActivitySummaryEntries.UNIT_METERS); - summaryData.add(ActivitySummaryEntries.ALTITUDE_MIN, minAltitude / 10.0f, ActivitySummaryEntries.UNIT_METERS); - summaryData.add(ActivitySummaryEntries.ALTITUDE_MAX, maxAltitude / 10.0f, ActivitySummaryEntries.UNIT_METERS); - summaryData.add(ActivitySummaryEntries.ELEVATION_GAIN, sumAltitudeUp / 10.0f, ActivitySummaryEntries.UNIT_METERS); - summaryData.add(ActivitySummaryEntries.ELEVATION_LOSS, sumAltitudeDown / 10.0f, ActivitySummaryEntries.UNIT_METERS); + + if(summaryMinAltitude == null) { + summaryMinAltitude = minAltitude; + } + + if(summaryMaxAltitude == null) { + summaryMaxAltitude = maxAltitude; + } + + if(elevationGain == null) { + elevationGain = sumAltitudeUp; + } + + if(elevationLoss == null) { + elevationLoss = sumAltitudeDown; + } } } + if (minHeartRatePeak > 0) { + summaryData.add(ActivitySummaryEntries.HR_MIN, minHeartRatePeak, ActivitySummaryEntries.UNIT_BPM); + } + if (maxHeartRatePeak > 0) { + summaryData.add(ActivitySummaryEntries.HR_MAX, maxHeartRatePeak, ActivitySummaryEntries.UNIT_BPM); + } + + if(summaryMinAltitude != null) { + summaryData.add(ActivitySummaryEntries.ALTITUDE_MIN, summaryMinAltitude / 10.0f, ActivitySummaryEntries.UNIT_METERS); + } + + if(summaryMaxAltitude != null) { + summaryData.add(ActivitySummaryEntries.ALTITUDE_MAX, summaryMaxAltitude / 10.0f, ActivitySummaryEntries.UNIT_METERS); + } + if(elevationGain != null) { + summaryData.add(ActivitySummaryEntries.ELEVATION_GAIN, elevationGain / 10.0f, ActivitySummaryEntries.UNIT_METERS); + } + if(elevationLoss != null) { + summaryData.add(ActivitySummaryEntries.ELEVATION_LOSS, elevationLoss / 10.0f, ActivitySummaryEntries.UNIT_METERS); + } + final LinkedHashMap pacesTable = new LinkedHashMap<>(); pacesTable.put("paces_table",