Skip to content

Add DiFluid Microbalance BLE scale support#3

Open
FabianSperrle wants to merge 2 commits into
rancilio-pid:developfrom
FabianSperrle:difluid-microbalance
Open

Add DiFluid Microbalance BLE scale support#3
FabianSperrle wants to merge 2 commits into
rancilio-pid:developfrom
FabianSperrle:difluid-microbalance

Conversation

@FabianSperrle
Copy link
Copy Markdown

Add DiFluid Microbalance BLE scale support

Summary

Adds a new DIFLUID scale_type so the library can read weight from a DiFluid Microbalance (and, by protocol, the Microbalance Ti). It slots into the existing per-type pattern (name match → service discovery → notify parser → tare), so downstream consumers like CleverCoffee need no changes beyond selecting the Bluetooth scale type.

Motivation

I ended up with a DiFluid Microbalance — a hand-me-down from a family member who wasn't using it — and wanted to run it as a brew scale, but the library didn't support it. Unlike the existing scales it ships a dual-channel GATT (one encrypted, one cleartext), which is why a naive connection only ever sees ciphertext — this PR documents and handles that.

How it works (protocol)

The Microbalance exposes data service 000000EE-0000-1000-8000-00805F9B34FB with two characteristics:

  • FF01encrypted channel (emits DA DA … ciphertext; ignored)
  • AA01cleartext channel, notify and write (used here)

Both are on by default on current firmware; no DiFluid-server/app handshake is required, so an offline ESP32 can read weight directly.

Flow once connected on AA01:

  1. Write DF DF 01 00 01 01 C1 (Func 1 / Cmd 0 = Auto Send on) — the scale does not stream until asked. No periodic heartbeat is needed afterwards.
  2. The scale pushes ~5 Hz sensor notifications:
DF DF 03 00 0D | W0 W1 W2 W3 | flow(2) | time(2) | timestamp(4) | unit | checksum
index:   0..4     5  6  7  8     9 10     11 12     13 14 15 16     17     18
  • Weight = signed big-endian int32 at offset 5, ×0.1 g.
  • Checksum = sum(all preceding bytes) & 0xFF (a byte-sum, not XOR).
  • Two other frames also arrive on AA01 and are excluded by the parse guards: the Func 1 auto-send echo, and the Func 3 / Cmd 5 device-status frame (pData[3] == 0x05).

Tare maps to a single power-button click: DF DF 03 02 01 01 C5 (Func 3 / Cmd 2).

Implementation notes

  • Matched by advertised-name prefix MICROBALANCE plus discovery of service 000000EE.
  • Skips the Acaia IDENTIFY / NOTIFICATION_REQUEST handshake (like GENERIC) and instead sends the auto-send-enable on connect; heartbeatRequired() stays false.
  • DiFluid command writes use write-with-response (the AA01 characteristic advertises Write-with-response).
  • Weight uses a signed BE int32 so post-tare negatives work without a separate sign byte.
  • On-scale timer is intentionally stubbed (no-op branches in startTimer/stopTimer/resetTimer) so DiFluid never receives Acaia timer bytes — the timer command bytes aren't verified yet.
  • Grams only (matches the library's existing limitation).

Testing

  • Protocol reverse-engineered and confirmed live with nRF Connect on a real Microbalance 299172 (full GATT capture, auto-send enable, weight + negative/post-tare frames, all checksum-validated).
  • Compiles in the CleverCoffee firmware (PlatformIO, az-delivery-devkit-v4, esp32) — build green.
  • Runs on hardware: connects and reports live weight via CleverCoffee.

Limitations / follow-ups

  • Branch is based on tag v4.0.1; may need a rebase onto develop.
  • Microbalance Ti is not physically tested. The DiFluid SDK docs suggest a shared protocol; if a Ti uses a different service UUID (the docs hint at 000000DD), discovery would need that UUID added. The MICROBALANCE name gate already covers its name.
  • On-scale timer not implemented (see above).

Checklist

  • New scale_type follows the existing discovery/parse/tare structure
  • No changes required in consumer firmware
  • Verified on real hardware
  • Microbalance Ti verified (no device)
  • On-scale timer commands

FabianSperrle and others added 2 commits May 24, 2026 22:37
Adds a DIFLUID scale_type for the DiFluid Microbalance / Microbalance Ti.

- Matched by advertised-name prefix MICROBALANCE and data service 000000EE.
- Weight read from the cleartext AA01 characteristic; FF01 in the same
  service is encrypted and is never subscribed to.
- Auto-send enabled on connect via DF DF 01 00 01 01 C1 (write-with-response);
  the Acaia IDENTIFY/NOTIFICATION_REQUEST handshake is skipped and no
  heartbeat is required.
- Sensor frame DF DF 03 00 0D <13B> carries a signed big-endian int32 weight
  at offset 5, scaled x0.1 g, validated by a sum checksum (NOT XOR). The
  Func1 echo and Func3/Cmd5 status frames are excluded by the guards.
- Tare maps to a single power-button click (DF DF 03 02 01 01 C5); on-scale
  timer is stubbed (command bytes unverified).

Protocol verified via nRF Connect on a real Microbalance 299172 and tested
working on hardware via CleverCoffee (2026-05-24).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds the DiFluid Microbalance to the Scale Compatibility table and the
roadmap checklist. Auto-tare verified on hardware; timer columns marked
not-implemented (command bytes unverified).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@FabianSperrle FabianSperrle force-pushed the difluid-microbalance branch from 4e8acac to 9225ad0 Compare May 24, 2026 20:46
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.

1 participant