Skip to content

Conversation

@michaelthatsit
Copy link
Contributor

@michaelthatsit michaelthatsit commented Dec 6, 2025

this is pretty early. all it does is pull the health data from the watch, and push the averages to it.

I'm thinking it's probably best to add this and do any UI changes in a separate PR: In it I would probably add:

TODOs:

  • set averages on watch
  • sync multiple watches

@CLAassistant
Copy link

CLAassistant commented Dec 6, 2025

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ michaelthatsit
❌ sjp4
You have signed the CLA already but the status is still pending? Let us recheck it.

@michaelthatsit michaelthatsit marked this pull request as draft December 6, 2025 01:06
@Odel
Copy link

Odel commented Dec 6, 2025

Would this handle a user switching between two watches throughout the day?

@michaelthatsit
Copy link
Contributor Author

Not yet no, and some of the discussion on discord suggests some of my initial assumptions were incorrect on how the data storage works on the watch.

This solution works but some steps I'm taking are unnecessary and could impact battery life.

@MrXANA91
Copy link

MrXANA91 commented Dec 11, 2025

It might be relevant to have the Unit Distance (Miles/Kilometers) setting in the health integration of the mobileapp, if it is not already the case in this PR

@michaelthatsit
Copy link
Contributor Author

May have gone a bit overboard here. But here's the daily, weekly, and monthly screens for health data. Monthly needs work and as of now you can only view the current day, week, or month.

Monthly is meant to show an area graph of each week of the current month but I'm still playing with KoalaPlot.

Screenshot_20251216-195228 Screenshot_20251216-195242 Screenshot_20251216-195253

@michaelthatsit
Copy link
Contributor Author

I recognize I might be going overboard with this one so lemme know if you folks want me to scale it back at all @sjp4

@michaelthatsit
Copy link
Contributor Author

It might be relevant to have the Unit Distance (Miles/Kilometers) setting in the health integration of the mobileapp, if it is not already the case in this PR

I added this in the health settings panel but it doesn't seem to immediately update on the watch.

@michaelthatsit
Copy link
Contributor Author

I've added metrics to the graphs.

Not the best example. Had to clear local db after merging in the upstream so there's no data for sleep and not a lot for steps.

Screenshot_20251217-182316.png

@michaelthatsit
Copy link
Contributor Author

@sjp4 Picking this back up and trying to simplify it further.

Would it be better to consolidate all datalogging into the DataLoggingService, rather than doing it in multiple locations?

michaelthatsit and others added 3 commits January 9, 2026 10:23
- Extract HealthDataProcessor from HealthService
- Datalogging routes health tags (81-85) to HealthDataProcessor
- DataLoggingService handles ALL datalogging packets and ACK/NACK
- Remove duplicate packet handling from HealthService
- HealthService now focuses on orchestration and public API

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Two critical fixes:

1. Emit healthUpdateFlow when health data is processed
   - HealthDataProcessor now emits to healthDataUpdated flow after inserting data
   - HealthService forwards these emissions to its healthUpdateFlow
   - This notifies UI (HealthStatsDialog) when new data arrives so it can refresh

2. Remove data blocking during reconciliation
   - Previously blocked ALL health data during reconciliation with setAcceptHealthData(false)
   - This caused reconciliation to hang because requested data was being dropped
   - waitForNewerHealthData() would timeout after 8s waiting for DB updates that never came
   - Now reconciliation allows data to flow freely
   - "Highest step count wins" strategy in DB handles any conflicts

Fixes: "today's steps" now update correctly in UI after sync

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Removed complex reconciliation logic that was trying to handle multiple
watches and prevent stale data. Now we just accept all incoming data
from the watch and let the "highest step count wins" database strategy
handle any conflicts.

Removed:
- reconcileWatchWithDatabase() function
- waitForNewerHealthData() function
- Data blocking during sync (setAcceptHealthData)
- lastFullStatsUpdate state tracking
- Related constants: HEALTH_SYNC_WAIT_MS, HEALTH_SYNC_POLL_MS,
  RECONCILE_DELAY_MS, FULL_STATS_THROTTLE_HOURS, TWENTY_FOUR_HOURS_MS

Simplified:
- No more reconciliation on watch connection
- Daily stats update now just waits until 7 AM without throttling logic
- sendHealthAveragesToWatch() no longer tracks last update time

Result: Much simpler, more predictable health data flow.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@michaelthatsit
Copy link
Contributor Author

The refinement continues, I went ahead and consolidated all datalogging into DataLoggingService. Ready for re-review.

@michaelthatsit
Copy link
Contributor Author

@sjp4 I'm gonna dogfood this with my PTS for a few days to make sure it's working as expected. but the logic seems sound. Ready for another look and (hopefully) merge.

@asyba
Copy link
Contributor

asyba commented Jan 14, 2026

@michaelthatsit Are these new tables designed for future synchronization with Apple Health or Google Health?
We don't want to run into problems later when we want to implement it, making us say, "We should have done this from the beginning," and now we have to do some workarounds, etc.

@michaelthatsit
Copy link
Contributor Author

michaelthatsit commented Jan 14, 2026

@michaelthatsit Are these new tables designed for future synchronization with Apple Health or Google Health?

We don't want to run into problems later when we want to implement it, making us say, "We should have done this from the beginning," and now we have to do some workarounds, etc.

I do believe they're at this point compatible but I can double check. There's a library I mentioned in an open issue that we can use for quick integrations for both services.

If the plan is to simply integrate with those services and not provide a built in health panel, we should also probably not store more than a week of data at a time.

@kellerkindt
Copy link

kellerkindt commented Jan 14, 2026

@sjp4 I'm gonna dogfood this with my PTS for a few days to make sure it's working as expected. but the logic seems sound. Ready for another look and (hopefully) merge.

Thank you for your efforts! I'll probably highly appreciate it once it has been merged.

@asyba
Copy link
Contributor

asyba commented Jan 14, 2026

I vote to have them on boths places on pebble app and then just send them on apple/google/etc in the background.

@michaelthatsit
Copy link
Contributor Author

I vote to have them on boths places on pebble app and then just send them on apple/google/etc in the background.

I'm personally more into the idea of a custom end point I can send the data to. There aren't many good self-hosted health tracking options out there. I'm planning to build one this year and being able to integrate directly into the mobile app would save me the effort of building a pebble app/face.

@michaelthatsit michaelthatsit requested a review from sjp4 January 15, 2026 03:08
@sjp4
Copy link
Member

sjp4 commented Jan 15, 2026

@sjp4 I'm gonna dogfood this with my PTS for a few days to make sure it's working as expected. but the logic seems sound. Ready for another look and (hopefully) merge.

Thanks! Taking a look today - is it OK if I push some commits to get it merged?

- Fixed compilation on iOS (can't use String.format in common code)
- Distance units does not belong in the activityPreferences entry - this broke changing any of the settings (even enabling health) because the watch couldn't parse it. This table actually should have multiple rows - I've refactored this (had to drop the previous table, so users will need to re-enable health after updating).
- A lot of things were happening in the connection-scoped service which should have been in the global Health class - moved them over.
- Many of the methods on libpebble/connected pebble weren't actually required: especially for requesting health sync (we can make the reuqest suspending until we get a response, and also note that the response does not mean that data has been synced via datalogging yet)
- It was creating an endless loop of health sync requests whenever we manually request a sync (because the response message from the watch - which is just an ACK of the request - was being treated as a request to send another request..)
- Refactored the 911 packet definitions - some of them were incorrect (or missing e.g. ACK vs NACK).
- Changed injected coroutine scope for HealthDataProcessor to global rather than connection. I'm not sure how this didn't crash during koin init, but it shouldn't be able to use the connection scope because it's globally scoped in koin.
- Moved the health debug screen behind debug settings flag
- Fixed HealthParsingTest (was using wrong DataBuffer args?)
@sjp4
Copy link
Member

sjp4 commented Jan 16, 2026

I pushed a bunch of fixes - see the commit message for details. A few things were broken which was stopping me from testing anything, and noticed more (including refactoring the existing settings model) as I went. I think sync requests and updating settings are working now - can you try out the updated branch, too? I'll go through the parsing/state code later - would be good to know it everything is still working for you before merging though - I made quite a lot of changes.

@michaelthatsit
Copy link
Contributor Author

I pushed a bunch of fixes - see the commit message for details. A few things were broken which was stopping me from testing anything, and noticed more (including refactoring the existing settings model) as I went. I think sync requests and updating settings are working now - can you try out the updated branch, too? I'll go through the parsing/state code later - would be good to know it everything is still working for you before merging though - I made quite a lot of changes.

@sjp4 Thanks for doing that and I appreciate the patience as I'm relatively new to Kotlin.

I pulled and tested the changes and everything is working as expected. Are there any other updates you'd like me to make before we merge?

@michaelthatsit
Copy link
Contributor Author

@sjp4 I'll leave next steps up to you! After this merges I can take up Apple/Google health integration.

@SterlingEly
Copy link

Thank you all so much for doing this. Really looking forward to the return of Pebble Health!

@SterlingEly
Copy link

One humble yet fervent request from a user who knows what's possible from experience but has no idea how much harder it is to implement:
When you do Apple/Google Health integration, please use minute-level granularity (like the OG Pebble app did) instead of cramming the totals in a single entry at the end of the day. The latter just creates garbage data that doesn't reconcile well with other sources.
image

sjp4 added 4 commits January 23, 2026 16:03
# Conflicts:
#	libpebble3/schema/io.rebble.libpebblecommon.database.Database/28.json
#	libpebble3/src/commonMain/kotlin/io/rebble/libpebblecommon/connection/FakeLibPebble.kt
#	libpebble3/src/commonMain/kotlin/io/rebble/libpebblecommon/connection/endpointmanager/blobdb/BlobDB.kt
#	libpebble3/src/commonMain/kotlin/io/rebble/libpebblecommon/database/Database.kt
#	libpebble3/src/commonMain/kotlin/io/rebble/libpebblecommon/di/LibPebbleModule.kt
@sjp4 sjp4 merged commit d4acf9b into coredevices:master Jan 24, 2026
1 check was pending
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants