Skip to content

Technical: Chores

ccpk1 edited this page Mar 14, 2026 · 7 revisions

Audience: automation builders, dashboard authors, and developer-mode users.

Important

This page documents technical contracts (sensor state/attributes, naming behavior, and automation-safe access). Functional setup and business behavior live in Chore Configuration Guide and Chore Advanced Features.


Scope: two core chore sensors

This reference focuses on the two most important chore entities:

  • sensor.<user>_choreops_chores
  • sensor.<user>_choreops_chore_status_<chore>

Both are Home Assistant native entities. Entity IDs and display names are auto-generated, can vary by locale/naming rules, and users can rename entities as needed.


Supported scheduling contract

ChoreOps now treats due dates as part of the supported recurrence contract.

  • none and daily may omit a due date
  • weekly, biweekly, monthly, custom interval, custom from completion, and daily_multi are expected to have a due date
  • If a chore should repeat without ever becoming late, use a due date plus never overdue

This keeps recurrence forecasting, calendar generation, due windows, and approval-boundary behavior anchored to the same schedule source.

No-due-date behavior

  • No-due-date daily chores are supported
  • For no-due-date daily, applicable_days works as weekday gating
  • No-due-date chores are excluded from calendar event generation

Legacy upgrade behavior

Existing stored chores from older versions are not automatically deleted or rewritten on load just because they use a now-unsupported combination.

That means an older recurring chore without a due date can still exist after upgrade, but it is considered legacy data rather than a fully supported configuration.

Practical effect:

  • The chore can remain in storage after upgrade
  • New create/edit/save paths now require a due date for recurrence types outside none and daily
  • The standalone due-date service now also rejects clearing the due date for those recurrence types
  • Calendar and recurrence behavior for those legacy chores should not be relied on until a due date is added

Recommended remediation for existing users:

  1. Open the chore and add a due date
  2. If you do not want it to become late, set overdue handling to never overdue
  3. Save the chore so it is back on the supported scheduling contract

Entity naming and stability

  • Entity IDs are now generated by Home Assistant native naming rules and are created with names in local language
  • Names can differ across installations and can be renamed by users.
  • Stable contract for automations is the exposed state/attribute surface (for example can_claim, can_approve, claim_button_eid, approve_button_eid, disapprove_button_eid) rather than assumed naming patterns.

Example IDs you may see:

  • sensor.alex_choreops_chores
  • sensor.alex_choreops_chore_status_brush_teeth_am
  • button.alex_choreops_chore_disapproval_brush_teeth_am

Sensor contract: chore aggregate sensor

Purpose

Aggregated chore statistics for one user (today/week/month/year/all-time + snapshot counters).

State

  • Native state is the all-time approved count used as the sensor value.

Attribute shape

  • Identity: purpose, user_name
  • Stats are exposed with chore_stat_ prefix

High-value attribute groups:

  • Current snapshot: chore_stat_current_due_today, chore_stat_current_claimed, chore_stat_current_approved, chore_stat_current_overdue
  • Today/Week/Month/Year totals: approved, claimed, missed, completed, points
  • All-time totals: approved_all_time, claimed_all_time, missed_all_time, completed_all_time, points_all_time
  • Streaks: chore_stat_longest_streak, chore_stat_longest_missed_streak
  • Averages: chore_stat_avg_per_day_week, chore_stat_avg_per_day_month, chore_stat_avg_per_day_year
  • Top chores: chore_stat_top_chores_week, chore_stat_top_chores_month, chore_stat_top_chores_year

These map to the rich dashboard rows such as:

  • Current Due Today / Current Claimed / Current Approved / Current Overdue
  • Approved/Claimed/Missed/Completed/Points across time windows
  • Average Per Day (Week/Month/Year)
  • Top Chore (Week/Month/Year)

Sensor contract: chore status sensor

Purpose

One sensor per user+chore pair with lifecycle state, timing context, actionable flags, and per-chore performance stats.

State values

Operational values include:

  • pending, due, claimed, approved, overdue
  • waiting, not_my_turn, missed, completed_by_other
  • claimed_in_part, approved_in_part (group/global contexts)

Attribute groups

Identity and metadata:

  • purpose, user_name, chore_name, description, assigned_users, labels

Configuration snapshot:

  • default_points, completion_criteria, approval_reset_type, recurring_frequency, applicable_days

Time and availability context:

  • due_date, due_window_start, available_at, time_until_due, time_until_overdue, approval_period_start
  • Rotation/locks: global_state, lock_reason, turn_user_name

Actionability and button pointers:

  • can_claim, can_approve
  • claim_button_eid, approve_button_eid, disapprove_button_eid

Per-chore performance metrics:

  • Counts: chore_points_earned, chore_claims_count, chore_completed_count, chore_approvals_count, chore_disapproved_count, chore_overdue_count, chore_missed_count
  • Streaks: chore_current_streak, chore_longest_streak, chore_current_missed_streak, chore_longest_missed_streak, chore_last_longest_streak_date
  • Last-event timestamps: last_claimed, last_approved, last_completed, last_disapproved, last_overdue, chore_last_missed
  • Attribution: claimed_by, completed_by

Conditional attributes:

  • custom_frequency_interval, custom_frequency_unit (when recurring frequency is custom)
  • chore_approvals_today (for multi-approval reset modes and upon-completion reset)

Automation-safe patterns

1) Gate by computed booleans, not assumed state text

Use can_claim and can_approve from the status sensor to decide action availability.

2) Press buttons via pointer attributes

Read button IDs from status sensor attributes instead of constructing button entity IDs.

{% set s = 'sensor.alex_choreops_chore_status_brush_teeth_am' %}
{% set can_claim = state_attr(s, 'can_claim') %}
{% set claim_button = state_attr(s, 'claim_button_eid') %}
{{ can_claim and claim_button is not none }}

3) Treat entity IDs as runtime values

For reusable blueprints or packages, resolve entity IDs from the registry/UI selection, not string concatenation.


Chore State Processing Architecture

Five Logic Drivers

Chore state is determined by the interaction of five configuration drivers:

Driver Controls Constants Engine Method
1. Completion Criteria Who must complete (independent, shared, rotation) COMPLETION_CRITERIA_* calculate_transition()
2. Recurring Frequency How often chore recurs FREQUENCY_* (schedule_engine.py)
3. Approval Reset Type When approved chores reset to pending APPROVAL_RESET_* should_process_at_boundary()
4. Pending Claim Action What happens to pending claims at reset APPROVAL_RESET_PENDING_CLAIM_* calculate_boundary_action()
5. Overdue Handling What happens when due date passes OVERDUE_HANDLING_* calculate_boundary_action()

State Formula: State = f(CompletionCriteria, Frequency, ApprovalResetType, PendingClaimAction, OverdueHandling)

Chore State quick reference

Use this as the practical interpretation of chore status in dashboards and sensors.

Per-user status (what each assignee sees)

These states are assignee-specific and can differ between users for the same chore:

  • pending
  • due
  • waiting
  • claimed
  • overdue
  • missed
  • not_my_turn
  • completed
  • completed_by_other

Notes:

  • completed is the display state for approved work in the current period.
  • completed_by_other is a blocker display state for non-actor assignees in first-claimer modes.

Global status (shared/global chore summary)

These states summarize the chore across all assigned users:

  • pending
  • due
  • waiting
  • claimed
  • completed
  • completed_in_part
  • overdue
  • missed
  • independent
  • claimed_in_part

Important mapping rule:

  • Persisted partial state approved_in_part is published as global UI state completed_in_part.

How to reason about mismatches:

  • Stored workflow state tracks checkpoints (approved, approved_in_part).
  • Display state is user-facing projection (completed, completed_in_part).
  • This means stored and displayed labels can intentionally differ while still representing the same lifecycle outcome.

Processing Boundaries

Chore state changes occur at two distinct boundaries:

1. User Action Boundary (Synchronous, Locked)

  • Triggers: claim, approve, disapprove, undo actions
  • Protection: asyncio.Lock per (assignee_id, chore_id) prevents race conditions
  • Processing: Immediate state transition via ChoreEngine
  • Location: chore_manager.py _claim_chore_locked(), _approve_chore_locked(), etc.

2. Time Boundary (Asynchronous, Batched)

  • Triggers: midnight_rollover, periodic_update (every ~5 min)
  • Processing Order (Phase 1): Reset-Before-Overdue (prevents Gremlin #1)
  • Batching: Single persist at end of pipeline (Phase 1)
  • Location: chore_manager.py _on_midnight_rollover(), _on_periodic_update()

Pipeline Hardening

Invariant 1: Single State Per Tick

  • Each (assignee_id, chore_id) pair modified at most once per pipeline run
  • Enforced by: Set-based exclusion (Phase 1) + debug tracking (Phase 4)
  • Debug flag: const.DEBUG_PIPELINE_GUARDS

Invariant 2: Idempotent Processing

  • Running same scan twice produces same result
  • _process_overdue() skips if already OVERDUE (Phase 4)
  • _process_approval_reset_entries() checks current state before transitioning

Invariant 3: Persist-Once-Per-Batch

  • All state changes batched, then single _persist() call
  • Reduces SD card writes from O(n) to O(1)
  • Implementation: persist=False parameter in processing methods

Valid vs Gremlin Combinations

Valid Configurations:

  • UPON_COMPLETION + any frequency → Resets immediately on approval
  • AT_MIDNIGHT_ONCE + FREQUENCY_DAILY → Classic daily chore
  • AT_DUE_DATE_* + FREQUENCY_WEEKLY → Due date triggers reset
  • MANUAL + any frequency → Never auto-resets (Phase 3)

Gremlin Scenarios (Prevented by Pipeline Reorder):

  1. Overdue-After-Approval: Chore approved at midnight → reset to PENDING → immediately OVERDUE
    • Prevention: Reset processes BEFORE overdue check
  2. Double-Processing: Chore in both reset AND overdue lists
    • Prevention: Set-based exclusion filters overdue list after reset
  3. Non-Recurring Past Due: FREQUENCY_NONE chore approved after due date → reschedules → goes OVERDUE
    • Prevention: Clear due date on UPON_COMPLETION for non-recurring chores

Troubleshooting checks

  • In Developer Tools → States, confirm expected chore sensors exist for the target user profile.
  • Verify purpose to ensure you are reading the intended sensor contract.
  • If action buttons do not work, inspect claim_button_eid / approve_button_eid / disapprove_button_eid first.
  • If timing appears wrong, inspect due_date, due_window_start, available_at, time_until_due, and time_until_overdue on the status sensor.

Source of truth for this page

  • Sensor implementations: custom_components/choreops/sensor.py
  • Attribute and key constants: custom_components/choreops/const.py
  • User-visible names/states: custom_components/choreops/translations/en.json

Related documentation

Clone this wiki locally