Feature area
Integration logic/state
Problem or use case
This issue targets two independent scalability axes: household size (more users, more chores) and gamification complexity (more types; badge, achievements, and challenges added in future development). Entity count grows along both axes simultaneously, and the problem compounds as ChoreOps adds new gamification object types.
ChoreOps generates entities at roughly O(users × chores × gamification_objects). The main drivers are:
- 3 buttons per (user, chore) pair: claim, approve, disapprove
- 3 buttons per (user, reward) pair: redeem, approve, disapprove
- 1 progress sensor per (user, badge), (user, achievement), (user, challenge)
- 1 status sensor per (user, reward)
A household of 4 users, 10 chores, and 10 gamification objects (5 badges, 5 achievements, no challenges or rewards) generates roughly 400 entities. A more feature-complete setup with rewards and challenges grows that number significantly.
This matters because HA's core architecture is affected by entity count in several ways:
- The HA WebSocket API pushes all entity state changes to all connected clients without server-side filtering. Community reports suggest performance degrades noticeably above 1,000 entities, though this is not an officially documented threshold. [WebSocket API] [Community discussion]
- The recorder writes state changes to the database in 5-second batches by default. Write volume scales roughly as
entity_count × update_frequency. ChoreOps entities are low-frequency, but at sufficient count the aggregate write volume is non-trivial, and it grows unbounded as users add chores and gamification objects.
- Every registered entity occupies a slot in the entity registry, the in-memory state machine, and the WebSocket broadcast surface, regardless of how often it updates.
The exact threshold at which this becomes a practical problem on typical household hardware (Raspberry Pi, SQLite, Home Assistant OS) is unclear and worth benchmarking officially somehow, maybe for the most "typical" HA hardware. An option could also be a discussion thread where people state their hardware and number of entities by group (e.g. 4 people, 20 chores, 10 gamification objects)
Proposed solution
I am still figuring out HA's inner workings (and this repo), but I think the following are a good starting point, where the changes address the majority of entity growth:
1. Replace action button entities with HA services
Claim, approve, and disapprove actions on chores and rewards don't require persistent entity state. HA's service system supports parameterized calls with typed selectors (chore_id, user_id), which replaces the current button-per-(user, object) pattern. This removes the single largest contributor to entity count and keeps the total flat regardless of how many chores or users are added.
Migration note: Implementing this would be a breaking change. The bundled dashboard templates in dashboards/ currently render claim, approve, and disapprove buttons as entity cards. Removing those button entities requires regenerating the dashboard templates via dashboard_builder.py before this change would ship. The notification action handler (notification_action_handler.py) routes actionable notification buttons that mirror the same claim/approve/disapprove surface and must also be reviewed.
2. Gate progress sensor creation behind a config option
Per-(user, badge), per-(user, achievement), and per-(user, challenge) progress sensors exist to expose gamification state to HA automations (e.g., triggering when badge progress reaches a threshold). Core ChoreOps functionality, the dashboard, badge awarding, notifications, does not depend on them. Most users will never need them, so creating them by default generates entities with no practical benefit for those households.
The fix is an options flow toggle, off by default. When off, async_add_entities is never called for these sensors and no entities are created. Users who want automation access enable the toggle once, and the config entry reloads and creates the sensors. ChoreOps already uses this dynamic creation pattern via signal handlers for chore and badge entities, so no new infrastructure is required. [Entity registry properties]
Note: ChoreOps already has per-user should_create_gamification_entities() and should_create_workflow_buttons() gates in entity_helpers.py. These operate at the individual user profile level (feature-gated profiles), not as a global system setting. should_create_gamification_entities() is also broader in scope than this proposal, it gates reward buttons, bonus and penalty buttons, and points adjust buttons in addition to progress sensors. The proposed toggle is narrower (progress sensors only) and coarser (global, not per-user): a system-wide off switch that prevents progress sensor creation for all users regardless of profile type.
3. Apply always_update=False to DataUpdateCoordinator
Setting always_update=False on the DataUpdateCoordinator prevents redundant callbacks when data hasn't changed, provided the data supports equality comparison via __eq__. For infrequently-changing entities this reduces recorder volume with no behavioral change. [Fetching data]
The coordinator's data is a single nested dict containing all users, chores, badges, rewards, and related state. Python's dict __eq__ compares by value recursively, so each update triggers a full deep-equality scan of the entire application state. On a large household this comparison is not free, and the benefit (skipping callbacks when nothing changed) should be verified to outweigh its cost before shipping. always_update is not currently set in the codebase, so this is a new addition.
A fourth option worth investigating separately: aggregating per-user progress into a single JSON-attribute sensor per user instead of N individual sensors. HA generally recommends against this for high-frequency attributes due to database bloat, but ChoreOps progress data is low-frequency and may be a reasonable fit.
4. Chore parameterization via label rotation
More of an example of how design can reduce the number of chores; Repetitive chores that vary only by a single parameter (room, person, location) can be modeled as separate chores, each generating its own entity set. Simplified example: A user vacuuming 7 rooms, could creates 7 chores for each room where 1 chore would suffice if the room were a rotating label. Adding label rotation to chore definitions would allow a single chore to cycle through a predefined list on a schedule, reducing N similar chores to 1. This requires new functionality rather than refactoring, but directly addresses entity growth for common household patterns.
Expected outcome
Reduction in total entity count. The dominant scaling term shifts from O(users × (chores + gamification_objects)) to O(users × chores), as buttons are replaced by services and entity generation is decoupled from gamification object creation. Creating a badge or achievement no longer automatically generates per-user progress sensor entities. With label rotation (4), the chores term itself shrinks for repetitive task patterns. Recorder write volume decreases proportionally to entities removed and callbacks eliminated.
Alternatives considered
None that better scale the system.
Additional context
This should be a tracking issue for future releases. Each proposed change should be broken into a separate implementation issue with this as the upper level:
- Replace chore and reward button entities with services
- Gate progress sensor creation behind an options flow toggle
- Apply
always_update=False to DataUpdateCoordinator
- Investigate the aggregate JSON-attribute sensor pattern for per-user progress data
- Investigate chore label rotation as a mechanism for reducing similar-chore proliferation
Feature area
Integration logic/state
Problem or use case
This issue targets two independent scalability axes: household size (more users, more chores) and gamification complexity (more types; badge, achievements, and challenges added in future development). Entity count grows along both axes simultaneously, and the problem compounds as ChoreOps adds new gamification object types.
ChoreOps generates entities at roughly O(users × chores × gamification_objects). The main drivers are:
A household of 4 users, 10 chores, and 10 gamification objects (5 badges, 5 achievements, no challenges or rewards) generates roughly 400 entities. A more feature-complete setup with rewards and challenges grows that number significantly.
This matters because HA's core architecture is affected by entity count in several ways:
entity_count × update_frequency. ChoreOps entities are low-frequency, but at sufficient count the aggregate write volume is non-trivial, and it grows unbounded as users add chores and gamification objects.The exact threshold at which this becomes a practical problem on typical household hardware (Raspberry Pi, SQLite, Home Assistant OS) is unclear and worth benchmarking officially somehow, maybe for the most "typical" HA hardware. An option could also be a discussion thread where people state their hardware and number of entities by group (e.g. 4 people, 20 chores, 10 gamification objects)
Proposed solution
I am still figuring out HA's inner workings (and this repo), but I think the following are a good starting point, where the changes address the majority of entity growth:
1. Replace action button entities with HA services
Claim, approve, and disapprove actions on chores and rewards don't require persistent entity state. HA's service system supports parameterized calls with typed selectors (
chore_id,user_id), which replaces the current button-per-(user, object) pattern. This removes the single largest contributor to entity count and keeps the total flat regardless of how many chores or users are added.Migration note: Implementing this would be a breaking change. The bundled dashboard templates in
dashboards/currently render claim, approve, and disapprove buttons as entity cards. Removing those button entities requires regenerating the dashboard templates viadashboard_builder.pybefore this change would ship. The notification action handler (notification_action_handler.py) routes actionable notification buttons that mirror the same claim/approve/disapprove surface and must also be reviewed.2. Gate progress sensor creation behind a config option
Per-(user, badge), per-(user, achievement), and per-(user, challenge) progress sensors exist to expose gamification state to HA automations (e.g., triggering when badge progress reaches a threshold). Core ChoreOps functionality, the dashboard, badge awarding, notifications, does not depend on them. Most users will never need them, so creating them by default generates entities with no practical benefit for those households.
The fix is an options flow toggle, off by default. When off,
async_add_entitiesis never called for these sensors and no entities are created. Users who want automation access enable the toggle once, and the config entry reloads and creates the sensors. ChoreOps already uses this dynamic creation pattern via signal handlers for chore and badge entities, so no new infrastructure is required. [Entity registry properties]Note: ChoreOps already has per-user
should_create_gamification_entities()andshould_create_workflow_buttons()gates inentity_helpers.py. These operate at the individual user profile level (feature-gated profiles), not as a global system setting.should_create_gamification_entities()is also broader in scope than this proposal, it gates reward buttons, bonus and penalty buttons, and points adjust buttons in addition to progress sensors. The proposed toggle is narrower (progress sensors only) and coarser (global, not per-user): a system-wide off switch that prevents progress sensor creation for all users regardless of profile type.3. Apply
always_update=Falseto DataUpdateCoordinatorSetting
always_update=Falseon theDataUpdateCoordinatorprevents redundant callbacks when data hasn't changed, provided the data supports equality comparison via__eq__. For infrequently-changing entities this reduces recorder volume with no behavioral change. [Fetching data]The coordinator's data is a single nested dict containing all users, chores, badges, rewards, and related state. Python's dict
__eq__compares by value recursively, so each update triggers a full deep-equality scan of the entire application state. On a large household this comparison is not free, and the benefit (skipping callbacks when nothing changed) should be verified to outweigh its cost before shipping.always_updateis not currently set in the codebase, so this is a new addition.A fourth option worth investigating separately: aggregating per-user progress into a single JSON-attribute sensor per user instead of N individual sensors. HA generally recommends against this for high-frequency attributes due to database bloat, but ChoreOps progress data is low-frequency and may be a reasonable fit.
4. Chore parameterization via label rotation
More of an example of how design can reduce the number of chores; Repetitive chores that vary only by a single parameter (room, person, location) can be modeled as separate chores, each generating its own entity set. Simplified example: A user vacuuming 7 rooms, could creates 7 chores for each room where 1 chore would suffice if the room were a rotating label. Adding label rotation to chore definitions would allow a single chore to cycle through a predefined list on a schedule, reducing N similar chores to 1. This requires new functionality rather than refactoring, but directly addresses entity growth for common household patterns.
Expected outcome
Reduction in total entity count. The dominant scaling term shifts from O(users × (chores + gamification_objects)) to O(users × chores), as buttons are replaced by services and entity generation is decoupled from gamification object creation. Creating a badge or achievement no longer automatically generates per-user progress sensor entities. With label rotation (4), the chores term itself shrinks for repetitive task patterns. Recorder write volume decreases proportionally to entities removed and callbacks eliminated.
Alternatives considered
None that better scale the system.
Additional context
This should be a tracking issue for future releases. Each proposed change should be broken into a separate implementation issue with this as the upper level:
always_update=Falseto DataUpdateCoordinator