What's New
Multi-User Weight Matching
- Configure multiple users in
config.yamlwith individual weight ranges - 4-tier matching priority: exact range → LKW tiebreak → closest LKW → strategy fallback
- Drift detection warns when weight approaches range boundaries (outer 10%)
last_known_weightauto-updated in config.yaml after each measurement (debounced, atomic write, comments preserved)- Configurable
unknown_userstrategy:nearest,log, orignore
Unified Config System
- New
config.yamlas primary configuration (.envstill supported as fallback) - Zod schema validation with human-readable error messages
${ENV_VAR}references in YAML values for secretsnpm run validateCLI for config validation- Environment overrides (
CONTINUOUS_MODE,DRY_RUN,DEBUG,SCAN_COOLDOWN,SCALE_MAC,NOBLE_DRIVER) always apply on top of YAML
Per-User Exports
- MQTT: publishes to
{topic}/{slug}, per-user HA device discovery + LWT - InfluxDB: adds
user={slug}tag to line protocol - Webhook: adds
user_name+user_slugfields to JSON payload - Ntfy: prepends
[{name}]to notification, appends drift warning - Garmin: per-user config via user-level
exporterssection
Exporter Registry
- Self-describing exporter schemas with field definitions and display metadata
- Factory pattern for creating exporters from config.yaml entries
- Per-user exporter resolution (user-level overrides global, deduped by type)
Infrastructure
scanAndReadRaw()BLE layer for match-before-compute flow- SIGHUP config reload between scan cycles (Linux/macOS)
- Heartbeat file (
/tmp/.ble-scale-sync-heartbeat) for Docker health checks - Exporter cache per user slug, cleared on SIGHUP reload
Testing
- 894 tests across 49 test files
- E2E verified with real Renpho scale on Windows + Raspberry Pi
- All 5 exporters tested with live services (Garmin Connect, HiveMQ, InfluxDB Cloud, ntfy.sh, webhook.site)
Breaking Changes
None — fully backwards compatible. Single-user .env configuration continues to work unchanged.