Skip to content

feat: Advisor 'Current Decision' sensor + dashboard banner (v1.14.0) - #17

Merged
cm-makes merged 1 commit into
mainfrom
feat/advisor-current-decision
Jul 15, 2026
Merged

feat: Advisor 'Current Decision' sensor + dashboard banner (v1.14.0)#17
cm-makes merged 1 commit into
mainfrom
feat/advisor-current-decision

Conversation

@cm-makes

Copy link
Copy Markdown
Owner

What

Decision transparency for AURUM — a single sensor that answers "what is AURUM doing right now, and why?" Ported conceptually from the HELIOS parent project, rebuilt from scratch for AURUM's per-device model.

New: sensor.aurum_current_decision

  • State = stable ENUM decision code, localised EN/DE via translation_key: running_solar, running_cheap_grid, running, waiting, battery_charging, startup, idle
  • Attributes = structured breakdown for dashboards: battery mode, price context, device counts, and a per-device list with a machine-readable reason code each (solar_surplus, solar_pv, cheap_grid, manual_override, forced_deadline, runtime_done, program_done, program_paused, program_standby, battery_charging, below_soc_threshold, condition_not_met, disabled, waiting_surplus)

New: Dashboard panel banner

☀️ Running on solar surplus · 2/3 active · ⚡ 1240 W · 💶 18.4 ct/kWh

  • Headline via hass.formatEntityState() → every HA language, EN/DE fallback for older frontends
  • Device cards show translated reasons ("→ solar surplus", "→ disabled (force-off)") instead of raw scheduling_reason codes

Design guarantees

  • Pure & safe: AdvisorManager is a pure function of shared state — no HA polling, no control side effects; invoked from the update loop's finally block (single exit — no future early-return can forget it, startup grace included)
  • No recorder churn: attributes deliberately carry no watts/timestamps; idle periods generate zero recorder writes — live numbers stay in the dedicated numeric sensors
  • No vocabulary drift: scheduling reasons are now shared SCHED_REASON_* constants in const.py; devices.py publishes authoritative off-reasons (disabled, condition_met) so consumers don't re-derive control logic
  • current_decision added to reserved device-name slugs

Review

8-angle multi-agent code review before commit caught and fixed pre-merge: a 100× price display bug (ct vs EUR unit), the default surplus_available reason not mapping to running_solar (flagship case), attribute churn defeating the recorder design, an idle-flash on restart, and misleading off-reasons for disabled/condition-gated/SD-standby devices.

Testing

  • 17 new unit tests for the advisor (decision aggregation + full reason mapping)
  • Full suite green: 189 passed (incl. smoke tests: JSON validity, version sync, compile checks)
  • node --check on the panel JS

🤖 Generated with Claude Code

https://claude.ai/code/session_01QLgEATa2NRuvft5vU4D5N3

Decision transparency ported from HELIOS, rebuilt for AURUM's
per-device model. sensor.aurum_current_decision (ENUM, translation_key,
EN/DE) answers "what is AURUM doing right now, and why"; attributes
carry a structured per-device reason list for dashboards. The sidebar
panel renders a decision banner (headline via hass.formatEntityState)
and translated per-device reason lines.

- AdvisorManager: pure function of shared state, invoked from the
  update loop's finally block (single exit, covers startup grace)
- No fast-changing numbers in attributes (no watts/timestamps) so idle
  periods generate no recorder writes
- devices.py publishes authoritative off-reasons (disabled,
  condition_met); scheduling reasons are shared SCHED_REASON_*
  constants in const.py so producer and consumers can't drift
- current_decision added to reserved device-name slugs
- 17 unit tests; full suite green (189)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLgEATa2NRuvft5vU4D5N3
@cm-makes
cm-makes merged commit cad89f5 into main Jul 15, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant