16689 Commits
Author SHA1 Message Date
José Rebelo ac26ce7cfd Merge pull request 'huawei: Add missing features in HUAWEI FreeClip 2' (#6451)
Reviewed-on: https://codeberg.org/Freeyourgadget/Gadgetbridge/pulls/6451
2026-07-27 21:47:06 +02:00
José Rebelo eae143b89c Merge pull request 'Fix enum mismatch in temperature setting for zeppos' (#6482)
Reviewed-on: https://codeberg.org/Freeyourgadget/Gadgetbridge/pulls/6482
2026-07-27 21:43:59 +02:00
Grzegorz MandGrzegorz 9d01875b3d huawei: Better wording for extra volume 2026-07-27 20:03:31 +02:00
Grzegorz MandGrzegorz 4c020c3986 huawei: Use existing string 2026-07-27 20:03:31 +02:00
Grzegorz MandGrzegorz 36615b18b2 huawei: Low Latency mode 2026-07-27 20:03:31 +02:00
Grzegorz MandGrzegorz 094379dbd5 huawei: Find headphones 2026-07-27 20:03:31 +02:00
Grzegorz MandGrzegorz 48a83cc734 huawei: Modify adaptive volume sensitivity 2026-07-27 20:03:31 +02:00
Grzegorz MandGrzegorz 390b9949d2 huawei: Extra media volume in HUAWEI FreeClip 2 2026-07-27 20:03:31 +02:00
Grzegorz MandGrzegorz 735601dd2b huawei: Adaptive Volume in HUAWEI FreeClip 2 2026-07-27 20:03:31 +02:00
José Rebelo 4cc618eb9e Make t.xml the project dictionary 2026-07-27 00:25:14 +01:00
José Rebelo 5c0715c108 SoFlow: Update icon and device kind to scooter 2026-07-27 00:25:14 +01:00
José Rebelo 51ce5ae8c8 Xiaomi Scooter 5 Max: Experimental support 2026-07-27 00:25:14 +01:00
brennoflavio ba15e9e0a1 Fix enum mismatch in temperature setting for zeppos 2026-07-26 18:25:47 -03:00
José Rebelo 2e562d99f9 AAWireless: Migrate device preferences to DSL 2026-07-26 17:02:42 +01:00
e1e7400f78 gloryfitpro: sync contacts to the watch
Implement onSetContacts for the DM58 (Pro dialect, cmd 0xc0): START (ab06), the contact list in field ab07 as [numberLen | number UTF-16BE | nameLen | name UTF-16BE] entries with a 2-byte offset + xor terminator, then END (ab09). Coordinator advertises getContactsSlotCount so the contacts screen appears. Verified on hardware.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 14:25:43 +02:00
40b6968e7a gloryfitpro: use a distinct icon for light rain
Map drizzle and light rain to icon code 3 (cloud + sun + rain) so they are visually distinct from plain rain (code 7); the watch has no lighter plain-rain icon.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 14:25:43 +02:00
705ea4b381 gloryfitpro: calibrate weather condition icon codes
Catalogued the DM58 weather icon codes 0-31 on hardware (34+ are placeholder/unrelated resources) and rewrote the OpenWeatherMap mapping to use the real set: distinct rain/heavy-rain/extreme-rain, showers, snow/heavy-snow/snowstorm, sleet, fog and thunderstorm/hail icons, instead of the earlier best-effort 0-8 guess.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 14:25:43 +02:00
f1ca04813e GloryFit Pro: send weather forecast (daily + hourly)
Previously only the current weather (e0 chunk0) was sent, so the watch's
multi-day view stayed stuck on whatever the official app last synced. Add the
forecast as a second, chunked e0 message:

- "ab0b" update timestamp, then a run of hourly entries (ab0d = ts, condition,
  temp) and daily entries (ab0e = high/low, condition, day midnight, sunrise,
  sunset, moon, humidity). Today comes first (todayAsDaily()), then the per-day
  forecasts; up to 7 days and 24 hours.
- Split into <=239-byte chunks "01 e0 abab <idx> ..." ending with
  "01 e0 abab fd <xor>", where the xor covers every transmitted byte (verified
  against the official app's framing).
- Map OpenWeatherMap condition codes to the watch's icon codes, calibrated on
  hardware: 0 clear, 1 partly cloudy, 2 cloudy, 3 light rain, 4 thunderstorm,
  5 hail, 6 snow, 7 rain, 8 heavy rain. Also applied to the current-weather
  condition byte (was left at 0).

Verified on DM58 hardware: 7 days populated with correct temps/weekdays and
matching icons.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 14:25:43 +02:00
a823a07fc3 GloryFit Pro: fix media play/pause icon and volume bar
- Play/pause icon: the watch reads the state from field03 of the music-info
  frame (0x03 -> pause icon = playing, 0x02 -> play icon = paused). The values
  were inverted, so the icon was always wrong; swap them.
- Populate the music screen on connect by pushing the currently-playing track
  via MediaManager.refresh(), instead of leaving it empty until the next event.
- Volume bar: send the phone's real media-volume scale (field04 = max steps,
  field05 = current step) so the bar matches the phone and moves one segment per
  volume key press. Re-send the track on volume changes. Drops the bogus
  standalone volume frame (the official app never sends one).

Verified on DM58 hardware.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 14:25:43 +02:00
d4a24a317c gloryfitpro: load alarms edited on the watch (read-only)
Read the watch's alarms on connect (01 c7 aaaa) and update Gadgetbridge's alarm
DB from the reply so alarms edited on the watch show up in the app. The reply
puts a 0x0f separator before each alarm block ("aa 01/02/03/04" =
index/weekday-mask/enabled/HH:MM); parse all blocks. Update the DB only, without
re-sending to the watch, so this never overwrites alarms just changed on the watch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-25 14:25:43 +02:00
22c64040e9 gloryfitpro: find device/phone, alarms and weather
Adds four features to the GloryFit Pro driver, reverse-engineered by capturing
the official app's BLE traffic:

- Find device (onFindDevice): 01 a5 ab 04 01 <01/00> to ring/vibrate the watch.
- Find phone: enable on init (01 a5 ab 0a 01 01); the watch pushes
  01 a5 ac 02 01 <01/00> -> GBDeviceEventFindPhone.
- Alarms (onSetAlarms, 5 slots): 01 c7 abab 00 <per-slot TLV> + fd/xor
  (weekday bitmask bit0=Sun..bit6=Sat). Verified on hardware (08:30 Sat/Sun).
- Weather (onSendWeather): current conditions as 01 e0 abab 00 <TLV> + fd/xor
  (city, temp, high/low, UV, humidity, update time). Forecast chunks and the
  condition-code mapping are TODO.

Coordinator advertises supportsFindDevice, getAlarmSlotCount=5, supportsWeather.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-25 14:25:43 +02:00
0856713671 gloryfitpro: media control and now-playing info
Handle the watch's music remote (0xe2 events) as media control:
play / pause / previous / next / volume up / down. Also send the now-playing
artist and title ("01 e2 abab ...") and the phone volume ("01 e2 ab 01 01 <vol>")
to the watch.

Verified on hardware: the buttons control phone playback and the watch shows the
current track. Keeping the play/pause icon in sync and a live volume bar would
require streaming updates ~2x/second (like the official app), which destabilised
the BLE connection here, so that is left as a follow-up.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-25 14:25:43 +02:00
6db1f240fd gloryfitpro: sync daily step total
Read the watch's day summary (c3, "01 c3 aaaa") on connect and on manual sync,
parse today's step total from field 0x0c sub-TLV subfield 0x05 (variable-length
big-endian int), and store it as a delta relative to what was already recorded
today so Gadgetbridge's per-interval sum equals the watch's daily total. Enables
activity tracking (reusing GloryFitStepsSample + GloryFitActivitySampleProvider).

Verified on hardware: step count matches the watch display and updates live.

Note: this tracks today's total going forward; per-minute history backfill from
the c6 stream (incl. heart rate) is a follow-up.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-25 14:25:43 +02:00
f7eac78407 gloryfitpro: report GloryFitPro as the DM58 manufacturer
Clearer than "Unknown" in the test device dialog (review feedback).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 14:25:43 +02:00
25afcd466b gloryfitpro: initial support for DM58 (GloryFit Pro / ATS3085L)
Adds a new device family `gloryfitpro` for smartwatches using the GloryFit Pro
BLE dialect (com.yc.gloryfitpro), with the DM58 (Actions ATS3085L, 1.43" AMOLED)
as the first supported model. This is the variant tracked in #5541 / #5840 (same
78:02:B7 MAC prefix) and #5505; it is not the classic GloryFit protocol, so it
lives in its own package.

Implemented and verified on real hardware (firmware AT328NNV002438):
- discovery + connect (advertises as DM58)
- firmware / model read-out
- battery level + charging state
- time sync (UTC unix timestamp + [0x80|hours][minutes] timezone field)
- notification forwarding (title + body, UTF-16BE)

Protocol notes: packets are framed 01|CMD|MODE|FIELD|LEN|VALUE, where MODE is
aa=get / ab=set / ac=report (doubled aaaa/abab = "all fields"), over the CMD
service 0x55ff (write 0x35f1, notify 0x35f2) and DATA service 0x56ff (write
0x34f1, notify 0x34f2), MTU 247. Multi-packet replies terminate with
01 CMD MODE fd <xor-of-data-packet>.

Steps/activity sync, health-monitoring toggles and other features are left as
follow-ups.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-25 14:25:43 +02:00
José Rebelo 4ae7864c40 Casio: Fix notifications with long unicode text 2026-07-25 09:21:59 +01:00
dependency-bot fff3087c25 Update mapsforge to v0.29.0 2026-07-25 01:17:25 +00:00
Dany MestasandJosé Rebelo 992bc7a257 Workouts: honour activity-specific chart unit conventions 2026-07-24 23:09:27 +02:00
Dany MestasandJosé Rebelo af685455a2 Workouts: honour unit preferences in charts 2026-07-24 23:09:27 +02:00
steveandJosé Rebelo 4a83aa763b Initial support for MoYoung L70
Initial support for MoYoung L70 this and includes fixes so hartrate data works
MoYoung also hads some issues with bad stress and blodoxygen values so filter them out.
2026-07-24 22:54:35 +02:00
José Rebelo 597f94ce7b AK75 Pro (FitCloud): Initial support 2026-07-24 21:40:55 +01:00
d3vv3andJosé Rebelo 38cc6b5d14 BLE: Keep server notification flow control focused
Remove the unrelated indication API, client callback timeout, GATT service refresh, and diagnostic logging from the standalone review. Retain only server notification serialization and its bounded callback wait.
2026-07-24 22:36:08 +02:00
d3vv3andJosé Rebelo 2682f5f897 BLE: Serialize server indications and bound callback waits 2026-07-24 22:36:08 +02:00
Ken Blizzard-CaronandJosé Rebelo fd1ffa28da Add Ollee Watch One support
Ollee Watch One is a Nordic-UART (nRF) analog smartwatch. This adds a new
all-Kotlin `ollee` device family providing:

  - time + location sync
  - a single alarm (weekday repetition; one-shot mapped to its next-fire
    weekday, as the watch has no true single-fire mode)
  - world time (one zone, with the world-time face enable and offset register)
  - notification count badge
  - battery voltage
  - activity step sync (on-watch record drain -> activity samples)

The device family follows the existing all-Kotlin coordinator/support
pattern: OlleeDeviceCoordinator (capabilities + discovery), a thin
OlleeDeviceSupport, and per-feature pure-logic files (frame codec, alarm
record builder, weekday/world-time register composer, faces table, activity
records codec), each covered by JVM unit tests.

The wire protocol was worked out clean-room from HCI snoop logs and BLE
probes of my own watch and companion watch faces; nothing here derives from
decompiled or proprietary sources.

Hardware-verified on an Ollee Watch One (firmware 01.05.0000.01.10):
connect/init, battery voltage, firmware version, time+location sync,
activity step sync, world time, and the alarm (set, acknowledged by the
watch, shown on the Alarm face, and physically ringing at the set time).
2026-07-24 22:29:00 +02:00
dependency-botandJosé Rebelo fe3770a79e Update org.json:json to v20260719 2026-07-24 22:26:04 +02:00
Ken Blizzard-Caron 7f24d92352 Casio GBD-200: add world time / world clocks support
Adds home-clock timezone/DST sync and generic World Clocks UI support
for the Casio GBD-200 (module 3506), grounded in a BLE capture of the
official CASIO WATCHES app.

- Coordinator advertises 1 world-clock slot (wire carries 2: slot 0 is
  the home clock), label length 18, and the World Clocks settings row.
- New CasioWorldClockCodec builds the 0x1d/0x1e/0x1f frames in the
  app's order, with the 0x1d pair frame padded to the captured 15-byte
  length; unit-tested against capture-derived fixtures.
- Casio2C2DSupport gains a shared writeClocks() helper that wraps clock
  writes in the 0x21 settings-session bracket (21 00 01 open, 21 01 01 /
  21 00 04 / 21 01 04 close). Hardware verification showed the GBD-200
  silently discards unbracketed clock writes (GATT_SUCCESS, no effect)
  and NACKs close frames without a matching open. The 0x1f city-name
  frames are optional per device — groundwork for the WS-B1000, whose
  protocol is identical except it never uses 0x1f.
- Time sync (onSetTime and watch-requested resync) also writes the home
  clock from the phone timezone while preserving the watch's world time
  city via read-back, so a city set on the watch survives syncs.
- onSetWorldClocks writes the first enabled world clock from the
  generic UI; the watch WT display follows the written city name
  (phone-computed city ID 00 00 is accepted).

Hardware-verified on a real GBD-200: on-watch WT survives sync; GB
World Clocks save appears in WT mode; phone TZ changes (Denver <->
Chicago) move the home clock both ways automatically.
2026-07-22 09:47:47 -06:00
Vladimir TasicandJosé Rebelo a5013a9327 Initial support for AK86 2026-07-22 00:26:45 +02:00
Gideon Zenz 40550eecb2 Health Connect: Fix sleep sessions written with truncated stages
A stored night whose start predates the 24h look-back window was re-detected
by SleepAnalysis as a clipped tail (only the samples inside the window). The
frozen-id registry correctly reused the record id and preserved the full span,
but the record was rebuilt with the fragment's stages, overwriting the good
multi-stage record with a single stage. clientRecordVersion = now always won
the HC conflict, so every sync regressed the night.

Two load-bearing causes, both required to fix #6453:

- buildSleepStages set the last stage end to +1ms. The registry persists the
  span as epochSeconds, so the reloaded end never equalled the re-detected end.
  This is the trigger: a clipped-tail re-detection whose last sample matches the
  stored night would otherwise compare changed=false and be skipped, but the
  +1ms end exceeded the truncated stored end -> changed=true -> the record was
  rewritten with the truncated stage list. End on a whole second so the span
  round-trips and the skip-unchanged guard holds.

- The SLEEP fetch window started at sliceStart - 24h regardless of stored
  sessions, so any legitimate rewrite of an older night carried only the tail's
  stages. Extend the window back to the start of any stored night overlapping
  it, clamped to one extra look-back, so SleepAnalysis re-derives the full stage
  list. Extracted as pure SleepSyncer.sleepQueryStart for unit testing.

Add stage-level regression tests: the clipped-tail overwrite (the exact #6453
trigger), the epochSecond round-trip, and the fetch-window extension incl.
edges (no rows, no overlap, inclusive boundary, floor clamp, earliest of many,
and a wiring test proving a wider fetch re-derives more stages).

Fixes: https://codeberg.org/Freeyourgadget/Gadgetbridge/issues/6453
2026-07-21 18:29:12 +02:00
Arjan Schrijver eea6b89107 Fix workout editor gpx path regression introduced in 4592a3fc1 2026-07-20 16:06:16 +02:00
José Rebelo 016d3849a2 Update changelog 2026-07-19 14:54:34 +01:00
José Rebelo 4f0d63948e Garmin Fenix 5S Plus: Experimental support 2026-07-19 14:43:50 +01:00
José Rebelo 762b346a4f Amazfit Balance 3/Ultra, Bip Max, Cheetah 2 Ultra: Experimental support 2026-07-19 14:41:09 +01:00
José Rebelo b477c69bdd Zepp OS: Fix some device capabilities 2026-07-19 14:30:12 +01:00
José Rebelo 93afedce2f Fix crash when opening map view 2026-07-19 14:13:52 +01:00
mcarr823andJosé Rebelo b9b4c77638 BitmapUtil: Handle adaptive and dimensionless drawables 2026-07-18 22:49:15 +02:00
Davis Mosenkovs c959098e69 Randomize test weather
Randomize many figures in test weather and use current timestamp.
2026-07-18 22:14:41 +03:00
Dany Mestas c7aa0307cb FIT : Mark exported local/system_timestamp fields as TIMESTAMP 2026-07-18 12:42:04 +02:00
DanyPM c258671f35 FIT : Write real local_timestamp in regenerated export, timestamp_correlation record at session start 2026-07-18 04:30:04 +02:00
Arjan Schrijver 4592a3fc17 Endurain: Save workout photos in device specific export directory 2026-07-13 15:20:34 +02:00
Arjan Schrijver d688a4b06a Endurain: Upload workout photo together with track 2026-07-13 09:03:47 +02:00