348 files

This commit is contained in:
Home Assistant Version Control
2026-07-23 19:02:12 +00:00
parent 0ed1687503
commit 016af2e013
348 changed files with 12368 additions and 11689 deletions
+44 -4
View File
@@ -159,6 +159,20 @@ def _build_children_summary(coordinator: TaskMateCoordinator, common: dict) -> l
"name": c.name,
"points": c.points,
"pending_points": pending.get(c.id, 0),
# Guest profiles (#690): cards filter these out of competitive views.
**({"is_guest": True, "guest_expires_on": getattr(c, "guest_expires_on", "")}
if getattr(c, "is_guest", False) else {}),
# Chore roulette (#677): today's pick + spins left, so the card can
# show the result and disable the button once the allowance is used.
**(
{
"roulette": {
**(coordinator.roulette_selection(c.id) or {}),
"spins_left": coordinator.roulette_spins_left(c.id),
}
}
if coordinator.roulette_enabled() else {}
),
"committed_points": committed_amount,
"allocated_points": allocated.get(c.id, 0),
# Allocations were deducted from child.points already, so spendable
@@ -260,6 +274,25 @@ def _build_chores_list(coordinator: TaskMateCoordinator, common: dict) -> list[d
record["visibility_entity"] = visibility_entity
record["visibility_operator"] = getattr(c, 'visibility_operator', 'equals')
record["visibility_state"] = getattr(c, 'visibility_state', 'on')
weather_entity = getattr(c, 'weather_entity', '')
if weather_entity:
record["weather_entity"] = weather_entity
record["weather_block_conditions"] = list(getattr(c, 'weather_block_conditions', []) or [])
for limit in ("weather_temp_min", "weather_temp_max", "weather_wind_max"):
value = getattr(c, limit, None)
if value is not None:
record[limit] = value
# Why it's hidden, so the panel can say "rained off" instead of
# just dropping the chore out of the list.
reason = coordinator.weather_block_reason(c)
if reason:
record["weather_blocked"] = reason
deadline_at = getattr(c, 'deadline_at', '')
if deadline_at:
record["deadline_at"] = deadline_at
speed_bonus = getattr(c, 'speed_bonus_points', 0)
if speed_bonus:
record["speed_bonus_points"] = speed_bonus
disabled_for = getattr(c, 'disabled_for', [])
if disabled_for:
record["disabled_for"] = disabled_for
@@ -269,6 +302,9 @@ def _build_chores_list(coordinator: TaskMateCoordinator, common: dict) -> list[d
assignment_current_child_id = getattr(c, 'assignment_current_child_id', '')
if assignment_current_child_id:
record["assignment_current_child_id"] = assignment_current_child_id
icon = getattr(c, 'icon', '')
if icon:
record["icon"] = icon
completion_sound = getattr(c, 'completion_sound', 'coin')
if completion_sound and completion_sound != 'coin':
record["completion_sound"] = completion_sound
@@ -691,16 +727,20 @@ class _CachedAttrsSensor(TaskMateBaseSensor):
def __init__(self, coordinator: TaskMateCoordinator, entry: ConfigEntry) -> None:
super().__init__(coordinator, entry)
self._cached_attrs: dict | None = None
self._cached_data_id: int | None = None
self._cached_key: tuple[int, int] | None = None
@property
def extra_state_attributes(self) -> dict:
data_id = id(self.coordinator.data)
if self._cached_data_id == data_id and self._cached_attrs is not None:
# The coordinator reuses one snapshot object while storage.data_version
# is unchanged, so id(data) alone would pin these attributes forever
# when only an external entity moved — stranding the visibility and
# weather gates on stale state. external_state_version covers that.
key = (id(self.coordinator.data), getattr(self.coordinator, "external_state_version", 0))
if self._cached_key == key and self._cached_attrs is not None:
return self._cached_attrs
attrs = self._build_attributes()
self._cached_attrs = attrs
self._cached_data_id = data_id
self._cached_key = key
return attrs
def _build_attributes(self) -> dict: # pragma: no cover - abstract