mirror of
https://github.com/cassandra/home-information.git
synced 2026-06-12 01:25:39 -04:00
* Introduce EntityStateRole for semantic role per EntityState Adds a first-class semantic-role concept to EntityState so the data model can express what each state means within its enclosing entity. Resolves the multi-of-same-type case (a thermostat's four TEMPERATURE substates; a fan's two DISCRETE substates) and replaces the legacy EntityStateType-priority pre-filter that bucketed icon display by type rather than per-entity primary state. Schema and model - New EntityStateRole(LabeledEnum) in hi/apps/entity/enums.py with two tiers: type-default roles (one per EntityStateType, name- matched) and domain-prefixed refinements (THERMOSTAT_*, FAN_*, LIGHT_*, HVAC_*). - New EntityStateType.default_role() method. - New EntityState.role_str field + entity_state_role property / setter. Save() defaults role_str to the type's default when not set explicitly, so direct EntityState.objects.create() paths get a role automatically. - Migration 0016 backfills existing rows with their type-default role; behavior pre-refinement is unchanged. Factory and HA integration - HiModelHelper.create_sensor / create_controller gain an optional entity_state_role parameter; threaded through to EntityState creation when provided. - HassConverter._SubstateSpec renamed _StateSpec; new role field on the spec. Climate / fan / light substate spec lists assign domain-prefixed roles for the multi-of-same-type cases. Modal listing order - New EntityStateRoleOrdering class + module-level ENTITY_STATUS_VIEW_ORDERING instance in hi/apps/entity/entity_state_role_order.py with per-EntityType override maps. - EntityStatusData.to_template_context() emits state_status_data_list (sorted by role priority); the underlying field stays order- neutral for non-modal consumers. LocationView icon primary-state selection - ENTITY_PRIMARY_STATE_ORDERING (separate instance) selects the primary state for entity-level visual representation. - LocationViewData._get_latest_entity_state_status_data_map switched from timestamp-sort to role-priority sort. - StatusDisplayManager.get_entity_to_entity_state_status_data_list no longer pre-filters by EntityStateType priority; returns all states (including delegations). Shared _all_entity_states_including_delegations helper introduced. - LocationViewData._get_css_class_map now emits exactly one hi-entity-state-* class per entity (the primary state's), so per-state polling updates don't clobber the entity's status attribute via shared CSS classes. EntityStatusView template dispatch - entity_status.html outer wrapper dispatches via include_with_fallback to per-EntityType templates; entity_status_default.html carries the existing flat-list body. Placeholder thermostat / ceiling_fan templates establish the customization pattern. Decision-point markers - LocationViewType and OneClickControlService._find_controller carry comments noting the legacy entity_state_type_priority_list is retained for one-click, pending a parallel ENTITY_CONTROL_STATE_ORDERING follow-up. Docs - integration-guidelines.md gains "EntityStateType vs. EntityStateRole" section explaining the two axes and the integration's role-declaration responsibility. Closes #319 (with manual verification of thermostat / fan / icon status behavior). Audit of EntityStateType vs role conflation (MOVEMENT vs PRESENCE, POWER_LEVEL vs LIGHT_DIMMER) and one-click ordering consolidation are out of scope and tracked as follow-ups. * Migrate OneClickControlService to role-based selection; drop legacy type-priority filter Completes the role-mechanism conversion: one-click control no longer consults LocationViewType.entity_state_type_priority_list and instead walks ENTITY_CONTROL_STATE_ORDERING for the entity's EntityType. The legacy type-priority pre-filter on LocationViewType is removed entirely along with its dead consumers in StatusDisplayManager. OneClickControlService - execute_one_click_control and _find_controller no longer take a location_view_type kwarg. The view-level "only AUTOMATION invokes one-click" gate remains at LocationItemStatusView. - _find_controller walks ENTITY_CONTROL_STATE_ORDERING.order_for strictly: only states whose role is listed are eligible. Unlisted roles (e.g., a thermostat's THERMOSTAT_TARGET_TEMPERATURE) are not one-click targets even when controllable. - _is_toggle_eligible helper extracted to keep the picker honest (only states with toggle_values within ONE_CLICK_CHOICE_LIMIT qualify). ENTITY_CONTROL_STATE_ORDERING - New EntityStateRoleOrdering instance with a curated default list of universally safe-to-toggle roles: ON_OFF, OPEN_CLOSE, OPEN_CLOSE_POSITION, POWER_LEVEL, LIGHT_DIMMER. Binary roles come first so they win when both binary and continuous variants exist. - Per-EntityType overrides for LIGHT (LIGHT_ON_OFF + LIGHT_BRIGHTNESS), CEILING_FAN / EXHAUST_FAN (FAN_SPEED), GARAGE_DOOR_OPENER (OPEN_CLOSE). Switches / outlets / locks rely on the default ON_OFF fallback. Legacy removals - LocationViewType.entity_state_type_priority_list and its __init__ override are gone; the enum collapses to plain DEFAULT / SECURITY / AUTOMATION members carrying just label and description. - StatusDisplayManager.get_entity_state_list_for_status and get_entity_state_type_for_status removed (their last consumer was one-click; the icon path stopped using them earlier in #319). Tests - New test_one_click_control_service.py covers: default fallback for unrecognized EntityTypes; LIGHT override preferring LIGHT_ON_OFF; LIGHT_BRIGHTNESS fallback for fully-modeled color bulbs; speed-only fan via POWER_LEVEL default; cover with OPEN_CLOSE_POSITION via default; sensor-only and thermostat cases correctly NotSupported; toggle-value-limit guard. * Fix collection card sensor polling updates and apply role ordering to collection cards Audit of CollectionView rendering surfaced two issues that #319's work touched indirectly: Sensor values not updating from polling - Collection card sensor renders did not wrap the value template in the per-EntityState CSS class, so the entity_state_status.js dispatcher had no DOM target for `.hi-entity-state-{id}` polling updates. Controllers worked because controller_data.html carries the class itself; sensor-only states (thermometer, humidity, etc.) silently never updated. - entity_state_row.html now wraps the value include in a div with sensor_response.css_class, matching the modal's pattern in sensor_response_status_row.html. State ordering inconsistency between modal and collection cards - EntityStatusData.state_status_data_list promoted from a local in to_template_context() to a public property. The modal continues to consume it via the template context; collection card templates now access it directly on the dataclass instead of reading the unordered entity_state_status_data_list field. Single source of truth for "display order" across both surfaces. - entity_card_list.html and entity_card_grid.html updated to pass entity_status_data.state_status_data_list into the partial. * New urlib3 version with security patch * Rename "wire value" to "EntityState value" in canonical-value docstrings The term "wire value" is appropriate for integration-boundary code where values genuinely travel over a wire (HA REST/WS payloads). Internally, once an EntityState has stored its value, it is the canonical EntityState value, not a wire-format string. Updating docstrings, parameter names, and local variable names in EntityStateValue.to_display_label, EntityState.choices, value_label tag, and associated tests to match. * Promote delegations helper, dedup result, prefetch hot path, add review-cycle test Review-cycle follow-ups for the EntityStateRole work: - Rename ``StatusDisplayManager._all_entity_states_including_delegations`` to ``all_entity_states_including_delegations`` (public). It is called from OneClickControlService and reaching across module boundaries to a private helper is an antipattern. - Deduplicate the helper's return list to guard against entities that delegate one of their own states or that have two delegations resolving to the same EntityState. - Add a one-shot ``prefetch_related_objects`` in ``get_entity_to_entity_state_status_data_list`` covering the entity states, delegations, sensors, and controllers walked downstream. On a LocationView with 20 entities of ~3 states each this collapses from ~160 queries per render to ~6. Drop the now-defeated ``select_related('entity_state')`` inside the helper so prefetched callers actually use the cache; the FK fetch cost for non-prefetched callers is bounded. - Add comments documenting two intentional choices: EntityStateRole's label collisions between bare and domain-refined roles, and the intentional absence of sensor-only roles from ``DEFAULT_CONTROL_STATE_ROLE_ORDER``. - Add ``execute_one_click_control`` end-to-end tests pinning the full pipeline (find_controller → get_current_state_value → determine_control_value → ControllerManager.do_control) for both the "toggle from known state" and "no sensor history" branches.