Summary
Add automatic dive download for the Suunto Nautic / Nautic S / Ocean, so new dives sync without the user manually connecting and tapping download. When a paired watch is in range, the app should connect, check for dives it doesn't already have, pull only the new ones, and update the log in the background.
Today the flow is manual: connect, then call retrieveDiveLogs. The pieces for automation already exist in the SDK (BLE state restoration, fingerprint-based incremental download, and the Nautic list/download primitives); this issue is about wiring them into a hands-off sync driven by device proximity and connection state.
How the official Suunto app does it (from APK analysis, com.stt.android.suunto 6.7.12)
The app talks to the watch over an MDS (Movesense Device Service) layer on top of BLE. Relevant findings:
- Dive logs live at the MDS resource
suunto://MDS/Logbook/. The dive sync itself is EonSynchronizer.syncLogbook(...) (with a retry count), part of the standard per-device sync. Nautic and Ocean are wired in as device types (SuuntoNauticCapability, SuuntoOceanCapability).
- Auto-sync is driven by
com.suunto.connectivity.sync.listener.WatchTriggeredSyncListener:
- It observes the watch connection state. On
WatchState.isConnected() becoming true it starts listening for a sync trigger and syncs.
- The watch pushes a "sync trigger" over an MDS event subscription, and there is also a periodic (hourly) trigger. When it fires, the app runs a full sync (which includes the logbook). Log line in the decompiled code: "Hourly sync triggered by the watch failed."
- The connection is kept alive / auto-reconnected: the connectivity layer has a connection state machine with a
Reconnecting state and an alarm-based reconnect refresher, so the watch stays effectively "always connected" in the background.
Net model: keep a background connection to the paired watch, sync on connect, and re-sync when the watch signals new data (or hourly). Dedup is by logbook id, so only new dives download.
What we already have in this repo
CoreBluetoothManager uses BLE state restoration (CBCentralManagerOptionRestoreIdentifierKey + willRestoreState), plus startScanning, connectToStoredDevice, and stored-device persistence. iOS can relaunch the app into the background on BLE events.
DiveLogRetriever.retrieveDiveLogs(..., useFingerprint: true, ...) already does incremental download: it stores a per-device fingerprint and only pulls dives newer than the last sync.
SuuntoNauticExplorer.listDives() -> [UInt32] logbook ids, and download(logbookID:) -> raw bytes are the Nautic list/download primitives.
- Currents has an early proximity BLE auto-sync scaffold (DiveSyncCoordinator / AutoSyncManager in CurrentsLogging), currently untested. This issue can build on or supersede it.
Proposed implementation
- Background scan + auto-connect: on app launch and via BLE state restoration, scan for the stored Nautic's advertised name (
Suunto Nautic <serial>) and auto-connect when seen, without user interaction. Reuse connectToStoredDevice and the restore path.
- Sync on connect: once connected and the EVA/RPC handshake is up, run
listDives(), diff against the stored fingerprint / known ids, and download(...) only the new logbook ids. Feed them through the standard parser pipeline and persist.
- Trigger re-sync: at minimum, sync on every (re)connect. Investigate whether the Nautic exposes an MDS-style "new dive" notification we can subscribe to (mirrors the app's watch sync trigger); if not, fall back to sync-on-connect plus an optional periodic refresh while connected.
- Background lifecycle (iOS): use CoreBluetooth background modes and state restoration so a nearby watch triggers a wake-and-sync. Keep it power-friendly (no busy reconnect loops). Surface a local notification / badge when new dives land.
- User controls: a per-device "auto-sync" toggle, and respect it in the scan/connect logic.
Acceptance criteria
- With auto-sync on and a paired Nautic in range, new dives appear in the log with no manual connect/download step.
- Only dives not already stored are downloaded (fingerprint/known-id dedup, no duplicates).
- Works after the app has been backgrounded or relaunched by iOS (state restoration path exercised).
- A clear per-device on/off setting; off means no background scanning/connecting for that device.
- No regression to the existing manual download path.
Open questions
- Does the Nautic advertise or expose a "new dive available" signal we can subscribe to, or do we always list-on-connect? (APK uses a watch-pushed MDS trigger; need to confirm what the Nautic firmware actually sends.)
- Reconnect/backoff policy and battery impact of keeping a background connection vs. connect-on-proximity-then-disconnect.
- Android parity (if/when relevant) vs. iOS-first (Currents).
Summary
Add automatic dive download for the Suunto Nautic / Nautic S / Ocean, so new dives sync without the user manually connecting and tapping download. When a paired watch is in range, the app should connect, check for dives it doesn't already have, pull only the new ones, and update the log in the background.
Today the flow is manual: connect, then call
retrieveDiveLogs. The pieces for automation already exist in the SDK (BLE state restoration, fingerprint-based incremental download, and the Nautic list/download primitives); this issue is about wiring them into a hands-off sync driven by device proximity and connection state.How the official Suunto app does it (from APK analysis, com.stt.android.suunto 6.7.12)
The app talks to the watch over an MDS (Movesense Device Service) layer on top of BLE. Relevant findings:
suunto://MDS/Logbook/. The dive sync itself isEonSynchronizer.syncLogbook(...)(with a retry count), part of the standard per-device sync. Nautic and Ocean are wired in as device types (SuuntoNauticCapability,SuuntoOceanCapability).com.suunto.connectivity.sync.listener.WatchTriggeredSyncListener:WatchState.isConnected()becoming true it starts listening for a sync trigger and syncs.Reconnectingstate and an alarm-based reconnect refresher, so the watch stays effectively "always connected" in the background.Net model: keep a background connection to the paired watch, sync on connect, and re-sync when the watch signals new data (or hourly). Dedup is by logbook id, so only new dives download.
What we already have in this repo
CoreBluetoothManageruses BLE state restoration (CBCentralManagerOptionRestoreIdentifierKey+willRestoreState), plusstartScanning,connectToStoredDevice, and stored-device persistence. iOS can relaunch the app into the background on BLE events.DiveLogRetriever.retrieveDiveLogs(..., useFingerprint: true, ...)already does incremental download: it stores a per-device fingerprint and only pulls dives newer than the last sync.SuuntoNauticExplorer.listDives()->[UInt32]logbook ids, anddownload(logbookID:)-> raw bytes are the Nautic list/download primitives.Proposed implementation
Suunto Nautic <serial>) and auto-connect when seen, without user interaction. ReuseconnectToStoredDeviceand the restore path.listDives(), diff against the stored fingerprint / known ids, anddownload(...)only the new logbook ids. Feed them through the standard parser pipeline and persist.Acceptance criteria
Open questions