Garmin Vivomove HR support

- communication protocols
- device support implementation
- download FIT file storage

Features:
- basic connectivity: time sync, battery status, HW/FW version info
- real-time activity tracking
- fitness data sync
- find the device, find the phone
- factory reset

Features implemented but not working:
- notifications: fully implemented, seem to communicate correctly, but not shown on watch

Features implemented partially (not expected to work now):
- weather information (and in future possibly weather alerts)
- music info
- firmware update: only the initial file upload implemented, not used

Things to improve/change:
- Device name hardcoded in `VivomoveHrCoordinator.getSupportedType`, service UUIDs not available
- Download FIT file storage: Should be store (and offer the user to export?) the FIT data forever?
- Obviously, various code improvements, cleanup, etc.
This commit is contained in:
Mormegil
2023-07-20 20:30:14 +00:00
committed by José Rebelo
parent 114f6fcbf0
commit 3a58314db6
112 changed files with 6998 additions and 11 deletions
@@ -92,6 +92,7 @@ public class GBDaoGenerator {
addPineTimeActivitySample(schema, user, device);
addHybridHRActivitySample(schema, user, device);
addVivomoveHrActivitySample(schema, user, device);
addDownloadedFitFile(schema, user, device);
addCalendarSyncState(schema, device);
addAlarms(schema, user, device);
@@ -475,6 +476,35 @@ public class GBDaoGenerator {
return activitySample;
}
private static Entity addDownloadedFitFile(Schema schema, Entity user, Entity device) {
final Entity downloadedFitFile = addEntity(schema, "DownloadedFitFile");
downloadedFitFile.implementsSerializable();
downloadedFitFile.setJavaDoc("This class represents a single FIT file downloaded from a FIT-compatible device.");
downloadedFitFile.addIdProperty().autoincrement();
downloadedFitFile.addLongProperty("downloadTimestamp").notNull();
final Property deviceId = downloadedFitFile.addLongProperty("deviceId").notNull().getProperty();
downloadedFitFile.addToOne(device, deviceId);
final Property userId = downloadedFitFile.addLongProperty("userId").notNull().getProperty();
downloadedFitFile.addToOne(user, userId);
final Property fileNumber = downloadedFitFile.addIntProperty("fileNumber").notNull().getProperty();
downloadedFitFile.addIntProperty("fileDataType").notNull();
downloadedFitFile.addIntProperty("fileSubType").notNull();
downloadedFitFile.addLongProperty("fileTimestamp").notNull();
downloadedFitFile.addIntProperty("specificFlags").notNull();
downloadedFitFile.addIntProperty("fileSize").notNull();
downloadedFitFile.addByteArrayProperty("fileData");
final Index indexUnique = new Index();
indexUnique.addProperty(deviceId);
indexUnique.addProperty(userId);
indexUnique.addProperty(fileNumber);
indexUnique.makeUnique();
downloadedFitFile.addIndex(indexUnique);
return downloadedFitFile;
}
private static Entity addWatchXPlusHealthActivitySample(Schema schema, Entity user, Entity device) {
Entity activitySample = addEntity(schema, "WatchXPlusActivitySample");
activitySample.implementsSerializable();