diff --git a/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java b/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java index a8b381019..dd5bde65f 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(72, MAIN_PACKAGE + ".entities"); + final Schema schema = new Schema(73, MAIN_PACKAGE + ".entities"); Entity userAttributes = addUserAttributes(schema); Entity user = addUserInfo(schema, userAttributes); @@ -1170,6 +1170,9 @@ public class GBDaoGenerator { workoutDataSample.addShortProperty("calories").notNull(); workoutDataSample.addShortProperty("cyclingPower").notNull(); + workoutDataSample.addShortProperty("frequency").notNull(); + workoutDataSample.addIntProperty("altitude"); + return workoutDataSample; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/GadgetbridgeUpdate_73.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/GadgetbridgeUpdate_73.java new file mode 100644 index 000000000..fd486c1b2 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/GadgetbridgeUpdate_73.java @@ -0,0 +1,43 @@ +/* Copyright (C) 2024 Martin.JM + + 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.database.schema; + +import android.database.sqlite.SQLiteDatabase; + +import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; +import nodomain.freeyourgadget.gadgetbridge.database.DBUpdateScript; +import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutDataSampleDao; + +public class GadgetbridgeUpdate_73 implements DBUpdateScript { + @Override + public void upgradeSchema(final SQLiteDatabase db) { + if (!DBHelper.existsColumn(HuaweiWorkoutDataSampleDao.TABLENAME, HuaweiWorkoutDataSampleDao.Properties.Frequency.columnName, db)) { + final String statement = "ALTER TABLE " + HuaweiWorkoutDataSampleDao.TABLENAME + " ADD COLUMN \"" + + HuaweiWorkoutDataSampleDao.Properties.Frequency.columnName + "\" INTEGER NOT NULL DEFAULT -1"; + db.execSQL(statement); + } + if (!DBHelper.existsColumn(HuaweiWorkoutDataSampleDao.TABLENAME, HuaweiWorkoutDataSampleDao.Properties.Altitude.columnName, db)) { + final String statement = "ALTER TABLE " + HuaweiWorkoutDataSampleDao.TABLENAME + " ADD COLUMN \"" + + HuaweiWorkoutDataSampleDao.Properties.Altitude.columnName + "\" INTEGER DEFAULT NULL"; + db.execSQL(statement); + } + } + + @Override + public void downgradeSchema(final SQLiteDatabase db) { + } +} 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 e725eb20e..74753e94e 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 @@ -241,6 +241,8 @@ public class Workout { public short calories = -1; public short cyclingPower = -1; + public short frequency = -1; + public Integer altitude = null; public int timestamp = -1; // Calculated timestamp for this data point @@ -264,6 +266,8 @@ public class Workout { ", strokeRate=" + strokeRate + ", calories=" + calories + ", cyclingPower=" + cyclingPower + + ", frequency=" + frequency + + ", altitude=" + altitude + ", timestamp=" + timestamp + '}'; } @@ -372,6 +376,9 @@ public class Workout { case 4: data.strokeRate = buf.getShort(); break; + case 5: + data.altitude = buf.getInt(); + break; case 6: // Inner data, parsing into data // TODO: function for readability? @@ -419,6 +426,9 @@ public class Workout { data.calories = buf.getShort(); break; case 8: + data.frequency = buf.getShort(); + break; + case 9: data.cyclingPower = buf.getShort(); break; default: 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 7722676a4..33a30b309 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 @@ -1515,7 +1515,9 @@ public class HuaweiSupportProvider { data.strokeRate, unknown, data.calories, - data.cyclingPower + data.cyclingPower, + data.frequency, + data.altitude ); dao.insertOrReplace(dataSample); } 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 ee552b264..d413da6af 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 @@ -108,7 +108,9 @@ public class HuaweiWorkoutGbParser { responseData.strokeRate, dataErrorHex, responseData.calories, - responseData.cyclingPower + responseData.cyclingPower, + responseData.frequency, + responseData.altitude ); dbHandler.getDaoSession().getHuaweiWorkoutDataSampleDao().insertOrReplace(dataSample); @@ -308,6 +310,13 @@ public class HuaweiWorkoutGbParser { int maxCyclingPower = 0; int cyclingPower = 0; int cyclingPowerCount = 0; + int avgAltitude = 0; + int altitudeCount = 0; + int minAltitude = 0; + int maxAltitude = 0; + Integer previousAlt = null; + int sumAltitudeUp = 0; + int sumAltitudeDown = 0; for (HuaweiWorkoutDataSample dataSample : dataSamples) { if (dataSample.getSpeed() != -1) { speed += dataSample.getSpeed(); @@ -391,6 +400,22 @@ public class HuaweiWorkoutGbParser { if (cp < minCyclingPower) minCyclingPower = cp; } + if (dataSample.getAltitude() != null) { + int alt = dataSample.getAltitude(); + avgAltitude += alt; + altitudeCount += 1; + if (alt > maxAltitude) + maxAltitude = alt; + if (alt < minAltitude) + minAltitude = alt; + if (previousAlt != null) { + if (alt > previousAlt) + sumAltitudeUp += alt - previousAlt; + else if (alt < previousAlt) + sumAltitudeDown += previousAlt - alt; + } + previousAlt = alt; + } if (dataSample.getDataErrorHex() != null) unknownData = true; } @@ -420,6 +445,8 @@ public class HuaweiWorkoutGbParser { heartRate = heartRate / heartRateCount; if (cyclingPowerCount > 0) cyclingPower = cyclingPower / cyclingPowerCount; + if (altitudeCount > 0) + avgAltitude = avgAltitude / altitudeCount; if (speedCount > 0) { JSONObject speedJson = new JSONObject(); @@ -578,6 +605,33 @@ public class HuaweiWorkoutGbParser { maxCyclingPowerJson.put("unit", ""); jsonObject.put(ActivitySummaryEntries.CYCLING_POWER_MAX, maxCyclingPowerJson); } + + if (altitudeCount > 0) { + JSONObject avgAltitudeJson = new JSONObject(); + avgAltitudeJson.put("value", avgAltitude); + avgAltitudeJson.put("unit", ""); + jsonObject.put(ActivitySummaryEntries.ALTITUDE_AVG, avgAltitudeJson); + + JSONObject minAltitudeJson = new JSONObject(); + minAltitudeJson.put("value", minAltitude); + minAltitudeJson.put("unit", ""); + jsonObject.put(ActivitySummaryEntries.ALTITUDE_MIN, minAltitudeJson); + + JSONObject maxAltitudeJson = new JSONObject(); + maxAltitudeJson.put("value", maxAltitude); + maxAltitudeJson.put("unit", ""); + jsonObject.put(ActivitySummaryEntries.ALTITUDE_MAX, maxAltitudeJson); + + JSONObject sumUpAltitudeJson = new JSONObject(); + sumUpAltitudeJson.put("value", sumAltitudeUp); + sumUpAltitudeJson.put("unit", ""); + jsonObject.put(ActivitySummaryEntries.ELEVATION_GAIN, sumUpAltitudeJson); + + JSONObject sumDownAltitudeJson = new JSONObject(); + sumDownAltitudeJson.put("value", sumAltitudeDown); + sumDownAltitudeJson.put("unit", ""); + jsonObject.put(ActivitySummaryEntries.ELEVATION_LOSS, sumDownAltitudeJson); + } } try (CloseableListIterator it = qbPace.build().listIterator()) { diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/TestWorkout.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/TestWorkout.java index d29b173de..b65934e95 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/TestWorkout.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/TestWorkout.java @@ -259,6 +259,14 @@ public class TestWorkout { byte backFootLanding2 = 0x26; byte eversionAngle2 = 0x27; + // TODO: Add: + // - swolf + // - stoke rate + // - calories + // - cycling power + // - frequency + // - altitude + ByteBuffer headerBuf = ByteBuffer.allocate(14); headerBuf.putShort(workoutNumber); headerBuf.putShort(dataNumber);