Skip to content

feat: Qardio QardioBase / QardioBase 2 support - #1557

Merged
oliexdev merged 1 commit into
oliexdev:masterfrom
wedsa5:qardiobase-handler
Oct 24, 2026
Merged

oliexdev merged 1 commit into
oliexdev:masterfrom
wedsa5:qardiobase-handler

Conversation

@wedsa5

@wedsa5 wedsa5 commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Qardio shut down in 2025 and its app no longer works; the scales keep
working over BLE. The protocol comes from the last official Android app
(2.5.1) and was verified on a QardioBase 2 (B200).

Features:

  • Weigh-ins over BLE: weight and impedance, plus the scale's own body
    fat, water, skeletal muscle and bone when it recognises the person.
    The weigh-in time is taken from the scale (Unix time in the result id).
  • User management: each openScale user is stored as a profile on the
    scale (name, height, birthday, sex, weight unit), kept up to date and
    re-registered after a reset. Several phones can share one scale.
  • Weigh-ins are saved to the active openScale user. Results the scale
    assigns to another profile are not saved (with a warning); guest
    weigh-ins follow the official app and are not saved unless "Save
    guest weigh-ins" is enabled. A guest result is held for 30 s so the
    user can pick their name on the scale.
  • Device settings, in sections:
    • Scale (read-only, from the last connection): model, firmware and
      software revision, battery, whether a Wi-Fi network is stored, and
      the profiles on the scale (names for those registered from this
      phone; the scale's list carries ids only).
    • Scale settings: impedance and vibration switches, scale-wide,
      applied once on the next connection by rewriting the own profile
      slot (the flags travel with every profile write, as in the official
      app).
    • This phone: select my profile when connecting, save guest
      weigh-ins.
    • Maintenance: resend profiles; reset (the scale cannot delete a
      single user); experimental legacy reset of the official app for
      firmware before 1.8 (clear user and Wi-Fi config).
image
  • Reset is a step of its own: it removes all users and the Wi-Fi network
    (verified on a B200) and restores the scale's defaults, then
    disconnects, so a reset scale can be given away. The next connection
    registers the profile again and restores the previous impedance and
    vibration settings.
  • Status messages say whether a profile is added, updated, or only the
    scale settings change.
  • Time sync and battery level.
image

Notes:

  • Profile names must be lowercase letters/digits, max 6, as the
    official app enforced; the firmware never matches other names.
  • Only values the scale reports are published; openScale derives BMI,
    BMR and lean body mass. The scale's "mt" (Qardio's muscle share) is
    documented and dropped; "sm" and "bmc" meanings are inferred and the
    evidence is written down in QardioBaseLib.
  • QardioBaseLib has no Android dependencies (own small JSON reader and
    writer); both test classes run on the JVM. Library tests use captured
    B200 payloads.
  • Only the QardioBase 2 (B200) was tested. The original QardioBase
    (B100) uses the same service in the official app but is untested.
  • Photo of a QardioBase 2 added to the scale gallery
    (docs/scales/qardio_qardiobase2.jpg).
  • QardioBase X is a different device (standard SIG profile) and is not
    covered.

Known limitations

Weigh-ins are saved only for the active openScale user. If the scale recognises another openScale user from the same phone, the result is not saved to that user. Use one phone per person, or switch the active user.
Driver settings are stored per handler class, not per scale. Two Qardio scales paired with one phone share the settings, including a pending reset.
Only the QardioBase 2 (B200) was tested on hardware. The original QardioBase (B100) is handled from the official app’s code; testing by a B100 owner is welcome.

@wedsa5
wedsa5 force-pushed the qardiobase-handler branch 3 times, most recently from 92d005e to 2010ceb Compare October 15, 2026 01:17
@wedsa5
wedsa5 marked this pull request as ready for review October 15, 2026 01:27
@wedsa5

wedsa5 commented Oct 15, 2026

Copy link
Copy Markdown
Contributor Author

Hello, requesting a review from @oliexdev or another maintainer

@oliexdev

Copy link
Copy Markdown
Owner

JSON. QardioBaseLib.Json re-implements a JSON reader/writer in ~150 lines. I'd prefer
org.json, which the app already uses: one less parser to maintain, and its error handling is
well tested. For the tests, @RunWith(RobolectricTestRunner::class) provides the real
implementation, as in the other tests here. Would you mind switching?

Wi-Fi read. The Wi-Fi config read returns SSID and passkey in clear text, only to show a
yes/no in the settings. GattScaleAdapter logs the first 24 bytes of every read, so the SSID ends
up in debug logs that users attach to issues. Does the scale report the Wi-Fi state anywhere else,
without the credentials? If not, please drop the read and the Wi-Fi entry in the settings — the
reset removes the network anyway.

Strings. 54 new strings is a lot for one driver, and each one goes to every translator on
Weblate. Please trim where it's easy:

  • Merge the five profile/settings progress messages into "Updating the scale…" / "Scale updated."
  • Reuse text_none and cap_battery.
  • Drop the section descriptions; the headers are enough.
  • Shorten the long texts to one or two sentences each, e.g. qardio_config_description,
    qardio_config_reset_desc, bt_warn_qardio_other_user, bt_warn_qardio_guest_not_saved.

Qardio shut down in 2025 and its app no longer works; the scales keep
working over BLE. The protocol comes from the last official Android app
(2.5.1) and was verified on a QardioBase 2 (B200).

Features:
- Weigh-ins over BLE: weight and impedance, plus the scale's own body
  fat, water, skeletal muscle and bone when it recognises the person.
  The weigh-in time is taken from the scale (Unix time in the result id).
- User management: each openScale user is stored as a profile on the
  scale (name, height, birthday, sex, weight unit), kept up to date and
  re-registered after a reset. Several phones can share one scale.
- Weigh-ins are saved to the active openScale user. Results the scale
  assigns to another profile are not saved (with a warning); guest
  weigh-ins follow the official app and are not saved unless "Save
  guest weigh-ins" is enabled. A guest result is held for 30 s so the
  user can pick their name on the scale; another weigh-in in that time
  resolves the held one first instead of dropping it.
- A weigh-in made while no phone was connected is collected on the next
  connection, quietly unless it is under 2 minutes old. Each weigh-in is
  saved once: by result id on the B200. The B100 sends no id or time, so
  a result read at connect is taken only if the first state is 6 (the
  weigh-in finished just before the connection; it gets the time of
  collection), and repeated reads are dropped by value per connection.
- Device settings, in sections:
  - Scale (read-only, from the last connection): model, firmware and
    software revision, battery, and the profiles on the scale (names for those registered from this
    phone; the scale's list carries ids only).
  - Scale settings: impedance and vibration switches, scale-wide,
    applied once on the next connection by rewriting the own profile
    slot (the flags travel with every profile write, as in the official
    app).
  - This phone: select my profile when connecting, save guest
    weigh-ins.
  - Maintenance: resend profiles; reset (the scale cannot delete a
    single user); experimental legacy reset of the official app for
    firmware before 1.8 (clear user and Wi-Fi config).
- Reset is a step of its own: it removes all users and the Wi-Fi network
  (verified on a B200) and restores the scale's defaults, then
  disconnects, so a reset scale can be given away. The next connection
  registers the profile again and restores the previous impedance and
  vibration settings.
- Configuration mode and reset give up after 10 s without an answer
  (the change stays pending), so the phone never holds the scale's
  single connection.
- Time sync and battery level.

Notes:
- Profile names must be lowercase letters/digits, max 6, as the
  official app enforced; the firmware never matches other names.
  Accents are dropped ("José" -> "jose"); a name without Latin letters
  or digits becomes "user".
- Only values the scale reports are published; openScale derives BMI,
  BMR and lean body mass. The scale's "mt" (Qardio's muscle share) is
  documented and dropped; "sm" and "bmc" meanings are inferred and the
  evidence is written down in QardioBaseLib.
- JSON goes through org.json; both test classes run under Robolectric.
  Library tests use captured B200 payloads.
- The Wi-Fi config is never read: it returns the SSID and passkey in
  clear text.
- Only the QardioBase 2 (B200) was tested. The original QardioBase
  (B100) uses the same service in the official app but is untested.
- Photo of a QardioBase 2 added to the scale gallery
  (docs/scales/qardio_qardiobase2.jpg).
- QardioBase X is a different device (standard SIG profile) and is not
  covered.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@wedsa5
wedsa5 force-pushed the qardiobase-handler branch from 2a66f5f to c8b7c7f Compare October 20, 2026 00:13
@wedsa5

wedsa5 commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

@oliexdev

Thanks for the review! All three done:

  • Switched to org.json; the lib tests now run under Robolectric.
  • Dropped the Wi-Fi config read and the Wi-Fi row. There's a separate Wi-Fi state characteristic, but I couldn't verify it reports whether a network is stored, so I left it out. The reset still clears the network.
  • Trimmed the strings: merged the progress messages, reused text_none and cap_battery, dropped the section descriptions, and shortened the long texts.

Also rebased onto master to fix the conflict in scale_catalog_remarks.txt.

@oliexdev
oliexdev merged commit 8809755 into oliexdev:master Oct 24, 2026
@oliexdev

Copy link
Copy Markdown
Owner

Thanks for your PR 👍

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.

2 participants