Auto updates
The app logs Update available: ... when a newer release exists, but it never installs one. Update check turns the check off. Releases are in the changelog.
Home Assistant add-on
Manual updates (default)
A new version shows an Update button under Settings > Apps > BLE Scale Sync. The Supervisor pulls the new image and restarts the add-on; options and /data are kept.
Automatic updates
- Open Settings > Apps > BLE Scale Sync.
- Turn on Auto update.
- Keep the backup toggle on in the update dialog, so the Supervisor makes a partial backup before each update. Settings > System > Backups sets whether that toggle starts on.
The Supervisor then installs new versions during its daily update check and restarts the add-on.
In custom config mode an update replaces the image and leaves /share/ble-scale-sync/config.yaml as it is. Check the changelog for config changes before you turn on unattended updates.
Docker Compose
An update re-creates the container, which drops the files the app keeps next to a single-file config.yaml mount, the export retry queue included. See Run.
Systemd timer
A timer that pulls the image and restarts the stack needs no extra container. Create /etc/systemd/system/ble-scale-sync-update.service, with WorkingDirectory set to the directory of your docker-compose.yml:
[Unit]
Description=Pull latest ble-scale-sync image and restart the stack
After=docker.service
[Service]
Type=oneshot
WorkingDirectory=/home/YOUR_USER/ble-scale-sync
ExecStart=/usr/bin/docker compose pull
ExecStart=/usr/bin/docker compose up -dand /etc/systemd/system/ble-scale-sync-update.timer:
[Unit]
Description=Daily ble-scale-sync image update
[Timer]
OnCalendar=daily
Persistent=true
RandomizedDelaySec=1h
[Install]
WantedBy=timers.targetEnable the timer and check the next run:
sudo systemctl daemon-reload
sudo systemctl enable --now ble-scale-sync-update.timer
systemctl list-timers ble-scale-sync-updateWatchtower
Watchtower restarts a container when a newer image is pushed. The upstream project was archived in December 2025 and gets no more updates. If you run it anyway, opt in only this container with a label and add the sidecar next to your existing service:
services:
ble-scale-sync:
# ... your existing service
labels:
- 'com.centurylinklabs.watchtower.enable=true'
watchtower:
image: containrrr/watchtower
container_name: watchtower
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- WATCHTOWER_LABEL_ENABLE=true # touch only labelled containers
- WATCHTOWER_CLEANUP=true # remove the old image after an update
- WATCHTOWER_POLL_INTERVAL=86400 # check once a day
- WATCHTOWER_INCLUDE_RESTARTING=true # also update a container stuck in a restart loopTo get a notification instead of an update, add WATCHTOWER_MONITOR_ONLY=true, WATCHTOWER_NOTIFICATIONS=shoutrrr and WATCHTOWER_NOTIFICATION_URL=ntfy://ntfy.sh/YOUR_TOPIC to the watchtower environment.
npm install
Update the global install and restart the service:
npm install -g ble-scale-sync@latest
sudo systemctl restart ble-scale.serviceSystemd install from a clone
For a clone that runs as ble-scale.service, a timer can fast-forward main, rebuild and restart the service. The service setup is in Run as a service. main can hold code that is not released yet. To stay on releases, pin a tag instead.
Update script
Create /home/YOUR_USER/ble-scale-sync/scripts/auto-update.sh and make it executable with chmod +x:
#!/usr/bin/env bash
set -euo pipefail
cd /home/YOUR_USER/ble-scale-sync
git fetch --quiet origin main
LOCAL=$(git rev-parse main)
REMOTE=$(git rev-parse origin/main)
if [ "$LOCAL" = "$REMOTE" ]; then
echo "Already up to date ($LOCAL)."
exit 0
fi
echo "Updating from $LOCAL to $REMOTE..."
# Fast-forward only: refuse divergent history to protect local edits
git merge --ff-only origin/main
# Full install when the lockfile changed: the build needs TypeScript, a devDependency
if git diff --name-only "$LOCAL" "$REMOTE" | grep -qE '^(package(-lock)?\.json)$'; then
npm ci
fi
# tsc stops the script on a type error, so the service is not restarted; dist/ is already rewritten
npm run build
# Stops the old process and starts the new build; if it fails to start,
# Restart=always in ble-scale.service keeps retrying
sudo systemctl restart ble-scale.service
echo "Updated to $REMOTE."The sudo systemctl restart line needs passwordless sudo for that command.
Timer
# /etc/systemd/system/ble-scale-sync-update.service
[Unit]
Description=Update ble-scale-sync from main and restart service
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
User=YOUR_USER
ExecStart=/home/YOUR_USER/ble-scale-sync/scripts/auto-update.sh# /etc/systemd/system/ble-scale-sync-update.timer
[Unit]
Description=Weekly ble-scale-sync git pull
[Timer]
OnCalendar=Sun 04:30
Persistent=true
RandomizedDelaySec=30min
[Install]
WantedBy=timers.targetsudo systemctl daemon-reload
sudo systemctl enable --now ble-scale-sync-update.timerThe timer runs every Sunday at 04:30 local time, up to 30 minutes later. If the script fails before the restart, because of diverged history or a failed install or build, the service keeps running the old build. The error is in journalctl -u ble-scale-sync-update.service.
Pinning a version
To upgrade only by hand, pin a release instead of latest.
Docker: image tags are the version without the v. X.Y.Z pins one release, X.Y follows its patch releases.
image: ghcr.io/kristianp26/ble-scale-sync:X.Y.ZInstall from a clone: check out a release tag, then rebuild.
cd /home/YOUR_USER/ble-scale-sync
git fetch --tags
git checkout vX.Y.Z
npm ci && npm run buildThe Home Assistant add-on always runs the image of its own version. Keep Auto update off to stay on it. With a pinned version, leave the update timer off. The update check still tells you when a release is out.
Safety checklist before enabling unattended updates
config.yaml(and/dataon Home Assistant, or your Docker volumes) is backed up off the device.- Your scale works on the current version, with no open issue for your hardware.
- You read the changelog from time to time; releases can add or rename config fields.
- Exporter tokens (Garmin, Strava) are in a volume that survives a re-created container.
- Something alerts you when the service stops, such as a check on
/tmp/.ble-scale-sync-heartbeat, a Home Assistant notification or the ntfy exporter.