Skip to content

Releases: SkiLtY/ha-ep-cube

v1.3.0

Choose a tag to compare

@github-actions github-actions released this 12 Jun 00:52

⚡ EP Cube Integration v1.3.0 — Dashboard Refresh + Signed Grid Net

TL;DR — single-session UX overhaul. (1) Dashboard restructured into three tabs (Now / Today / Control) — the single Overview mixed instant gauges with daily kWh rollups and control widgets in one viewport. (2) Now tab swaps the SC/SS instant percentage gauges (which pinned at 100% most of the day because a 20 kWh battery buffers the difference) for live power gauges in W: Solar, Battery, Grid. (3) Two new derived sensors (grid_net_today + grid_net_yesterday) give a single signed-kWh view, mirroring the Now-tab Grid gauge's centered-needle convention. (4) SC + SS today/yesterday now return 0.0 instead of unknown when their divisor is below the jitter floor — fixes the "Entity is non-numeric" overlay that hit gauges every morning before sunrise.

✨ What's new

Signed grid net — two new sensors

Sensor State class Source
sensor.ep_cube_grid_net_today TOTAL (signed kWh) gridelectricityfrom − gridelectricityto from today bucket
sensor.ep_cube_grid_net_yesterday TOTAL (signed kWh) Same against yesterday bucket

Positive = net importer for the period; negative = net exporter. The existing monotonic grid_import_* / grid_export_* sensors stay (Energy Dashboard wiring needs TOTAL_INCREASING) — the new pair is purely for at-a-glance dashboard gauges. Translations shipped for en / de / it / nl.

Dashboard refresh — three tabs

The single Overview view mixed timescales (instant gauges next to daily kWh totals next to control widgets), making it hard to read at a glance. Restructured into three tabs:

Now — what's happening right this second

  • Three live power gauges in W (Solar / Battery / Grid), refreshed on the 30s coordinator cadence with no dead-band wrapping — the jitter IS the live feedback
  • Power-flow card
  • Battery status

Today — daily rollups, mirroring HA's native Energy tab

  • Three gauges across the top (Grid net / Self-consumption / Self-sufficiency), refreshed every 5 min from the stats coordinator
  • Energy today + Energy yesterday entity lists
  • Matching three-gauge row above Energy yesterday so the rollup view is symmetric

Control — operating mode + mode-specific settings (unchanged behaviour, just moved into its own tab)

Unified colour palette

Replaced the per-gauge ad-hoc colouring with a consistent palette across all signed gauges:

  • Solar — Material Design Green (#43a047) — renewable generation
  • Battery — purple (#8353d1) when discharging (< 0, energy out), blue (#488fc2) when charging (> 0, energy in)
  • Grid — purple (#8353d1) when exporting (< 0, energy out), blue (#488fc2) when importing (> 0, energy in)
  • Percentage gauges (SC / SS today and yesterday) — Material green throughout, no severity bands

Purple/blue carries the same "energy going out" / "energy coming in" meaning on both Battery and Grid gauges, so a glance tells you which way energy flows regardless of which gauge you're reading. Matches HA's Energy Dashboard convention (purple = returned, blue = consumed). The previous 7-stop and 14-stop gradient experiments were dropped — interesting visually but added no signal users couldn't read from the numeric value.

🔧 Behaviour changes

  • SC + SS today/yesterday now return 0.0 instead of unknown when their divisor (solar / load in kWh) is below the jitter floor (~0.05 kWh). HA's gauge card surfaces unknown as an "Entity is non-numeric" error overlay, which made those gauges error-out every morning before sunrise. Genuine missing-data states (no stats fetched yet / bucket keys absent / malformed values) still return unknown — that signal is preserved for when something's actually wrong upstream.
  • Energy today entity list was pointing at the back-compat-preserved sensor.ep_cube_self_consumption, which reads 0 on cube firmware 02200242022220260515+ (the cube stopped exposing selfHelpRate on homeDeviceInfo in that build). Swapped to the new derived sensor.ep_cube_self_consumption_today and added a Self-sufficiency row.
  • Energy yesterday entity list gains the matching Self-consumption and Self-sufficiency rows it was missing.

🧪 Tests

Suite grows from 216 → 223 cases (+7). All in tests/test_derived_pct_sensors.py:

  • 7 new cases × _grid_net: net-importer, net-exporter, balanced, empty/missing/non-numeric handling, bucket-routing
  • 2 existing SC + SS jitter-floor tests updated to assert == 0.0 instead of is None

All green on Python 3.12 (validate.yml).

📦 Upgrading

  • HACS users: bump v1.2.0 → v1.3.0 in the HACS UI. Restart HA.
  • Manual users: re-copy custom_components/ep_cube/ from the release zip. Restart HA.
  • If you use the dashboard YAML (dashboards/ep_cube.yaml): the layout has shifted from a single Overview view to three tabs. Easiest path is to repaste the file via Raw configuration editor. If you customised the dashboard, the three new view blocks (- title: Now / - title: Today / - title: Control) are pasteable independently.

🛣 What's next

  • v1.4 — lifetime totals (Phase 4.2 Tier 3 — RestoreSensor + coordinator-startup state-seeding) + eco metrics (coal / treeNum from queryDataElectricityV2). Originally pencilled for v1.3 but today's UX work filled the slot; the roadmap items roll forward unchanged.
  • HACS Default mergehacs/default#8364 is in queue (834 PRs deep at submission; expected wait weeks-to-months). All bot checks green.
  • v1.xHomeAssistant-OctopusEnergy consumption swap, gated on Octopus Home Mini arrival (ETA 2026-06-17 → 2026-07-01).

☕ Support

If this saves you the hours, consider tossing a ko-fi in the tank. Thanks!


Not affiliated with or endorsed by Canadian Solar or EP Cube.

v1.2.0

Choose a tag to compare

@github-actions github-actions released this 10 Jun 21:09

🪜 EP Cube Integration v1.2.0 — Mislabel Fix + Cube-Native Rollups + Instant Tiles

TL;DR — three additive threads in one release. (1) The cube's selfHelpRate field has been mislabeled as "Self-consumption" since v0.5; it actually reports self-sufficiency. Display name corrected, entity_id preserved for back-compat. (2) Eight new cube-native monthly + yearly rollups replace the HA-side utility_meter helpers that previous releases shipped in the example package — more accurate, no drift on month/year roll. (3) Three new instant-KPI sensors + dashboard gauges answer "what's the house doing right now?" without users reading the power-flow card.

✨ What's new

15 new sensors, all additive — no new cloud calls, all derive from existing polls.

Self-consumption / sufficiency surface — corrected + expanded

Sensor Unit Source
sensor.ep_cube_self_sufficiency_pct % Cube's selfHelpRate (renamed from self_consumption_pct; unique_id preserved)
sensor.ep_cube_self_consumption_today % (solar_today − grid_export_today) / solar_today × 100
sensor.ep_cube_self_consumption_yesterday % Same against yesterday bucket
sensor.ep_cube_self_sufficiency_today % (load_today − grid_import_today) / load_today × 100
sensor.ep_cube_self_sufficiency_yesterday % Same against yesterday bucket

Verified 2026-06-10 against the live cube: on a 0.23 kWh import + 14.36 kWh load + 11.93 kWh export + 29.95 kWh solar day, the existing sensor read 99% (= 98.4% self-sufficiency, which it is) while true self-consumption was only ~60% (11.93/29.95 exported). The new pair surfaces both numbers honestly.

Cube-native monthly + yearly rollups

Sensor Unit Source
sensor.ep_cube_grid_import_month / _year kWh queryDataElectricityV2 scope=2 / scope=3
sensor.ep_cube_grid_export_month / _year kWh Same
sensor.ep_cube_solar_month / _year kWh Same
sensor.ep_cube_backup_loads_month / _year kWh Same

All state_class=TOTAL (not TOTAL_INCREASING) because they reset at the month/year boundary — HA's statistics engine handles the snap-back as a normal delta rather than spurious counter resets. More accurate than the HA-side utility_meter helpers that previous releases shipped in the example package: cube-native rollups don't drift if HA is down at month/year roll, because the cube itself owns the boundary snap-back.

Instant-KPI tiles

Sensor Unit Behaviour
sensor.ep_cube_self_consumption_right_now % (solar_w − export_w) / solar_w × 100, unknown below 50 W solar
sensor.ep_cube_self_sufficiency_right_now % (load_w − import_w) / load_w × 100, unknown below 50 W load
sensor.ep_cube_grid_flow_right_now W Signed; ±200 W dead-band rounded to 0 to stop the gauge twitching on routine in-house transients (kettle / microwave / fridge cycles)

Dashboard grows a "Right now" horizontal-stack of three type: gauge cards above the power-flow card, with severity bands matching what the cube is doing (self-consumption / sufficiency green > 70%, yellow 30-70%, red < 30%; grid flow green when exporting, yellow on modest import, red on sustained import > 3 kW).

💥 What changes for existing users

The self-consumption rename is the only user-visible change. Existing installs:

  • Display name changes from "Self-consumption" to "Self-sufficiency" automatically on update.
  • entity_id stays sensor.ep_cube_self_consumptionunique_id is preserved across the rename, so Energy Dashboard wiring, automations, templates, and history all keep working unchanged.
  • Fresh installs (post-v1.2) get sensor.ep_cube_self_sufficiency as the entity_id slug.

If you'd like to manually update the entity_id on an existing install: Settings → Devices & services → EP Cube → click the renamed sensor → settings (gear) → change the entity_id manually. Optional; the legacy slug stays sticky otherwise.

🔧 Behaviour changes

  • Dashboard refresh: dashboards/ep_cube.yaml adds the three gauge cards in a "Right now" horizontal-stack at the top of the Overview view.
  • Example package cleanup: examples/ha_config/packages/ep_cube.yaml drops the utility_meter rollups for solar / grid / backup / nonbackup (monthly + yearly). Use the new cube-native sensors directly. The battery charge/discharge utility_meter rollups stay — the cube doesn't expose signed battery flow on the stats endpoint, so the client-side delta-tracker + utility_meter chain is still the only path for monthly/yearly battery totals.
  • Translations: de / it / nl previously followed the English mislabel ("Eigenverbrauchsquote" / "Autoconsumo" / "Zelfverbruik"). Corrected to "Autarkiegrad" / "Autosufficienza" / "Zelfvoorziening". Plus 14 new entries per locale for the v1.2 additions.

🧪 Tests

Suite grows from 178 → 216 cases (+38). All in tests/test_derived_pct_sensors.py:

  • 19 cases × _self_consumption_pct + _self_sufficiency_pct (kWh-domain bucket value_fns): normal-case math, divisor below jitter threshold → None, clamp to [0,100], empty bucket / missing field / non-numeric handling, bucket-routing
  • 19 cases × _instant_self_consumption_pct + _instant_self_sufficiency_pct + _instant_grid_flow_w (W-domain): pass-through, sub-50-W noise floor, ±200 W dead-band edge handling

All green on Python 3.12 (validate.yml).

📦 Upgrading

  • HACS users: bump v1.1.3 → v1.2.0 in the HACS UI. Restart HA. The renamed sensor's display name updates immediately; entity_id stays put.
  • Manual users: re-copy custom_components/ep_cube/ from the release zip. Restart HA.
  • If you use the example package (examples/ha_config/packages/ep_cube.yaml): the file in this release drops 8 utility_meter entries (solar/grid/backup × month/year). If you have customisations layered on top, merge them onto the v1.2 base.
  • If you use the dashboard YAML (dashboards/ep_cube.yaml): the v1.2 file adds a "Right now" horizontal-stack of three gauges at the top. If you customised the dashboard, the gauges are pasteable as a single horizontal-stack block.

🛣 What's next

  • v1.3 — lifetime totals (Phase 4.2 Tier 3 — RestoreSensor + coordinator-startup state-seeding) + eco metrics (coal / treeNum from queryDataElectricityV2).
  • HACS Default mergehacs/default#8364 is in queue (834 PRs deep at submission; expected wait weeks-to-months). All bot checks green.
  • v1.xHomeAssistant-OctopusEnergy consumption swap, gated on Octopus Home Mini arrival (ETA 2026-06-17 → 2026-07-01).

☕ Support

If this saves you the hours, consider tossing a ko-fi in the tank. Thanks!


Not affiliated with or endorsed by Canadian Solar or EP Cube.

v1.1.3

Choose a tag to compare

@github-actions github-actions released this 09 Jun 22:29

🪜 EP Cube Integration v1.1.3 — Hassfest Compliance

TL;DR — clearing the way for HACS Default submission. validate.yml has been red since v1.0 because predbat_inverter_mode select shipped translation keys that don't match Home Assistant's [a-z0-9-_]+ rule. Dropping the offending state translation block — i18n on "Timed Export" → DE/IT/NL locale labels is lost (Eco stays "Eco" in every language regardless). No runtime behaviour change; this is a CI-pipeline fix.

🐛 What's fixed

Hassfest no longer fails on Invalid translation key 'Eco' at data['entity']['select']['predbat_inverter_mode']['state']. The select's wire-format values ("Eco" / "Timed Export") are dictated by Predbat — predbat/inverter.py:2212,2214 does case-sensitive string equality against "Eco" and "Timed Export", so we can't lowercase the state values without breaking the Predbat bridge. The only fix that satisfies both constraints is dropping the state translation block entirely. HA falls back to displaying the raw state values, which is fine since "Eco" is "Eco" in every locale anyway and "Timed Export" is a Predbat-specific technical term.

Lost: localized labels for "Timed Export" (Zeitgesteuerter Export / Esportazione temporizzata / Geplande export). If you'd like them back, the fix path is HA-side — open an issue against home-assistant/core to allow uppercase translation keys for entity state values, or against predbat/predbat to make Predbat's state matcher case-insensitive.

📦 Upgrading

  • HACS users: bump v1.1.2 → v1.1.3. Restart HA. If you're in de / it / nl and your select.ep_cube_predbat_inverter_mode dropdown showed translated labels for "Timed Export", they'll revert to the raw English string.
  • Manual users: re-copy custom_components/ep_cube/. Restart HA.

🛣 What's next

HACS Default submission immediately after this release lands — validate.yml goes green, the smoke test from v1.1.2 cleared the install path, and we have a real-cube-verified production deployment for ~3 weeks. Submission is the only remaining gate.

☕ Support

If this saves you the hours, consider tossing a ko-fi in the tank. Thanks!


Not affiliated with or endorsed by Canadian Solar or EP Cube.

v1.1.2

Choose a tag to compare

@github-actions github-actions released this 09 Jun 22:17

🪜 EP Cube Integration v1.1.2 — Dashboard Fix + Backup-Loads Clarification

TL;DR — small patch on top of v1.1.1, surfaced by the HACS pre-submission smoke test. One broken entity row in the bundled dashboard YAML, one README clarification about what backup_today actually measures. No code change, no behaviour change. Upgrade if you use the bundled dashboards/ep_cube.yaml or have ever wondered what "Backup loads today" means on your install.

🐛 What's fixed

dashboards/ep_cube.yaml — "Energy today" card showed "Entity not found" on the Self-consumption row. Referenced sensor.ep_cube_self_consumption_pct (matching the integration's translation_key) but HA derives entity-IDs from the entity's display name, not the translation key — so the actual ID is sensor.ep_cube_self_consumption. README already documents this slug-derivation gotcha for users editing dashboards; the bundled YAML was the one place that didn't follow its own advice.

Bug was present from v1.1.0 (when the Energy today card was first added). Silent on existing installs unless you scrolled past the row.

📝 What's documented

README — backup-loads semantics callout. New > [!NOTE] admonition under the Sensors table explaining that backup_today / backup_yesterday count kWh delivered through the cube's backup-output terminal, not "loads that stayed up during an outage". Whether this reads as whole-house or essential-circuits-only depends entirely on what your installer wired through the backup panel. Adds context that outage-resilience under UK G99/G100 regs needs an external EPS Gateway — the cube physically refuses to supply via the backup terminal during a grid outage without one, even though it continues to meter kWh through it under normal operation.

🧪 HACS pre-submission smoke test

This release was triggered by the HACS Custom Repository install-path verification on a throwaway HA instance. Findings:

  • ✅ HACS install via official one-liner: clean
  • ✅ Custom Repository → Integration download: clean
  • ✅ Config flow against live cube (multi-region + captcha + bearer): clean
  • ✅ All 33 entities (26 sensors + 5 controls + 2 Predbat stubs) populated with sane live data
  • ✅ Logs clean, Repairs clean (Predbat-priority detector correctly silent without a Predbat container)
  • ✅ Brand icon rendering on device detail page (HA core's /api/brands/integration/ep_cube/icon.png serving from custom_components/ep_cube/brand/)
  • ⚠️ HACS store list shows "icon not available" — HACS fetches store icons direct from brands.home-assistant.io CDN, bypassing HA's brands endpoint. Not fixable from the integration side; resolves itself once HACS Default is accepted and we re-submit to home-assistant/brands (post-submission).
  • 🐛 Dashboard YAML self-consumption row → fixed above

📦 Upgrading

  • HACS users: bump v1.1.1 → v1.1.2. If you've pasted the dashboard YAML, re-open it via Raw Configuration Editor and re-paste from dashboards/ep_cube.yaml (or hand-edit the one line). Otherwise nothing to do.
  • Manual users: re-copy custom_components/ep_cube/ from the release zip if you want the version bump in HA's UI. No functional difference vs v1.1.1 in the integration code itself.

🛣 What's next

  • HACS Default submission — smoke test passed (this release is the "fix the hiccups" pass), submitting next.
  • v1.2 — cube-native monthly + annual rollups (Phase 4.2 Tier 3) + dashboard KPI tile refresh.
  • v1.3 — lifetime totals (Phase 4.2 Tier 4) + eco metrics (Tier 5).

☕ Support

If this saves you the hours, consider tossing a ko-fi in the tank. Thanks!


Not affiliated with or endorsed by Canadian Solar or EP Cube.

v1.1.1

Choose a tag to compare

@github-actions github-actions released this 05 Jun 11:48

🪜 EP Cube Integration v1.1.1 — Stale-Entity Cleanup

TL;DR — small patch on top of v1.1.0. The two sensors deleted in v1.1.0 (grid_today + nonbackup_today) were leaving behind unavailable ghost rows in the HA entity registry until the user manually deleted them. This release sweeps those rows on every setup. Upgrade and the ghosts disappear after the next HA restart. No behavioural change otherwise.

🧹 What's fixed

After upgrading to v1.1.0, users would see two leftover entities in HA's UI:

  • sensor.ep_cube_grid_today (or whatever name your HA had localised it to)
  • sensor.ep_cube_non_backup_loads_today

Both stuck on unavailable because the integration no longer registers them. v1.1.1 adds a one-time sweep on every config-entry setup that removes any registry row whose unique_id matches the deleted set:

  • <entry_id>_grid_today (deleted v1.1.0 — direction-ambiguous)
  • <entry_id>_nonbackup_today (deleted v1.1.0 — zero on EU firmware)

Scoped to the config entry only, so a multi-entry / multi-cube setup where one entry was upgraded ahead of others doesn't yank entries from siblings. Idempotent — running against an already-clean registry is a no-op.

🧪 Tests

Suite grows 176 → 178 cases. 2 new in tests/test_setup.py::TestStaleEntityPurge:

  • test_pre_existing_grid_today_entry_purged_on_setup — seeds the registry with both ghost rows, runs setup, asserts both are gone afterwards
  • test_purge_is_idempotent_when_registry_clean — fresh install with no ghosts; setup still succeeds, no-op purge

All 178 green on Python 3.12.

📦 Upgrading

  • HACS users: bump v1.1.0 → v1.1.1. Restart HA — that's when the sweep runs. Refresh the Devices & services page and the ghost rows are gone.
  • Manual users: re-copy custom_components/ep_cube/ from the release zip. Restart HA.

🛣 What's next

Roadmap unchanged from v1.1.0:

  • v1.2 — cube-native monthly + annual rollups (Phase 4.2 Tier 3)
  • v1.3 — lifetime totals (Phase 4.2 Tier 4) + eco metrics (Tier 5)
  • HACS Default submission — held until v1.1 has bedded in

☕ Support

If this saves you the hours, consider tossing a ko-fi in the tank. Thanks!


Not affiliated with or endorsed by Canadian Solar or EP Cube.

v1.1.0

Choose a tag to compare

@github-actions github-actions released this 05 Jun 09:57

🪜 EP Cube Integration v1.1.0 — Stats Endpoint + Clean Grid Import/Export Split

TL;DR — 6 new sensors backed by the cube's own electricity-rollup endpoint (queryDataElectricityV2). Grid energy today is now correctly split into import + export rather than the single direction-ambiguous counter v1.0 inherited from v0.5.0. Yesterday's energy quartet is genuinely new surface for daily-summary automations.

✨ What's new

Six new sensors fed by a second background coordinator polling the cube's stats endpoint every 5 min for today + at slower cadences for the wider rollups. ≈320 cloud calls/day total, ~5× the existing homeDeviceInfo budget.

Sensor Unit State class Source
sensor.ep_cube_grid_import_today kWh TOTAL_INCREASING gridElectricityFrom (scope=1 today)
sensor.ep_cube_grid_export_today kWh TOTAL_INCREASING gridElectricityTo (scope=1 today)
sensor.ep_cube_grid_import_yesterday kWh TOTAL gridElectricityFrom (scope=1 yesterday)
sensor.ep_cube_grid_export_yesterday kWh TOTAL gridElectricityTo (scope=1 yesterday)
sensor.ep_cube_solar_yesterday kWh TOTAL solarElectricity (scope=1 yesterday)
sensor.ep_cube_backup_loads_yesterday kWh TOTAL backUpElectricity (scope=1 yesterday)

Today's pair (grid_import_today / grid_export_today) is the direct fix for the v0.5.0 limitation that v1.0 inherited: the cube's homeDeviceInfo field gridElectricity is direction-ambiguous — equals export on export-heavy days, import on import-heavy days. The new pair reads from the stats endpoint which exposes both directions cleanly, so HA's Energy Dashboard wires up correctly without Riemann tricks.

The yesterday quartet is genuinely new — no previous integration version surfaced it. Useful for "did I export much yesterday?" automations and for Energy Dashboard back-fill semantics.

💥 Breaking changes

  • Removed sensor.ep_cube_grid_today — the direction-ambiguous counter. Replaced by grid_import_today + grid_export_today. If you reference grid_today in automations / templates / dashboards, update them to the new pair.
  • Removed sensor.ep_cube_nonbackup_today — reported 0 across every window on EU firmware. Misleading. If you have a non-backed-loads-aware setup outside the EU, please open an issue — happy to restore as a region-gated sensor.

🔧 Behaviour changes

  • Dashboard refresh: dashboards/ep_cube.yaml now has Energy today + Energy yesterday entities cards between the Battery card and the Operating-mode picker. Drop-in users get the new sensors surfaced without further wiring.
  • Stats coordinator runs alongside the existing 60 s homeDeviceInfo coordinator. Today's bucket polls every 5 min; month every 1 h; year every 6 h; lifetime totals every 12 h; yesterday re-fetches only on HA-local date roll + once at startup. Best-effort: if a wider bucket fetch fails the previous cached value stays put and the integration doesn't flag.

🧪 Tests

Suite grows from 160 → 176 cases. 8 new in tests/test_api_client.py::TestGetStats covering the helper (URL composition per scope, lowercase normalisation, 403 reauth retry path, US /app-api prefix). 8 new in tests/test_stats_coordinator.py covering the cadence logic (per-bucket refresh thresholds, day-roll yesterday refetch, today-failure-raises-vs-non-today-best-effort error handling). All green on Python 3.12.

📦 Upgrading

  • HACS users: bump v1.0.0 → v1.1.0 in the HACS UI. Restart HA. Update any automation / template / dashboard reference to sensor.ep_cube_grid_today to use the new import/export pair.
  • Manual users: re-copy custom_components/ep_cube/ from the release zip. Restart HA.

🛣 What's next

  • v1.2 — cube-native monthly + annual rollups (Phase 4.2 Tier 3). Will replace the utility_meter helpers in examples/ha_config/packages/.
  • v1.3 — lifetime totals (Phase 4.2 Tier 4) + eco metrics (Phase 4.2 Tier 5).
  • HACS Default submission — held until v1.1 has bedded in.
  • v1.xHomeAssistant-OctopusEnergy — half-hourly smart-meter consumption replaces Riemann load_today. Gated on Octopus Home Mini arrival.

☕ Support

If this saves you some hours, consider tossing a ko-fi in the tank. Thanks!


Not affiliated with or endorsed by Canadian Solar or EP Cube.

v1.0.0

Choose a tag to compare

@github-actions github-actions released this 04 Jun 22:03

🪜 EP Cube Integration v1.0.0 — Opinionated Predbat Bridge (Breaking Change)

TL;DR — the TOU editor card and ep_cube.set_tou_schedule service are gone. From v1.0 the integration treats Predbat as the single source of truth for time-of-use control. If your cube has user-painted TOU slots while Predbat is running, an HA Repair issue offers a one-click wipe. If you want manual TOU control without Predbat, use the EP Cube mobile app or Bobsilvio/epcube.

Why this is breaking

The TOU editor existed as a relief valve for "Predbat isn't doing what I want right now." But overriding at the cube creates state divergence: Predbat re-plans against its model of the cube while the cube is actually running a hand-painted schedule the model doesn't know about. The right fix for "Predbat isn't doing what I want" is to tune Predbat (metric10_weight, metric_battery_value_scaling, etc.) — not to override at the device.

The honest product framing for v1.0:

  • Predbat + variable tariff users (the integration's primary audience): everything they need is in the shim's charge_start / discharge_start / charge_freeze / idle services. They never needed set_tou_schedule and shouldn't be tempted by it.
  • Fixed-tariff non-Predbat users (the audience the editor was secretly built for): better served by Bobsilvio's bobsilvio/epcube HACS integration, or just the EP Cube mobile app. Neither has an "is Predbat tuned right?" problem to fight.

💥 Breaking changes

  • Removed ep_cube.set_tou_schedule service. Any automation calling it will fail. Migrate to one of:
    • EP Cube mobile app for ad-hoc manual TOU painting.
    • Bobsilvio's epcube integration if you want manual TOU as a permanent HA-native control surface (deliberately different design from this one).
  • Removed www/ep-cube-tou-editor.js (the Lovelace editor card). If you have it installed:
    • Settings → Dashboards → Resources → delete the /local/ep-cube-tou-editor.js entry.
    • The dashboards/ep_cube.yaml no longer references it. If you customised the dashboard, the type: custom:ep-cube-tou-editor card block can be removed.
  • Removed tou_schedule and tou_prices extra-state-attributes from select.ep_cube_operating_mode. If you read these from automations, switch to the EP Cube app or a different integration for the underlying data.
  • parse_tou_schedule() and parse_tou_prices() helpers removed from services.py. They were public-but-internal — listed here for anyone who imported them in a custom module.

✨ New: HA Repair flow for the Predbat-priority transition

When the coordinator detects:

  1. The cube has at least one non-shim slot in any of the six non-DST tier lists (workday + weekend × peak / mid-peak / off-peak), AND
  2. At least one entity in the predbat.* domain exists on this HA instance,

…an HA Repair issue appears (Settings → System → Repairs) titled "Manual TOU slots on the cube while Predbat is running." Selecting Submit wipes the six non-DST tier lists on the cube in a single guided flow:

  • Abandons any in-flight Predbat shim override first (user-wins).
  • Reads current state, strips stale shim-signature slots, builds an overrides dict that empties the six tier lists.
  • Uses the 2-write dance when the cube is in non-TOU mode (write A flips to TOU and lands the empty lists; write B flips back to the original mode). Same provenance and quirks as the shim's existing dance — see services.py PredbatShim.
  • Triggers a coordinator refresh — the detection helper auto-clears the issue once it sees the wiped snapshot.

DST tier lists are deliberately left intact. They're shared-across-year state; the conflict surface lives entirely in the six non-DST lists.

The repair flow is idempotent and non-destructive without confirmation — the issue surfaces, the user reads, the user clicks. No auto-wipe.

🧹 What was cleaned up

  • custom_components/ep_cube/services.py lost ~400 lines: handle_set_tou_schedule + SET_TOU_SCHEDULE_SCHEMA + _PRICES_SCHEMA + _USER_SLOT_RE + _parse_user_slot + _validate_day_profile + _user_slot_to_wire + _slot_wire_to_user + _existing_house_price + _DEFAULT_PRICE_BY_USER_FIELD + parse_tou_schedule + parse_tou_prices.
  • tests/test_set_tou_schedule.py removed (~900 lines, 30+ cases). The 2-write dance is still under test coverage via tests/test_shim.py (the shim uses the same pattern for charge / discharge / freeze).
  • const.DEFAULT_TIER_PRICE_* removed (only set_tou_schedule referenced them).
  • services.yaml lost the set_tou_schedule entry; the shim services remain.

📦 What's kept

  • Predbat shim: charge_start, charge_stop, discharge_start, discharge_stop, charge_freeze, discharge_freeze, idle — unchanged.
  • debug_freeze diagnostic service — unchanged.
  • All 22 sensors, 1 select (operating mode), 2 numbers (reserve SoCs), 2 switches (grid-charge allow + DST) — unchanged.
  • select.ep_cube_predbat_inverter_mode + number.ep_cube_predbat_charge_limit (Predbat-entity-first stubs from v0.7 line) — unchanged.
  • parse_tou_schedule callers in dashboards / cards — none in the public repo; if you forked the editor card it'll stop working without the helpers.

🧪 Tests

Suite shrinks from 229 → ~200 with the deletion. The repair flow itself gets light coverage in this release; the cube-write path is exercised by the existing shim tests. Suite is green on Python 3.12.

📦 Upgrading

  • HACS users: bump v0.7.0 → v1.0.0 in the HACS UI. Restart HA. After restart, if the cube has manual TOU slots and you run Predbat, an HA Repair will appear — click through to wipe them.
  • Manual users: re-copy custom_components/ep_cube/ from the release zip. If you'd installed www/ep-cube-tou-editor.js, remove it from /config/www/ and remove the Lovelace resource entry. Restart HA.
  • Automation cleanup: search your automations.yaml and node-red flows for ep_cube.set_tou_schedule — these calls now fail. Decide per-call: drop entirely (let Predbat handle it), move to the EP Cube app, or migrate to Bobsilvio's integration.

🛣 What's next

  • v1.0.xqueryDataElectricityV2 cloud-stats expansion (signed grid import/export, *_yesterday variants, lifetime totals with RestoreSensor seeding) — waiting on a mitmproxy capture session.
  • v1.1 — HACS Default submission.
  • v1.xHomeAssistant-OctopusEnergy — half-hourly smart-meter consumption replaces Riemann load_today. Gated on Octopus Home Mini arrival.

Why v1.0 not v0.8

This is the first release whose scope matches the original product statement: "let Predbat control the EP Cube." Earlier versions stopped short of being opinionated about it and shipped escape hatches that, in practice, made the Predbat path harder to reason about. v1.0 deletes the escape hatches and replaces them with a one-click handoff.

☕ Support

If this saves you the mitmproxy sessions and Python hours it took to build, consider tossing a ko-fi in the tank. Thanks!


Not affiliated with or endorsed by Canadian Solar or EP Cube.

v0.7.0

Choose a tag to compare

@github-actions github-actions released this 02 Jun 18:00

💷 EP Cube Integration v0.7.0 — Per-Tier Rate Entry on TOU Card

Phase 4.1++ closes the TOU editor's last functional gap: per-tier prices are now editable from the card, not just preserved server-side. The cube's internal tier prices are cosmetic for Predbat users (Predbat optimises against your real Octopus tariff), but for fixed-tariff and non-Predbat users they're load-bearing — and previously the only way to set them was via the EP Cube mobile app.

✨ What's new

  • Per-tier rate inputs in the editor card — three p/kWh inputs per tab (Peak / Mid-peak / Off-peak × Workday / Weekend), inline with each tier's "Add slot" button. Hydrates on first load from a new tou_prices extra-state-attribute on select.ep_cube_operating_mode. Type a value to override; leave blank to keep the cube's existing per-tier price. Placeholder shows the cube's factory default for empty tiers (40 / 25 / 5 p/kWh for peak / mid-peak / off-peak).

  • Optional prices arg on ep_cube.set_tou_schedule — pass a dict with up to 6 keys (peak_workday, mid_peak_workday, off_peak_workday, peak_weekend, mid_peak_weekend, off_peak_weekend) to override per-tier prices in p/kWh. Range 0-999. Tiers omitted from the dict fall through to preserve-from-cube semantics (existing behaviour). Backwards-compatible — pre-v0.7 callers without prices see no behaviour change.

  • parse_tou_prices() helper + tou_prices attribute — sibling to parse_tou_schedule / tou_schedule. Returns the price of the first non-shim slot in each tier, or None if the tier is empty (so the card can show a placeholder instead of a misleading "real" value). Automations can read it directly from the select entity's attributes.

🐛 Fixed

  • Card hydration race — the card's first-load guard used to flip true as soon as the schedule attribute appeared, even if tou_prices wasn't there yet. Result: rate inputs stayed blank forever until the user clicked "Reload from cube" manually. v0.7.0 only sets the guard once prices have successfully landed, so schedule-only ticks keep retrying.

🧹 Cleanup

  • Dropped the v0.6.3 legacy synthetic-price tokens (0.01 / 0.20 / 1.00) from the strip set — the one-release migration window has expired. Any pre-v0.6.3 in-flight Predbat overrides have long since rotated out. Slots with these prices on your cube would now look like genuine user slots, which was the whole reason for the v0.6.3 migration in the first place (they collided with realistic fixed-tariff prices and were silently dropping user data from the editor card's hydrated view).

📋 Service contract (new field highlighted)

service: ep_cube.set_tou_schedule
data:
  peak_workday:     ["16:00-19:00"]
  mid_peak_workday: ["04:30-16:00", "19:00-23:59"]
  off_peak_workday: ["00:30-04:30"]
  peak_weekend:     []
  mid_peak_weekend: []
  off_peak_weekend: []
  switch_to_tou:    false           # optional
  prices:                           # ✨ NEW in v0.7.0, optional
    off_peak_workday: 8.5           # p/kWh
    peak_workday:     28.5
  device_id:        "5613"          # optional

Each prices key independently routes through: (1) explicit value → (2) cube's existing price → (3) factory default. Pass none of them and behaviour matches pre-v0.7. Pass some of them and only those tiers get overridden.

📏 Precision note

The cube's wire format is 2dp on the £-scale = 1p resolution per tier. Sub-p input (e.g. 19.25 p/kWh from an Octopus Agile rate) rounds to 19 on save. Documented in the service description, the card hint text, and services.py. For Predbat users this is irrelevant (Predbat optimises against the real Octopus rate, not the cube's internal prices). For fixed-tariff users UK tariffs are usually quoted to whole pence anyway.

🧪 Tests

Suite is now 229 tests (was 200 in v0.6.4):

  • 23 new cases in tests/test_set_tou_schedule.py covering the prices arg (full override, partial preservation, empty-cube-tier with explicit price, schema validation, sub-penny rounding, string coercion, 2-write dance interaction, zero-price accepted) and the new parse_tou_prices helper + _first_non_shim_price shared scanner.
  • 3 hard-coded legacy synthetic prices in tests/test_shim.py replaced with SHIM_PRICE_* constants.
  • 1 new case verifying legacy prices (0.01 / 0.20 / 1.00) now flow through as user slots instead of being stripped.

All green on Python 3.12 in CI + local Synology container.

📦 Upgrading

  • HACS users: bump from v0.6.4 → v0.7.0 in the HACS UI.
  • Manual users: re-copy custom_components/ep_cube/ + www/ep-cube-tou-editor.js from the release zip; bump the card's resource version (Settings → Dashboards → Resources → change /local/ep-cube-tou-editor.js?v=0.6.4 to ?v=0.7.0) so browsers re-fetch.
  • HA restart required — Python-side service + entity changes.

🛣 What's next

  • v0.7.x — placeholder defaults driven by predbat.metric_low_rate_threshold / high_rate_threshold (or the current Octopus rate via the BottlecapDave integration) instead of static constants. Chipped during v0.7.0 testing.
  • v0.7.xqueryDataElectricityV2 cloud-stats expansion (signed grid import/export, *_yesterday variants, lifetime totals with RestoreSensor seeding) — waiting on a mitmproxy capture session.
  • v0.8 — auto-paint TOU schedule from Predbat's rate thresholds + Agile forecast (one-click "match Predbat's bucketing").

☕ Support

If this saves you the mitmproxy sessions and Python hours it took to build, consider tossing a ko-fi in the tank. Thanks!


Not affiliated with or endorsed by Canadian Solar or EP Cube.

v0.6.4

Choose a tag to compare

@github-actions github-actions released this 29 May 14:59

🛠 EP Cube Integration v0.6.4 — TOU Schedule Edits Always Land

Fixes a real silent-drop bug surfaced during 2026-05-29 live-cube testing: editing the TOU schedule while the cube was in self-consumption or backup mode would claim "Schedule saved" but actually do nothing. The cube's documented TOU → non-TOU transition quirk extends to any schedule write made while the cube isn't already in TOU mode — the HTTP call returns 200 but the cube silently ignores the tier-list portion of the payload.

✨ What's new

  • 2-write dance in ep_cube.set_tou_schedule — when the cube is in non-TOU mode and the user doesn't tick "Switch to TOU when saving", the service now performs two writes:

    1. Write A: flip to TOU mode + apply new tier lists (cube honours both because TOU → TOU never drops the write)
    2. Write B: flip back to the user's original mode (cube switches mode, drops the tier-list write — but the tier lists from A are already on the cube)

    Net result: schedule edits always land on the cube regardless of current mode, with no user-visible mode change for the operator. Single-write behaviour preserved when the cube is already in TOU mode or when the user explicitly wants to end up in TOU.

  • "Clear all" button on the editor card — one-click wipe of every slot on both workday + weekend profiles. Confirmation modal before save. Useful for starting fresh, removing leftover shim slots from prior Predbat overrides, or preparing for an auto-paint pass (Phase 4.3 — coming v0.8). Calls the same set_tou_schedule service with empty tier lists, just bypasses the manual remove-one-at-a-time loop.

🐛 Fixed

  • Silent-drop on save while in non-TOU mode — edits to the TOU schedule no longer require the cube to be in TOU mode at save time. Previously you had to either (a) tick "Switch to TOU when saving" first, or (b) manually switch to TOU via the operating-mode dropdown, edit, then switch back. Now any save just works.
  • Leftover shim slots from prior Predbat / debug_freeze overrides auto-clean on next save — because every set_tou_schedule now writes via TOU mode briefly, leftover shim-signature slots in the cube's TOU memory get stripped from live_clean before write A goes out. So one save (even an empty one via the new "Clear all" button) clears any accumulated cruft.

🧪 Tests

Four new pytest cases in tests/test_set_tou_schedule.py::TestServiceDispatch covering the 2-write decision matrix:

  • 2-write when cube is non-TOU + no switch_to_tou flag
  • Single write when switch_to_tou=True (user wants TOU end-state)
  • Single write when cube is already in TOU mode
  • The user's specific scenario: clearing slots from self-consumption mode lands correctly

Existing tests updated where the await-count assertion changed from 1 to 2. Suite now 183 tests, all green.

📦 Upgrading

  • HACS users: bump from v0.6.3 → v0.6.4 in the HACS UI.
  • Manual users: re-copy custom_components/ep_cube/ + www/ep-cube-tou-editor.js from the release zip; browser hard-refresh for the card.
  • HA restart required — Python-side service changes.

📋 Behaviour change to note

Saves now cost 2 cloud writes (was 1) when the cube isn't already in TOU mode. Writes are cheap and infrequent (users edit schedules occasionally, not minutely), so this is well within the cube's tolerance — but worth flagging for anyone monitoring write rates.

If the cube rejects write B (rare), the cube is left in TOU mode rather than the user's original mode. The service raises HomeAssistantError with a message explaining this, so it's visible in the UI rather than silent.

🛣 What's next

  • v0.7 — per-tier rate entry on the editor card (chipped); drop legacy shim-price tokens from migration window.
  • v0.7queryDataElectricityV2 cloud-stats expansion.
  • v0.8 — auto-paint TOU schedule from Predbat's low-rate threshold + Agile forecast.

☕ Support

If this saves you the mitmproxy sessions and Python hours it took to build, consider tossing a ko-fi in the tank. Thanks!


Not affiliated with or endorsed by Canadian Solar or EP Cube.

v0.6.3

Choose a tag to compare

@github-actions github-actions released this 29 May 13:33

🎯 EP Cube Integration v0.6.3 — Shim Price Refactor

Small but important fix that closes a real footgun: the synthetic prices the Predbat shim used to tag its temporary override slots (0.01 / 0.20 / 1.00) collided with realistic UK tariff prices. A user on a fixed-rate tariff with 1.00 p/kWh peak slots would have those slots silently stripped from the TOU editor card's hydrated view (introduced in v0.6.2). Surfaced during a live debug_freeze test on 2026-05-29.

✨ What's new

  • Shim synthetic prices migrated to 2.22 / 3.33 / 4.44 — all above Agile's 100p/kWh daily cap, so no realistic UK retail tariff hits them. The repeating-digit pattern also makes shim slots visually identifiable if a user ever spots one in the EP Cube mobile app's schedule view.
  • One-release migration window_SHIM_PRICE_TOKENS keeps the legacy values (0.01 / 0.20 / 1.00) in its match set so any leftover shim slots from a pre-v0.6.3 Predbat run still get stripped cleanly on next read. Legacy entries will be dropped in v0.7 once any in-flight overrides have rotated out of cube memory.
  • One new pytest case verifying both new + legacy synthetic prices are stripped (suite now 179 tests).

🐛 Fixed

  • Editor card hiding genuine user slots at 1.00 p/kWh — fixed-tariff users with realistic peak prices at the £1 cap would see those slots vanish from the hydrated card view. Migration window catches both old and new synthetic prices, so any leftover shim slots from prior Predbat runs are still cleaned up.

📦 Upgrading

  • HACS users: bump from v0.6.2 → v0.6.3 in the HACS UI.
  • Manual users: re-copy custom_components/ep_cube/ from the release zip.
  • HA restart required — Python-side constants change.
  • No card changewww/ep-cube-tou-editor.js unchanged in this release.

📋 User-facing constraint update

Previously: "don't manually configure slots at 0.01 / 0.20 / 1.00."

Now: "don't manually configure slots with prices in the synthetic set." The synthetic set is currently {0.01, 0.20, 1.00, 2.22, 3.33, 4.44} during the v0.6.3 migration window; will narrow to {2.22, 3.33, 4.44} in v0.7.

In practice this matters only for fixed-tariff users (Predbat / Agile users won't manually set these prices since the cube's TOU prices are internal tier-priority labels for their setup).

🛣 What's next

  • v0.7 — per-tier rate entry on the editor card (chipped); drop legacy shim-price tokens from migration window.
  • v0.7queryDataElectricityV2 cloud-stats expansion.
  • v0.8 — auto-paint TOU schedule from Predbat's low-rate threshold + Agile forecast.

☕ Support

If this saves you the mitmproxy sessions and Python hours it took to build, consider tossing a ko-fi in the tank. Thanks!


Not affiliated with or endorsed by Canadian Solar or EP Cube.