Skip to content

feat: live dashboard strategy (custom:givenergy) for #131#132

Merged
dewet22 merged 3 commits into
mainfrom
claude/sad-mendeleev-93dfa6
Jun 5, 2026
Merged

feat: live dashboard strategy (custom:givenergy) for #131#132
dewet22 merged 3 commits into
mainfrom
claude/sad-mendeleev-93dfa6

Conversation

@dewet22

@dewet22 dewet22 commented Jun 5, 2026

Copy link
Copy Markdown
Owner

Closes #131 (v1 — the classic strategy).

What this adds

A Lovelace dashboard strategy (custom:givenergy) that builds the existing six-tab dashboard but resolves every entity from the live registry on each render, so it can't silently rot the way the static generate_dashboard YAML does. It resolves by unique_id ({serial}_{key}) rather than constructing entity_ids, which makes it structurally immune to the HA 2026.6 area-prefix re-slug (sensor.loft_givenergy_…) that was leaving most cards dangling on my own install after I moved the inverter into an area.

Usage — create a dashboard, open the raw config editor, and set:

strategy:
  type: custom:givenergy
  mode: classic
  max_power_kw: 10     # optional
  serial: SA2114G047   # optional, multi-plant pin

Notes

  • The old standalone ge-cell-heatmap.js is merged into the strategy module, so one file now serves both custom:givenergy and custom:ge-cell-heatmap. Both gained an area-prefix-agnostic entity lookup (the heatmap was still constructing entity_ids directly and broke under the same re-slug); the strategy additionally skips disabled entities so their rows don't dangle.
  • generate_dashboard stays as the editable static "eject" path — nothing changes there for existing users.
  • Added a small vitest harness (mock hass) mirroring the Python test_dashboard.py discipline, plus a Python parity guard that pins every key the strategy references to a real EntityDescription.key, so a renamed key fails loudly here rather than dangling silently. New js tests CI job runs the vitest suite.

Known limitation

On a hard refresh (cache bypass) the strategy can occasionally hit HA's "Timeout waiting for strategy element" — a 5-second registration window that a cold module re-fetch can lose when queued behind other custom-card resources. This affects all network-loaded HA strategies, not just this one; a normal reload serves from cache and isn't affected. Documented in the README. I didn't want to ship the fragile workaround (registering an inline Lovelace resource by poking the resource collection) for an edge case that only bites manual hard-reloads.

Testing

  • 257 Python + 15 JS tests green; ruff/mypy/codespell clean.
  • Verified live on my own install (2-battery plant, inverter in an area so entity_ids carry the loft_ prefix): all six views render and resolve correctly.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Introduced a custom dashboard strategy (custom:givenergy) that dynamically generates Lovelace dashboards from live Home Assistant data, automatically resolving entities and persisting across renames.
    • Added cell-heatmap visualization for battery cell-balance monitoring.
  • Documentation

    • Added configuration guide for the new dashboard strategy with classic layout support.
  • Chores

    • Enhanced testing infrastructure with automated CI/CD workflow and test suite setup.

Adds a Lovelace dashboard strategy that reproduces the six-tab "classic"
dashboard but resolves every entity from the live registry on each render,
so it never goes stale when a device moves area or an entity is renamed.
Resolution is by unique_id ({serial}_{key}) via the entity registry, which
is structurally immune to the HA 2026.6 area-prefix re-slug that rotted the
static generated YAML.

The bundled ge-cell-heatmap card is merged into the same module, so one JS
file serves both custom:givenergy and custom:ge-cell-heatmap. Both gain an
area-prefix-agnostic entity lookup; the strategy additionally skips disabled
entities so their rows don't dangle.

Adds a vitest JS harness mirroring the Python dashboard tests, a Python
parity guard pinning every key the strategy references to a real
EntityDescription.key, and a JS CI job. generate_dashboard remains as the
static eject path.

Refs #131

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 5, 2026

Copy link
Copy Markdown

Too much diff to scan? Review this PR in Change Stack to start with the highest-impact changes.

Review Change Stack

Warning

Review limit reached

@dewet22, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 41 minutes and 47 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8711c612-8c82-446f-9fec-768f6608e040

📥 Commits

Reviewing files that changed from the base of the PR and between 1008546 and 1bdbedc.

📒 Files selected for processing (4)
  • README.md
  • custom_components/givenergy_local/www/ge-strategy.js
  • tests/js/ge-strategy.test.js
  • tests/js/mock-hass.js
📝 Walkthrough

Walkthrough

This PR introduces a Lovelace dashboard strategy (custom:givenergy) that dynamically generates a multi-tab GivEnergy dashboard from Home Assistant's entity registry, replacing static YAML generation. The strategy discovers inverter and battery devices, resolves entities by unique_id to handle renames and area moves, supports plant pinning and EMS-specific views, and gracefully degrades when optional custom cards are unavailable.

Changes

Live dashboard strategy with registry-driven discovery

Layer / File(s) Summary
Test infrastructure and CI setup
package.json, vitest.config.js, .github/workflows/validate.yml, .gitignore
Node test runner configured with vitest; GitHub Actions js-tests job runs tests on Node.js 20; frontend dependencies ignored.
Dashboard strategy registration and plant discovery
custom_components/givenergy_local/www/ge-strategy.js (lines 1–156)
Registers ll-strategy-dashboard-givenergy custom element; queries entity/device registries; classifies devices and builds unique_id→entity_id maps; selects target plant by serial option or defaults to first inverter; scopes batteries by device.
Classic-mode view builders and dashboard composition
custom_components/givenergy_local/www/ge-strategy.js (lines 158–371)
Implements reusable view constructors (Overview, Energy, Batteries, Battery Health, Controls, Diagnostics); detects optional cards (power-flow-card-plus, apexcharts-card); routes to EMS-specific views when applicable.
Cell-heatmap custom card and testing exports
custom_components/givenergy_local/www/ge-strategy.js (lines 929–1060)
Defines ge-cell-heatmap custom element with per-pack cell deviation table and area-prefixing fallback; registers strategy in HA's community dashboards; exports testing API (buildPlant, classicViews, generateDashboard).
Python integration wiring and frontend registration
custom_components/givenergy_local/__init__.py (lines 69–275), notification text (lines 667–673); custom_components/givenergy_local/www/ge-cell-heatmap.js (removed)
Updates constants to reference bundled ge-strategy.js and version; refactors _async_register_frontend_card to register and auto-load strategy module; extends dashboard-ready notification with strategy configuration guidance.
Synthetic Home Assistant test fixture
tests/js/mock-hass.js
Provides makeHass() factory synthesizing entity/device registries with configurable plant type, batteries, optional smart-load and AC-coupled entities, and area prefixing; includes entity key constants and withCards() helper for feature-detection stubbing.
JavaScript unit tests for dashboard strategy
tests/js/ge-strategy.test.js
Verifies dashboard structure, registry-resolution correctness, missing-entity robustness, strategy options (max_power_kw, serial pinning), feature detection (card fallbacks), EMS mode, and graceful "no plant" handling.
Python manifest parity and integration test updates
tests/test_strategy_manifest.py, tests/test_init.py (lines 15–16, 68–84)
Adds parity test validating JS key references against Python entity keys via regex scraping; updates integration test to assert bundled strategy module is registered and auto-loaded with version querystring.
User documentation and configuration guidance
README.md (lines 230–247)
Documents custom:givenergy strategy configuration (mode, max_power_kw, optional serial), card dependencies, known hard-refresh timeout, and classic-layout limitation.

Sequence Diagram

sequenceDiagram
  participant User as User
  participant HA as Home Assistant
  participant Strategy as ge-strategy.js<br/>(strategy)
  participant Registry as Entity/Device<br/>Registry
  participant Cards as Custom Cards<br/>(power-flow, apexcharts)
  User->>HA: Configure dashboard with strategy
  HA->>Strategy: generate(config, hass)
  Strategy->>Registry: query entity/device lists
  Registry-->>Strategy: entity registry + device info
  Strategy->>Strategy: classify devices, resolve entity_ids
  Strategy->>Strategy: select plant (by serial or first)
  Strategy->>Strategy: build view list with entity refs
  Strategy->>Cards: feature-detect (card registered?)
  Cards-->>Strategy: yes/no
  Strategy->>Strategy: degrade to markdown if missing
  Strategy-->>HA: dashboard object (views + cards)
  HA-->>User: render multi-tab dashboard
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • dewet22/givenergy-hass#79: Both PRs work with the ge-cell-heatmap custom card; this PR bundles it into the new ge-strategy.js module and updates _async_register_frontend_card accordingly, while PR #79 adds the bundled heatmap card to support the new "Battery Health" view.

Poem

🐰 A strategy springs forth, no YAML chains!
Registry whispers which entity remains.
Ten thousand heatmap cells align—
Each pack's heartbeat, in colors fine.
From unique_id to entity_id it flows,
A living dashboard that gracefully grows. 🔋✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.36% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding a live dashboard strategy (custom:givenergy) as described in issue #131, which is the primary feature in this PR.
Linked Issues check ✅ Passed The PR implements the v1 classic registry-driven strategy [#131] with entity resolution by unique_id and support for strategy options (mode, max_power_kw, serial). It includes comprehensive testing (JS tests with mock hass and Python parity checks) and documentation, meeting the primary v1 objectives.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the v1 classic strategy [#131]: the strategy module, tests, CI configuration, documentation, and bundled frontend assets. No unrelated changes detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/sad-mendeleev-93dfa6

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@dewet22-codex

Copy link
Copy Markdown
Collaborator

I’ve started reviewing this PR.

@socket-security

socket-security Bot commented Jun 5, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednpm/​vitest@​2.1.998257999100

View full report

@socket-security

socket-security Bot commented Jun 5, 2026

Copy link
Copy Markdown

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Warn Critical
Critical CVE: When Vitest UI server is listening, arbitrary file can be read and executed

CVE: GHSA-5xrq-8626-4rwp When Vitest UI server is listening, arbitrary file can be read and executed (CRITICAL)

Affected versions: < 4.1.0

Patched version: 4.1.0

From: package-lock.jsonnpm/vitest@2.1.9

ℹ Read more on: This package | This alert | What is a critical CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known critical CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/vitest@2.1.9. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

Comment thread custom_components/givenergy_local/www/ge-strategy.js Outdated
Comment thread custom_components/givenergy_local/www/ge-strategy.js Outdated
Comment thread custom_components/givenergy_local/www/ge-strategy.js Outdated

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a live, self-maintaining dashboard strategy (custom:givenergy) bundled with the existing cell-balance heatmap card into a single frontend module (ge-strategy.js). This registry-driven strategy resolves entities dynamically, preventing stale configurations when devices are renamed or moved. The PR also adds a comprehensive JS testing suite using Vitest, updates Python tests, and adds a parity guard to ensure strategy keys align with real entity descriptions. The review feedback focuses on improving robustness and performance: wrapping WebSocket registry calls in a try-catch block to handle non-admin users gracefully, defensively checking for hass.states to prevent TypeErrors during early bootstrap, and caching resolved entity IDs to avoid scanning all states on every update.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread custom_components/givenergy_local/www/ge-strategy.js Outdated
Comment thread custom_components/givenergy_local/www/ge-strategy.js Outdated
Comment thread custom_components/givenergy_local/www/ge-strategy.js

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (7)
README.md (2)

232-232: 💤 Low value

Use third-person voice for consistency.

The phrase "I added it because..." introduces a first-person voice that's inconsistent with the rest of the documentation (which uses neutral third-person). Consider rephrasing to maintain a consistent technical documentation tone.

📝 Suggested rephrase
-To avoid that snapshot problem entirely, there's also a dashboard *strategy* that builds the same six-tab layout but resolves every entity from the registry each time the dashboard loads — so it doesn't go stale when a device moves area or an entity is renamed. I added it because the static YAML kept silently rotting on my own install after area reassignments. To use it, create a new dashboard, open the **raw configuration editor**, and set the whole config to:
+To avoid that snapshot problem entirely, there's also a dashboard *strategy* that builds the same six-tab layout but resolves every entity from the registry each time the dashboard loads — so it doesn't go stale when a device moves area or an entity is renamed. To use it, create a new dashboard, open the **raw configuration editor**, and set the whole config to:
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` at line 232, The sentence "I added it because the static YAML kept
silently rotting on my own install after area reassignments." uses first-person
voice; change it to third-person/neutral technical tone by rephrasing to
something like "This was added because the static YAML can silently rot after
area reassignments, causing dashboards to become stale when devices move or
entities are renamed." Update the README line that describes the dashboard
strategy to use this neutral phrasing so the documentation remains consistent.

239-239: 💤 Low value

Consider using a clearer placeholder serial.

The example serial SA2114G047 follows the real GivEnergy format. While functional, using an obviously placeholder format (e.g., SA1234G567) would make it clearer to users that this is an example value to replace.

🔖 Alternative placeholder
-  serial: SA2114G047   # optional; pin one inverter on a multi-plant install
+  serial: SA1234G567   # optional; pin one inverter on a multi-plant install
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` at line 239, Replace the real-looking example serial value used in
the README by swapping the current serial value (the YAML key "serial" with
value "SA2114G047") for a clearly placeholder string such as "SA1234G567" so
readers understand it's an example to replace; update the "serial" example line
in the README to use the placeholder format.
custom_components/givenergy_local/www/ge-strategy.js (2)

79-85: ⚡ Quick win

Consider adding error handling for registry API failures.

If either WebSocket call fails (e.g., transient network issue, HA restarting), the unhandled rejection will propagate to HA. While HA's strategy runner catches errors, adding a try/catch here would allow returning a user-friendly diagnostic view rather than a generic failure.

🛡️ Suggested error handling
   async function buildPlant(hass, opts) {
-    var res = await Promise.all([
-      hass.callWS({ type: "config/entity_registry/list" }),
-      hass.callWS({ type: "config/device_registry/list" }),
-    ]);
-    var entities = res[0] || [];
-    var devices = res[1] || [];
+    var entities, devices;
+    try {
+      var res = await Promise.all([
+        hass.callWS({ type: "config/entity_registry/list" }),
+        hass.callWS({ type: "config/device_registry/list" }),
+      ]);
+      entities = res[0] || [];
+      devices = res[1] || [];
+    } catch (err) {
+      // Return empty plant; generateDashboard will show "no plant found" message
+      return { target: null, batteries: [] };
+    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@custom_components/givenergy_local/www/ge-strategy.js` around lines 79 - 85,
The buildPlant function currently awaits two hass.callWS calls without
protection; wrap the Promise.all(...) call in a try/catch inside buildPlant,
catch any errors from hass.callWS (e.g., network/HA restart), log the error (or
pass to a provided logger), and return a user-friendly diagnostic view or
placeholder result instead of letting the rejection propagate; ensure references
to hass.callWS({ type: "config/entity_registry/list" }) and hass.callWS({ type:
"config/device_registry/list" }) are preserved so callers get a clear fallback
when the registries cannot be loaded.

962-965: 💤 Low value

Heatmap card constructs entity_id strings directly (unlike strategy resolution).

The main strategy uses registry-based unique_identity_id resolution (lines 98-116), but the heatmap card constructs entity IDs directly using the pattern sensor.givenergy_battery_{serial}_cell_{n}_voltage. The fallback map (lines 957-961) provides partial area-prefix resilience, but this approach differs from the robust resolution used elsewhere.

This is likely intentional for the heatmap's simpler use case, but worth noting for future maintainers that this card won't benefit from the registry-driven resolution if entity naming conventions change beyond the current fallback handling.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@custom_components/givenergy_local/www/ge-strategy.js` around lines 962 - 965,
The heatmap helper cellState currently builds entity_id strings directly
(`sensor.givenergy_battery_${s.toLowerCase()}_cell_${n}_voltage`) which bypasses
the registry-based unique_id → entity_id resolution used elsewhere; change
cellState to resolve the entity id via the same registry lookup logic (re-use
the unique_id->entity_id resolution code used by the main strategy and fall back
to the existing fallback map) so it returns hass.states[resolvedId] ||
fallback[resolvedId] instead of relying on constructed ids. Ensure you reference
the same resolver function or mapping used in the main strategy and preserve
fallback behavior for area-prefix resilience.
.github/workflows/validate.yml (1)

59-59: ⚡ Quick win

Consider adding persist-credentials: false to the checkout step.

This prevents credentials from being persisted in the workspace's git config, reducing the risk of accidental credential exposure through artifacts or subsequent steps.

🔒 Proposed hardening
     steps:
       - uses: actions/checkout@v6
+        with:
+          persist-credentials: false
       - uses: actions/setup-node@v4
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/validate.yml at line 59, Update the GitHub Actions
checkout step that uses actions/checkout@v6 to set persist-credentials: false so
credentials are not written into the repository workspace; locate the checkout
step (the action invocation "uses: actions/checkout@v6") and add the
persist-credentials: false input to that step to prevent credentials from being
persisted to the git config.
tests/js/ge-strategy.test.js (1)

16-24: 💤 Low value

Minor duplication: withCards is also exported by mock-hass.js.

This local redefinition adds async/await support (line 20), whereas the mock-hass export is synchronous. Consider either:

  1. Using the mock-hass export directly (it works with async functions via promise chaining), or
  2. Updating the mock-hass export to support async and importing it here.

Not blocking, as the duplication is minimal and the async wrapper is clear.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/js/ge-strategy.test.js` around lines 16 - 24, The test defines a local
withCards function that duplicates the one exported by mock-hass.js; remove this
local definition and import the shared withCards from mock-hass instead (or
update the exported withCards in mock-hass to return a Promise/async so it
supports await in tests). Specifically, delete the local async function
withCards in ge-strategy.test.js and replace its usage by importing the shared
withCards export (or modify mock-hass's withCards implementation to be
async-compatible) so only one canonical implementation exists.
tests/js/mock-hass.js (1)

80-82: 💤 Low value

Optional: Document the serial lowercasing convention.

The entityId helper lowercases the serial number. While this is consistent throughout the mock, a brief inline comment would clarify this is intentional test fixture behavior (matching Home Assistant's entity_id slugification) rather than a production requirement.

📝 Suggested comment
 // entity_id marker: includes the (optional) area prefix so tests can assert the
-// returned config used the registry's *current* id, not a reconstructed one.
+// returned config used the registry's *current* id, not a reconstructed one.
+// Serial is lowercased to match HA's entity_id slugification.
 function entityId(prefix, serial, key) {
   return "sensor." + prefix + "ge_" + String(serial).toLowerCase() + "_" + key;
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/js/mock-hass.js` around lines 80 - 82, Add a short inline comment above
the entityId function explaining that the serial number is intentionally
lowercased to mirror Home Assistant's entity_id slugification for test fixtures;
reference the entityId helper and note this is a mock/test convention (not a
production requirement) so future readers understand why
String(serial).toLowerCase() is used.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@README.md`:
- Line 238: Update the README example line for the configuration field
max_power_kw to state its default and valid bounds: indicate that max_power_kw
defaults to 10 and accepts integers (or numeric values) in the range 1–100;
e.g., modify the comment after "max_power_kw: 10" to something like "# default
10; valid range 1–100 — Overview 24h chart y-axis envelope (kW)" so readers know
the accepted bounds when tuning this parameter.

---

Nitpick comments:
In @.github/workflows/validate.yml:
- Line 59: Update the GitHub Actions checkout step that uses actions/checkout@v6
to set persist-credentials: false so credentials are not written into the
repository workspace; locate the checkout step (the action invocation "uses:
actions/checkout@v6") and add the persist-credentials: false input to that step
to prevent credentials from being persisted to the git config.

In `@custom_components/givenergy_local/www/ge-strategy.js`:
- Around line 79-85: The buildPlant function currently awaits two hass.callWS
calls without protection; wrap the Promise.all(...) call in a try/catch inside
buildPlant, catch any errors from hass.callWS (e.g., network/HA restart), log
the error (or pass to a provided logger), and return a user-friendly diagnostic
view or placeholder result instead of letting the rejection propagate; ensure
references to hass.callWS({ type: "config/entity_registry/list" }) and
hass.callWS({ type: "config/device_registry/list" }) are preserved so callers
get a clear fallback when the registries cannot be loaded.
- Around line 962-965: The heatmap helper cellState currently builds entity_id
strings directly
(`sensor.givenergy_battery_${s.toLowerCase()}_cell_${n}_voltage`) which bypasses
the registry-based unique_id → entity_id resolution used elsewhere; change
cellState to resolve the entity id via the same registry lookup logic (re-use
the unique_id->entity_id resolution code used by the main strategy and fall back
to the existing fallback map) so it returns hass.states[resolvedId] ||
fallback[resolvedId] instead of relying on constructed ids. Ensure you reference
the same resolver function or mapping used in the main strategy and preserve
fallback behavior for area-prefix resilience.

In `@README.md`:
- Line 232: The sentence "I added it because the static YAML kept silently
rotting on my own install after area reassignments." uses first-person voice;
change it to third-person/neutral technical tone by rephrasing to something like
"This was added because the static YAML can silently rot after area
reassignments, causing dashboards to become stale when devices move or entities
are renamed." Update the README line that describes the dashboard strategy to
use this neutral phrasing so the documentation remains consistent.
- Line 239: Replace the real-looking example serial value used in the README by
swapping the current serial value (the YAML key "serial" with value
"SA2114G047") for a clearly placeholder string such as "SA1234G567" so readers
understand it's an example to replace; update the "serial" example line in the
README to use the placeholder format.

In `@tests/js/ge-strategy.test.js`:
- Around line 16-24: The test defines a local withCards function that duplicates
the one exported by mock-hass.js; remove this local definition and import the
shared withCards from mock-hass instead (or update the exported withCards in
mock-hass to return a Promise/async so it supports await in tests).
Specifically, delete the local async function withCards in ge-strategy.test.js
and replace its usage by importing the shared withCards export (or modify
mock-hass's withCards implementation to be async-compatible) so only one
canonical implementation exists.

In `@tests/js/mock-hass.js`:
- Around line 80-82: Add a short inline comment above the entityId function
explaining that the serial number is intentionally lowercased to mirror Home
Assistant's entity_id slugification for test fixtures; reference the entityId
helper and note this is a mock/test convention (not a production requirement) so
future readers understand why String(serial).toLowerCase() is used.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 266f995c-b304-4cf3-8004-05746217d1cb

📥 Commits

Reviewing files that changed from the base of the PR and between 54cf19b and 1008546.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (12)
  • .github/workflows/validate.yml
  • .gitignore
  • README.md
  • custom_components/givenergy_local/__init__.py
  • custom_components/givenergy_local/www/ge-cell-heatmap.js
  • custom_components/givenergy_local/www/ge-strategy.js
  • package.json
  • tests/js/ge-strategy.test.js
  • tests/js/mock-hass.js
  • tests/test_init.py
  • tests/test_strategy_manifest.py
  • vitest.config.js
💤 Files with no reviewable changes (1)
  • custom_components/givenergy_local/www/ge-cell-heatmap.js

Comment thread README.md Outdated
dewet22 and others added 2 commits June 6, 2026 00:36
Multi-plant correctness and defensiveness from PR #132 review:

- Battery attribution: only fall back to all batteries when the registry
  exposes no via_device links at all. When links exist, an empty match stays
  empty so an inverter-only plant no longer borrows another plant's packs.
- Serial pin: an unresolved explicit `serial:` no longer silently falls back
  to the first inverter (which would mis-target the Maintenance buttons); it
  shows the no-plant notice naming the missing serial. The first-inverter
  default applies only when no serial was supplied.
- Classification: classify devices against the full registered key set so
  disabling a single marker entity (p_pv, ems_plant_enable) can't hide a whole
  device; the renderable key->entity_id map still excludes disabled entities.
- Wrap the registry callWS in try/catch and surface a friendly notice rather
  than crashing the render on a transient connection drop.
- Heatmap card: guard hass.states before iterating, and cache resolved cell
  entity_ids per-instance instead of scanning all states on every render.

Adds JS regression tests for the multi-plant, unmatched-serial,
disabled-marker, and registry-failure paths.

Refs #132

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Refs #132

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dewet22-codex

Copy link
Copy Markdown
Collaborator

I’ve started re-reviewing this PR.

@dewet22-codex dewet22-codex left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved. I re-reviewed the current head and do not have any actionable concerns. The three earlier registry-resolution findings are addressed with targeted regression coverage, and the current GitHub checks are green.

@dewet22 dewet22 merged commit 0e1ee96 into main Jun 5, 2026
12 checks passed
@dewet22 dewet22 deleted the claude/sad-mendeleev-93dfa6 branch June 5, 2026 23:48
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.

Dashboard redesign — strategy + custom cards + mode-based UX

2 participants