Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
111 commits
Select commit Hold shift + click to select a range
de0ab81
feat(#1321): SEM Next — a second dashboard, five screens by question
traktore-org Nov 5, 2026
68ad938
docs(#1321): SEM Next in the guides, 16 languages, changelog
traktore-org Nov 5, 2026
3797a77
fix(#1321): SVG parts use lit's svg tag; a source is off only when un…
traktore-org Nov 5, 2026
c4ee729
fix(#1321): the timeline shows a load lane only when something is pla…
traktore-org Nov 5, 2026
fce7b6b
fix(#1321): the timeline keeps its width on a phone and scrolls sideways
traktore-org Nov 5, 2026
5c41538
Merge develop into feature/1321-dashboard-next (#1321)
traktore-org Nov 7, 2026
c9c1418
feat(#1321): SEM Next base for the redesign — header chips, All-setti…
traktore-org Nov 7, 2026
70e6b18
feat(#1321): Now screen — one power bar with In/Out list, today tiles…
traktore-org Nov 7, 2026
71820d7
feat(#1321): Plan screen — price strip with the plan on it, per-devic…
traktore-org Nov 7, 2026
d3eaf36
feat(#1321): Insights screen — one period for every chart; energy, po…
traktore-org Nov 7, 2026
0f7dea7
feat(#1321): Devices screen — one card per device, rank badge, reorde…
traktore-org Nov 7, 2026
727197e
feat(#1321): System screen — health first, what SEM held back, settin…
traktore-org Nov 7, 2026
56d6c22
feat(#1321): translations for the five screens (16 languages), bundle…
traktore-org Nov 7, 2026
95b12f6
fix(#1321): first live look — price level in the header chip, mode na…
traktore-org Nov 7, 2026
b1aa8aa
fix(#1321): the Min-reached plan row carries its kWh, so the cards no…
traktore-org Nov 7, 2026
74ee71d
fix(#1321): the Sankey mounts on request — mounted by default it logg…
traktore-org Nov 7, 2026
8835cac
feat(#1321): every SEM Next text translated in all 16 languages
traktore-org Nov 7, 2026
f6aa700
docs(#1321): changelog line within the 25-word cap
traktore-org Nov 7, 2026
2e8f031
Merge develop (beta.8) into feature/1321-dashboard-next (#1321)
traktore-org Nov 8, 2026
f55eec6
fix(#1321): SEM Next buttons say when they fail
traktore-org Nov 8, 2026
34de9c3
feat(#1321): Devices folds to one line per device
traktore-org Nov 8, 2026
f39cd68
fix(#1321): "updated" shows the newest power reading
traktore-org Nov 8, 2026
c75e072
fix(#1321): SEM Next shows what is true
traktore-org Nov 8, 2026
674cd12
fix(#1321): the house lead is one sentence; Insights saved counts the…
traktore-org Nov 8, 2026
036d56d
fix(#1327): the battery card no longer reads as a worn-out battery
traktore-org Nov 8, 2026
6419258
fix(#1326): a load never seen running says "not measured yet"
traktore-org Nov 8, 2026
9189e3e
fix(#1324): energy flows add up to the meter-backed daily totals
traktore-org Nov 8, 2026
32da877
fix(#1325): the night plan's cost counts the house after the battery
traktore-org Nov 8, 2026
86efb63
Merge branch 'fix/1324-flows' into feature/1321-dashboard-next
traktore-org Nov 8, 2026
a133a1f
Merge branch 'fix/1325-plan-cost' into feature/1321-dashboard-next
traktore-org Nov 8, 2026
a470755
Merge branch 'fix/1326-rating' into feature/1321-dashboard-next
traktore-org Nov 8, 2026
22d721d
Merge branch 'fix/1327-capacity' into feature/1321-dashboard-next
traktore-org Nov 8, 2026
5d8cdff
fix(#1325): the plan cost tile counts the house night use in its kWh
traktore-org Nov 8, 2026
a1ddbf8
feat(#1321): SEM Next needs the old dashboard for nothing
traktore-org Nov 8, 2026
3f00ae9
fix(#1321): hardware panel names roles in words; held-back calls list…
traktore-org Nov 8, 2026
cea2293
fix(#1321): at night with nothing flowing the lead does not name the sun
traktore-org Nov 8, 2026
b5c6918
fix(#1324): the split follows the meters that count, without a solar …
traktore-org Nov 8, 2026
6094cfb
fix(#1321): optional chaining for a state read the lint flags
traktore-org Nov 8, 2026
71674c7
feat(#1321): SEM Next is the default dashboard
traktore-org Nov 8, 2026
a5f71a4
feat(#1321): the default dashboard is Solar Energy Management, the ol…
traktore-org Nov 8, 2026
d884916
feat(#1321): an hourly sun forecast for the Plan chart
traktore-org Nov 8, 2026
55858ee
feat(#1321): Price and plan as three lanes on one clock
traktore-org Nov 8, 2026
88af9ad
fix(#1321): two unnamed car rows in the plan chart are numbered
traktore-org Nov 8, 2026
6710bf1
fix(#1321): tomorrow's preview places the car the way its mode charges
traktore-org Nov 9, 2026
482c6be
Merge branch 'feature/1102-one-engine' into feature/1321-dashboard-next
traktore-org Nov 9, 2026
57b6601
chore(#1321): regenerate language files and cards after merging devel…
traktore-org Nov 9, 2026
f09e204
test(#1102): register the engine comparison as a publisher; preview c…
traktore-org Nov 9, 2026
1f73bd2
fix(#1102): a load's run time today survives a restart or a settings …
traktore-org Nov 9, 2026
9dc8d8e
fix(#1321): the chart tooltip always says price, sun and what runs
traktore-org Nov 9, 2026
15e4064
Merge branch 'feature/1102-one-engine' into feature/1321-dashboard-next
traktore-org Nov 9, 2026
0f2d325
Merge branch 'feature/1102-one-engine' into feature/1321-dashboard-next
traktore-org Nov 9, 2026
b889ba8
feat(#1321): tap the House row on Now to see the 3 biggest loads; the…
traktore-org Nov 10, 2026
82fe2f6
fix(#1321): the House top 3 reads devices like the Home tab — idle on…
traktore-org Nov 10, 2026
676f71d
Merge develop into feature/1321-dashboard-next (#1321)
traktore-org Nov 10, 2026
5430b9c
fix(#1321): per-battery entity pickers in System; Today shows each ch…
traktore-org Nov 10, 2026
273e82c
fix(#1321): plan_override knows chargers by the loop's id rule, and t…
traktore-org Nov 10, 2026
61a8819
fix(#1321): plan_override counts the charger index over the whole lis…
traktore-org Nov 10, 2026
b160818
feat(#1321): the plan shows why each block sits where it does and wha…
traktore-org Nov 10, 2026
7ca67ea
Merge fix/1309-1311-1331-plan-truth: one load engine (#1335), plan fi…
traktore-org Nov 10, 2026
7233b9b
fix(#1321): one-off override refuses unknown ids, reads real charger …
traktore-org Nov 10, 2026
7f3047d
test(#1309): the shared-helper check reads the call, not the source text
traktore-org Nov 10, 2026
482c3e5
test(#1321): the Now and System card tests run without node_modules, …
traktore-org Nov 10, 2026
5717ede
Merge branch 'fix/1309-1311-1331-plan-truth' into feature/1321-dashbo…
traktore-org Nov 10, 2026
acfa0b3
Merge remote-tracking branch 'origin/develop' into feature/1321-dashb…
traktore-org Nov 10, 2026
6d7c796
fix(#1335): a stop the minimum run holds says so, not 'running on sun'
traktore-org Nov 10, 2026
e88fbf0
Merge remote-tracking branch 'origin/develop' into feature/1321-dashb…
traktore-org Nov 10, 2026
21d85e7
fix(#1321): a pause does not release a peak step-down
traktore-org Nov 11, 2026
629e556
Merge remote-tracking branch 'origin/develop' into feature/1321-heate…
traktore-org Nov 11, 2026
64ef7d8
feat(#1321): a heater says what it does and why; the plan names its K…
traktore-org Nov 11, 2026
fc1e4d1
fix(#1321): the plan says 'cost not known yet' and lists a heater once
traktore-org Nov 11, 2026
355cc43
fix(#1321): a peak-only load says SEM only pauses it at a peak
traktore-org Nov 11, 2026
c5ee93f
Merge remote-tracking branch 'origin/develop' into feature/1321-heate…
traktore-org Nov 12, 2026
853a46e
docs(#1321): a blank line before the released section
traktore-org Nov 12, 2026
50deb54
feat(#1321): a load that buys no power says it waits for sun
traktore-org Nov 12, 2026
8812d4a
feat(#1349): SEM Next asks a heater's four questions, from the model …
traktore-org Nov 12, 2026
27c33d2
feat(#1349): SEM Next names a load's mode by who runs it; Today shows…
traktore-org Nov 12, 2026
1ee42d5
feat(#1349): SEM Next asks a cooling unit the same four questions; th…
traktore-org Nov 13, 2026
820071f
feat(#1349): SEM Next shows what SEM uses for a unit on its own setpo…
traktore-org Nov 13, 2026
0dda5e4
Merge remote-tracking branch 'origin/develop' into feature/1321-heate…
traktore-org Nov 13, 2026
2c4b981
Merge feature/1321-heater-says-why: SEM Next asks a heater four quest…
traktore-org Nov 13, 2026
e2940a6
fix(#1354): the System card says what the battery and price settings do
traktore-org Nov 13, 2026
f070a81
fix(#1354): a load has one mode control; rows SEM cannot use are hidden
traktore-org Nov 13, 2026
76da7b0
fix(#1354): the Now screen never shows the engine's raw text
traktore-org Nov 13, 2026
9a913d5
Merge fix/1321-wrong-texts: SEM Next — three wrong texts, one mode co…
traktore-org Nov 13, 2026
9fecd05
Merge origin/develop into feature/1354-next-shared
traktore-org Nov 13, 2026
b0c1eb7
feat(#1354): SEM Next uses the shared settings models — peak, battery…
traktore-org Nov 13, 2026
f941ef2
docs(#1354): the SEM Next guide names the peak question, the battery …
traktore-org Nov 13, 2026
04289b2
fix(#1354): next-settings imports only what it uses
traktore-org Nov 13, 2026
e6d735a
fix(#1354): no plan id or planner prose on screen in SEM Next
traktore-org Nov 13, 2026
51a4f1b
Merge feature/1354-next-shared: SEM Next uses the shared settings log…
traktore-org Nov 13, 2026
86c0cdf
Merge remote-tracking branch 'origin/develop' into feature/1321-dashb…
traktore-org Nov 13, 2026
fa85aeb
fix(#1321): SEM Next names a charger by its configured name in every …
traktore-org Nov 13, 2026
e42f1e1
Merge fix/1321-charger-name: charger names come from SEM's setting (#…
traktore-org Nov 13, 2026
d4f4a2b
feat(#1321): the dashboards are named SEM-dashboard and SEM-classic
traktore-org Nov 13, 2026
c9e642c
feat(#1321): Now shows where power comes from, the next 24 h of price…
traktore-org Nov 13, 2026
35fba90
feat(#1321): the plan says why per device, chargers show their charge…
traktore-org Nov 13, 2026
fe9867d
Merge branch 'feature/1321-engine-for-rien' into feature/1321-rien-in…
traktore-org Nov 13, 2026
17e58da
Merge branch 'feature/1321-now-phone' into feature/1321-rien-integrated
traktore-org Nov 13, 2026
80abe12
Merge branch 'feature/1321-plan-devices' into feature/1321-rien-integ…
traktore-org Nov 13, 2026
a2b96d7
fix(#1321): the cards read what the engine publishes
traktore-org Nov 13, 2026
d0802f7
fix(#1321): the average-price reader guards an absent state with ?.
traktore-org Nov 13, 2026
942f1f6
Merge remote-tracking branch 'origin/develop' into feature/1321-rien-…
traktore-org Nov 13, 2026
d10740d
Merge feature/1321-rien-integrated: Rien's review — low-risk parts (#…
traktore-org Nov 13, 2026
c2793fd
Merge feature/1081-cost-of-heat into feature/1081-next (#1081)
traktore-org Nov 13, 2026
217fe89
feat(#1081): SEM-dashboard shows the heat pump's COP and the cheapest…
traktore-org Nov 13, 2026
036c3ec
Merge feature/1081-cost-of-heat into feature/1081-next: the learned C…
traktore-org Nov 13, 2026
e23c954
Merge remote-tracking branch 'origin/develop' into feature/1321-dashb…
traktore-org Nov 13, 2026
6657850
Merge branch 'feature/1081-cost-of-heat' into feature/1081-next
traktore-org Nov 14, 2026
00d7a52
Merge branch 'feature/1081-cost-of-heat' into feature/1081-next
traktore-org Nov 14, 2026
44d3f5f
Merge develop into feature/1321-dashboard-next (#1321)
traktore-org Nov 14, 2026
076437d
Merge feature/1081-next: COP row on SEM-dashboard (#1081, #1321)
traktore-org Nov 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

# [Unreleased]

- ✨ **SEM-dashboard Now shows where power comes from in percent, the next 24 hours of price, and a chip per device** (#1321).
- ✨ **SEM-dashboard System shows each source's value and the entity SEM reads** (#1321), to check a setup.
- 🔧 **The two dashboards are named SEM-dashboard and SEM-classic in the sidebar** (#1321). The names change at the next "generate dashboard".
- ✨ **SEM Next: the plan says why per device, each charger shows its charge plan, the battery its reserve** (#1321). Phones get no sideways scroll.
- 🐛 **SEM Next shows a charger by its own name in every language, not as "ev charger 1"** (#1321).
- 🔧 **SEM Next asks the peak limit, battery levels and charger targets with the same words and logic as the classic dashboard** (#1354).
- ✨ **SEM Next: a heater says what it does and what comes next** (#1321), like "heats to 52 °C at 23:00".
- 🐛 **The plan chart shows one car as one row** (#1321). Tomorrow's preview named it differently from tonight's plan.
- ✨ **Each planned device says why its hours were chosen**: cheapest hours, sun, battery, before leaving or one rate (#1321).
- ✨ **On a dynamic tariff, the cost sensors show the average price paid per bought kWh and the average price of all hours** (#1321).
Expand Down Expand Up @@ -62,6 +69,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- 🔧 **Heaters with a thermometer and Keep at now join the shared plan on every install** (#1335). Cheap hours for the car and battery can shift.
- 🐛 **A load SEM started on sun now stops when solar production ends, even when its power sensor reads 0 W** (#1335).
- 🐛 **A planned comfort block now runs through without switching the load on and off** (#1334), also with Grid set to Off.
- ✨ **The new dashboard is the default, named Solar Energy Management** (#1321). The old one is now SEM Classic, kept for one release.
- 🐛 **Energy flows add up to your meters** (#1324). A missed reading no longer shortens the split or shows export the meter never counted.
- 🐛 **The night plan's cost now counts what the house buys after the battery runs out** (#1325). It showed empty before.
- 🐛 **A load SEM never saw running says "not measured yet"** instead of a made-up 1 kW (#1326).
- ✨ **SEM Next**: a new dashboard, five screens — one power bar, the plan on the price strip, devices you can reorder, settings as sentences (#1321).
- ✨ **The plan says why each block sits where it does, and what waiting saves against buying now** (#1321).
- ✨ **Loads get Boost: run now for 30, 60 or 120 minutes, then back to Smart** (#1321). A grid peak still stops it.
- 📝 **The load card's Comfort hint now says how Keep at is reached**: in the planned hour from any source, sun may go further (#1334).
- 📝 **The guides now explain Keep at, Extra from surplus and Run now past, and the order SEM follows** (#1334).
- 🐛 **EG4 Web Monitor: solar power is found and grid import reads right from the start** (#810). The charge-start SOC is no longer the target.
Expand Down
42 changes: 32 additions & 10 deletions __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3479,6 +3479,9 @@ def _deferred_entity_check(_now, _name=charger_name,
# (#1084) the Why? card reads the decision log over this command
from .decision_ws import async_register_websocket as _why_ws
_why_ws(hass)
# (#1321) the Plan chart's hourly sun forecast
from .solar_forecast_ws import async_register_websocket as _sun_ws
_sun_ws(hass)
# (#1174) the plain sentences the logbook names a decision with
from .plain_reasons import async_load_plain_reasons
await async_load_plain_reasons(hass)
Expand Down Expand Up @@ -4512,9 +4515,12 @@ async def async_stop_battery_boost(call) -> None:
async def async_plan_override_service(call) -> None:
"""(#1085 Part B) One-off: this device only, for this many
minutes — then it's gone, even across a restart."""
coordinator.set_plan_override(
call.data["device_id"], call.data["action"],
call.data["minutes"], call.data.get("value"))
try:
coordinator.set_plan_override(
call.data["device_id"], call.data["action"],
call.data["minutes"], call.data.get("value"))
except ValueError as err:
raise ServiceValidationError(str(err)) from err
await coordinator.async_request_refresh()

async def async_plan_override_clear_service(call) -> None:
Expand Down Expand Up @@ -4666,8 +4672,23 @@ async def async_remove_leftovers_service(call) -> None:
# Dashboard generation service
async def async_generate_dashboard_service(call) -> None:
"""Generate and install the SEM dashboard with all assets."""
from .features.dashboard_generator import (
CLASSIC_DASHBOARD_TITLE, NEXT_DASHBOARD_ICON, NEXT_DASHBOARD_PATH, NEXT_DASHBOARD_TITLE,
)
template = call.data.get("template", "next")
dashboard_title = call.data.get("dashboard_title", "Solar Energy Management")
dashboard_path = call.data.get("dashboard_path", "sem-dashboard")
# (#1321) SEM Next lives beside the classic dashboard: with the
# default title/path it lands at /sem-next, never over /sem-dashboard.
if template == "next":
if dashboard_path == "sem-dashboard":
dashboard_path = NEXT_DASHBOARD_PATH
if dashboard_title == "Solar Energy Management":
dashboard_title = NEXT_DASHBOARD_TITLE
elif dashboard_title == "Solar Energy Management":
# the main name belongs to the default dashboard now
dashboard_title = CLASSIC_DASHBOARD_TITLE
dashboard_icon = NEXT_DASHBOARD_ICON if template == "next" else "mdi:solar-power"

try:
from .dashboard_generator import DashboardGenerator
Expand Down Expand Up @@ -4906,6 +4927,7 @@ def _cache_bust_for(base_url: str) -> str:
dashboard_config = await generator.generate_dashboard(
dashboard_title=dashboard_title,
dashboard_path=dashboard_path,
template=template,
)

if not dashboard_config:
Expand Down Expand Up @@ -4963,7 +4985,7 @@ def _cache_bust_for(base_url: str) -> str:
if item.get("id") == dashboard_path:
item["mode"] = "storage"
item["title"] = dashboard_title
item["icon"] = "mdi:solar-power"
item["icon"] = dashboard_icon
item["show_in_sidebar"] = True
item["require_admin"] = False
dashboard_exists = True
Expand All @@ -4974,7 +4996,7 @@ def _cache_bust_for(base_url: str) -> str:
"id": dashboard_path,
"mode": "storage",
"title": dashboard_title,
"icon": "mdi:solar-power",
"icon": dashboard_icon,
"show_in_sidebar": True,
"require_admin": False,
"url_path": dashboard_path,
Expand Down Expand Up @@ -5047,6 +5069,7 @@ async def _delayed_restart(_now):
schema=vol.Schema({
vol.Optional("dashboard_title", default="Solar Energy Management"): cv.string,
vol.Optional("dashboard_path", default="sem-dashboard"): cv.string,
vol.Optional("template", default="next"): vol.In(["classic", "next"]),
}),
)
_LOGGER.debug("Registered service: %s.generate_dashboard", DOMAIN)
Expand Down Expand Up @@ -5984,11 +6007,10 @@ async def _async_install_card_assets(
dashboard_generated = True

# Method 2: Dashboard storage file (set by generate_dashboard service)
dashboard_storage = os.path.join(
hass.config.config_dir, ".storage", "lovelace.sem-dashboard"
)
if os.path.exists(dashboard_storage):
dashboard_generated = True
for _path in ("sem-dashboard", "sem-next"):
if os.path.exists(os.path.join(
hass.config.config_dir, ".storage", f"lovelace.{_path}")):
dashboard_generated = True

if not dashboard_generated:
_LOGGER.debug(
Expand Down
6 changes: 5 additions & 1 deletion coordinator/charging_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

import logging
from typing import Dict, Any, Optional
from dataclasses import dataclass
from dataclasses import dataclass, field

from homeassistant.core import HomeAssistant

Expand Down Expand Up @@ -115,6 +115,10 @@ class ChargingContext:
# Mode flags
charging_strategy: str = "idle"
charging_strategy_reason: str = ""
# (#1321) The primary charger's reason as a code + numbers, so a card
# can say it in the user's language. Recorded only; no decider reads it.
charging_strategy_reason_code: str = ""
charging_strategy_reason_params: Dict[str, Any] = field(default_factory=dict)

# Canonical strategy (EVBudgetStrategy.value string) — the input the
# canonical EV budget calc consumed in this cycle. Distinct from
Expand Down
Loading
Loading