A cross-platform CLI tool that reads body composition data from 24+ BLE smart scales and exports to Garmin Connect, Strava, MQTT (Home Assistant), InfluxDB, Webhooks, Ntfy, and local files (CSV/JSONL). No phone app needed. Your data stays on your device.
Documentation · Getting Started · Supported Scales · Exporters · FAQ
Most BLE smart scales measure weight and body impedance over Bluetooth, but their companion apps have no way to sync data to Garmin Connect. The only workflow was: open the phone app, wait for it to sync, then manually type the numbers into Garmin. Every single time.
I didn't want to depend on a phone app. So I built this tool. A Raspberry Pi Zero 2W sits next to the scale, always on, always listening. Step on the scale, wait a few seconds, and the reading appears in Garmin Connect - no phone needed, no app, no manual entry. It just works.
If you can't have a Pi next to your scale, a cheap ESP32 proxy can sit nearby and relay BLE data over WiFi to a Docker server anywhere on your network. See the ESP32 BLE proxy guide.
# Configure
docker run --rm -it --network host --cap-add NET_ADMIN --cap-add NET_RAW \
--group-add 112 -v /var/run/dbus:/var/run/dbus:ro \
-v ./config.yaml:/app/config.yaml \
-v ./garmin-tokens:/app/garmin-tokens \
ghcr.io/kristianp26/ble-scale-sync:latest setup
# Run (continuous mode, auto-restart)
docker run -d --restart unless-stopped --network host \
--cap-add NET_ADMIN --cap-add NET_RAW \
--group-add 112 --device /dev/rfkill \
-v /var/run/dbus:/var/run/dbus:ro \
-v ./config.yaml:/app/config.yaml:ro \
-v ./garmin-tokens:/app/garmin-tokens:ro \
-e CONTINUOUS_MODE=true \
ghcr.io/kristianp26/ble-scale-sync:latestIdeal for Raspberry Pi, NAS, and headless servers. Works alongside any Home Assistant install (Container, Core, OS) via MQTT auto-discovery.
If you run Home Assistant OS or Supervised, one click is all it takes:
The badge opens your Home Assistant instance, confirms the repository, and shows BLE Scale Sync in the Add-on Store ready to install.
Prefer manual steps?
- Settings > Add-ons > Add-on Store > three-dot menu > Repositories
- Add
https://github.com/KristianP26/ble-scale-syncand install BLE Scale Sync
The add-on handles config through the UI, auto-detects the Mosquitto broker for Home Assistant auto-discovery, and bootstraps Garmin tokens on first start. See the Home Assistant Add-on guide for the full option reference, MFA workaround, and custom config mode.
Note: Add-ons are not available on HA Container or HA Core installs (no Supervisor). Use the Docker method above instead. Sensors still appear in HA via MQTT auto-discovery.
Runs natively on all major desktop and server operating systems. No containers required.
git clone https://github.com/KristianP26/ble-scale-sync.git
cd ble-scale-sync && npm install
npm run setup # interactive wizard
CONTINUOUS_MODE=true npm start # always-onRequires Node.js v22+ and a BLE adapter. See the full install guide for prerequisites and systemd service setup.
- 24+ scale brands. Xiaomi (Mi Scale 2 passive broadcast), Renpho (Elis 1, FITINDEX, Sencor, QN-Scale), Eufy, Yunmai, Beurer, Sanitas, Medisana, and more.
- 7 export targets. Garmin Connect, Strava, MQTT (Home Assistant), InfluxDB, Webhook, Ntfy, File (CSV/JSONL).
- 10 body metrics. BIA-based body composition from weight + impedance.
- Multi-user. Automatic weight-based identification with per-user exporters.
- Historical sync. Replays a scale's onboard cache of offline measurements with their original timestamps to exporters that support back-dating (Garmin Connect, InfluxDB, File).
- Interactive setup wizard. Scale discovery, exporter config, connectivity tests.
- BLE diagnostic tool.
npm run diagnosefor detailed BLE troubleshooting. - Home Assistant Add-on. One-click install via My Home Assistant badge, MQTT auto-discovery, UI-driven config, Garmin token bootstrap, and MFA workaround.
- ESP32 BLE proxy. Use a remote ESP32 as a BLE radio over MQTT, with a built-in embedded broker for zero-config setup, simplified Docker deployment, and optional display.
- ESPHome Bluetooth proxy. Reuse an existing ESPHome BT proxy mesh (Home Assistant) as a BLE radio via Native API (experimental, broadcast-only in phase 1).
- BLE adapter selection.
ble.adapter: hci1for multi-adapter setups (Linux). - Broadcast mode. Supports non-connectable scales that only advertise weight via BLE advertisements.
- Linux stability hardening. Auto-recovery for the BlueZ "stuck discovery" state via a consecutive-failure watchdog, plus optional systemd
Type=notifyintegration for whole-loop freezes. - Update check. Optional, anonymous version check after each measurement (opt-out via
update_check: false); see the auto update guide for Watchtower, systemd timer, and HA add-on recipes. - Cross-platform. Linux (Docker + native), macOS, Windows.
- Private. Your data stays on your device, no vendor cloud.
- Scale protocols - many adapters ported from openScale (oliexdev and contributors); Eufy P2 / P2 Pro ported from bdr99/eufylife-ble-client; QN-Scale / FITINDEX and a few others reverse-engineered in this project
- Garmin upload - powered by garminconnect by cyberjunky
- BLE - node-ble (Linux), @abandonware/noble (Windows), @stoprocent/noble (macOS)
- ESP32 proxy - mqtt_as by peterhinch, aioble
KristianP26 |
APIUM |
marcelorodrigo |
fromport |
See CONTRIBUTING.md for development setup, project structure, and how to add new scale adapters or exporters.
GPL-3.0. See LICENSE for details.