2026.5.0
🙏 This release is dedicated to @mano3m, whose PR #355 was the inspiration and technical foundation for this version — state restoration, Dutch translations, profile ID filtering and weight range filtering. Thank you for this outstanding contribution.
🆕 New features
Profile system and interactive notifications
- New
profile.py— complete profile management architecture:NotificationCoordinator: central coordinator for sending interactive push notifications to mobile devices- Notification translations loaded dynamically based on HA server language (
_get_notify_translations) - Added optional weight pre-filter for notification profiles (
notify_weight_min/notify_weight_max) — when configured, a notification is only sent to a user if the measured weight falls within their range, allowing up to 5+ users to share the same scale without exceeding the 3-action limit on mobile notifications ProfileFilter(ABC) + implementationsNoFilterProfile,WeightRangeFilter,ProfileIdFilter: automatic profile selection based on measured weight, a sensor identifier, or no filterbuild_profile_filter(): factory that instantiates the correct filter based on configuration- Support for 4 profile detection methods:
none,weight_range,notification,profile_id
- New sensor
sensor.profile_id— active profile identifier during a weigh-in
Dutch translations
- Added
translations/nl.json
Impedance sensors created by the integration
- bodymiscale now creates its own impedance sensors (no more external
input_numberhelpers needed for storage) - Automatic state restoration on startup via
RestoreSensor— no moreunknownstate after HA restart
Improved cold start
- Current state of scale sensors is read at startup in
BodyScaleMetricsHandler.__init__— calculations are available immediately without waiting for a new weigh-in, including after migration from a previous version
⚙️ Changes
Restructured config flow (VERSION 1 → 4)
- Added
async_migrate_entry— automatic migration of existing v1, v2 and v3 config entries:- v1 → v2: move
name/birthday/gendertodata, moveheight/sensors tooptions - v2 → v3: add
impedance_modeandcalculation_mode, purgelast_measurement_time - v3 → v4: add
profile_method
- v1 → v2: move
- Refactored form schemas into 4 distinct functions:
_get_user_schema— identity (name, birthday, gender)_get_modes_schema— height, impedance mode, calculation mode, profile method_get_sensors_schema— scale sensors_get_profile_schema— profile method and notification
- Removed
_get_impedance_schemaand_get_main_options_schema(replaced) - Added
_purge_impedance_keys,_purge_other_method_keys,_validate_weight_range - Removed manual
last_measurement_timesensor configuration — bodymiscale now manages the timestamp automatically fromstate.last_changedafter each valid measurement, simplifying setup and avoiding stale timestamps
Internal metrics (metrics/__init__.py)
- New
_MetricsStore— internal store with differentiated TTL between source metrics (weight, impedance) and derived metrics, replaces the simple dict
New constants (const.py)
CONF_NOTIFY_DEVICE_ID,CONF_NOTIFY_SERVICE— notification configurationCONF_NOTIFY_WEIGHT_MIN,CONF_NOTIFY_WEIGHT_MAX- weight range for the notificationCONF_PROFILE_ID,CONF_SENSOR_PROFILE_ID— profile identificationCONF_PROFILE_METHOD,PROFILE_METHOD_NONE/NOTIFY/WEIGHT/ID,PROFILE_METHOD_OPTIONSCONF_WEIGHT_MIN,CONF_WEIGHT_MAX— weight range for profile filterEVENT_MOBILE_APP_NOTIFICATION_ACTION— HA event for notification responseNOTIFICATION_COORDINATOR,NOTIFICATION_TAG,PENDING_MEASUREMENT_TIMEOUTMAIN_ENTITIES,CONSTRAINT_PROFILE_ID_MIN/MAX
Developer tooling
- Migration from
setup.cfg+mypy.ini+requirements.txt+bandit.yaml→ unifiedpyproject.toml - Replaced flake8/black/isort with Ruff (lint + format)
- Modernized
.devcontainer.json—astral-sh.ruffextension, removed black/flake8/autopep8 - Added
.codespell-ignorefor scientific terms in docstrings pre-commit: addedcodespell,yamllint,bandithooks
🗑️ Removals
cachetoolsremoved fromrequirementsinmanifest.json— no longer usedbandit.yamlremoved — bandit config migrated topyproject.tomlsetup.cfg,mypy.ini,requirements.txtremoved — consolidated intopyproject.toml
🔧 Bug fixes
- Fixed [#362] —
Metric.SKELETAL_MUSCLE_MASSwas incorrectly listed as a dependency ofMetric.BODY_SCOREbut is only available in dual frequency mode; removed from dependencies so body score is correctly calculated in single impedance mode - Fixed [#276], [#342], [#343] — the S400 is now supported via profile ID filtering (the S400 sends a profile ID per user via BLE); note that the S400 uses its own calculation engine.
- Fixed [#320] — profile ID filtering is now natively supported; configure a profile ID sensor per user and bodymiscale will automatically route measurements to the correct profile
- Fixed [#11], [#38], [#238], [#252], [#282] — profile filtering (weight range, profile ID, notification) allows multiple users to share the same scale sensors; combined with automatic state restoration, dedicated per-user
input_numberhelpers are no longer needed - Fixed [#171], [#235], [#330] — TTLCache expiry during reload caused metrics to be cleared for all but the first user to trigger a callback; replaced by
_MetricsStorewhich preserves source metrics independently per user across restarts and reloads - Possibly fixed [#117] — the new
_MetricsStorewith differentiated TTL ensures derived metrics are recalculated even when source values are unchanged - Fixed [#37] — automatic state restoration via
RestoreSensorensures all metrics persist across restarts and reloads - YAML → UI migration:
birthday,heightand impedance sensors correctly preserved when migrating from an old YAML config to UI configuration - Fixed metric dependency graph being shared across all profile instances —
depended_bywas mutated on global_METRIC_DEPSobjects, causing each metric recalculation to fire N times (where N = number of configured users). EachBodyScaleMetricsHandlernow owns an isolated copy of the dependency graph.
📐 Blueprint
- Blueprint: Updated
interactive_notification_user_selection_weight_data_update.yaml. (thank you @DJaeger)- Added dual-impedance support (Low & High Frequency) for Xiaomi S400 scales.
- Integrated smart Min/Max sorting for LF/HF values.
- Added 30s data freshness check for improved accuracy.
- Added 2-decimal rounding for assistance mode.