@@ -1358,20 +1358,31 @@ def _on_scale_data(self, data: ScaleData) -> None:
13581358 )
13591359 # Decide which user this measurement is for.
13601360 # - multi-user mode: the async resolver may have already picked one,
1361- # in which case `_last_resolved_user_id` is set.
1361+ # in which case `_last_resolved_user_id` is set. Otherwise, try to
1362+ # resolve and if there's still no clear winner, treat as pending.
13621363 # - fixed-user / weight-only mode (1 configured user): the library
13631364 # doesn't call our resolver at all, but the answer is unambiguous —
13641365 # route to the only user.
1365- # - otherwise: store as pending and fire the ambiguous-notification flow.
13661366 user_id = self ._last_resolved_user_id
13671367 self ._last_resolved_user_id = None
1368- if user_id is None and len (self ._user_profiles ) == 1 :
1369- user_id = self ._user_profiles [0 ][CONF_USER_ID ]
1368+
1369+ candidate_ids : list [str ] | None = None
1370+ if user_id is None :
1371+ if len (self ._user_profiles ) == 1 :
1372+ user_id = self ._user_profiles [0 ][CONF_USER_ID ]
1373+ else :
1374+ candidate_ids = self ._compute_pending_candidates (measurement .weight_kg )
1375+ if len (candidate_ids ) == 1 :
1376+ user_id = candidate_ids [0 ]
13701377
13711378 if user_id is not None :
13721379 self ._commit_measurement_to_user (user_id , measurement , data )
13731380 else :
1374- self ._add_pending_measurement (measurement , data )
1381+ # Reuse the candidate list already computed above (if any) so we
1382+ # don't run the router a second time for the same measurement.
1383+ self ._add_pending_measurement (
1384+ measurement , data , candidate_ids = candidate_ids
1385+ )
13751386
13761387 # Push firmware revision into the device registry (no-op until the
13771388 # library reads it; harmless to call repeatedly).
@@ -1590,10 +1601,17 @@ def _maybe_compute_bmi(self, data: ScaleData, user_id: str) -> None:
15901601 )
15911602
15921603 def _add_pending_measurement (
1593- self , measurement : WeightMeasurement , data : ScaleData
1604+ self ,
1605+ measurement : WeightMeasurement ,
1606+ data : ScaleData ,
1607+ candidate_ids : list [str ] | None = None ,
15941608 ) -> None :
15951609 """Store a measurement that wasn't attributed at weigh time.
15961610
1611+ ``candidate_ids`` may be passed by the caller when it has already
1612+ computed the candidate list (via ``_compute_pending_candidates``), so
1613+ the router isn't evaluated a second time for the same measurement.
1614+
15971615 Triggers the ambiguous-notification flow (mobile push to candidate
15981616 users + persistent notification) and keeps the measurement in
15991617 ``_pending_measurements`` until either:
@@ -1605,7 +1623,8 @@ def _add_pending_measurement(
16051623 # Opportunistic cleanup: drop any pending entries older than the
16061624 # max age before adding the new one.
16071625 self ._cleanup_aged_pending_measurements ()
1608- candidate_ids = self ._compute_pending_candidates (measurement .weight_kg )
1626+ if candidate_ids is None :
1627+ candidate_ids = self ._compute_pending_candidates (measurement .weight_kg )
16091628 timestamp_iso = measurement .timestamp .isoformat ()
16101629 # Reuse the measurement's pre-computed display string when present
16111630 # (it always is for live measurements; falls back to a fresh render
@@ -1634,7 +1653,9 @@ def _add_pending_measurement(
16341653 )
16351654
16361655 def _compute_pending_candidates (self , weight_kg : float ) -> list [str ]:
1637- """Return the same candidate list ``_resolve_user`` would have produced.
1656+ """Return the same candidate list ``_resolve_user`` would have produced,
1657+ but with added logic to fallback to all users if no candidates match
1658+ the weight.
16381659
16391660 Used in the unresolved (weight-only) path to populate the pending
16401661 record's ``candidates`` so we can mobile-notify those users.
@@ -1650,9 +1671,30 @@ def _compute_pending_candidates(self, weight_kg: float) -> list[str]:
16501671 ranked = self ._router .evaluate_measurement (synthetic )
16511672 except Exception :
16521673 _LOGGER .exception ("Router evaluation failed in pending-candidate compute" )
1653- return []
1674+ ranked = []
16541675 candidate_ids = [c .user_id for c in ranked ]
1655- return self ._filter_candidates_by_location (candidate_ids )
1676+ filtered_candidates = self ._filter_candidates_by_location (candidate_ids )
1677+ if filtered_candidates :
1678+ return filtered_candidates
1679+ if candidate_ids :
1680+ return candidate_ids
1681+
1682+ # Fallback: if no candidates match weight, include all users
1683+ all_user_ids = [
1684+ u [CONF_USER_ID ] for u in self ._user_profiles if CONF_USER_ID in u
1685+ ]
1686+ if not all_user_ids :
1687+ return []
1688+
1689+ filtered_all = self ._filter_candidates_by_location (all_user_ids )
1690+ if filtered_all :
1691+ return filtered_all
1692+
1693+ _LOGGER .debug (
1694+ "No pending candidates found for weight %.2f kg, falling back to all configured users" ,
1695+ weight_kg ,
1696+ )
1697+ return all_user_ids
16561698
16571699 def _update_config_entry (self ) -> None :
16581700 """Persist coordinator state to the config entry's data dict.
0 commit comments