API Changelog

Chronological public API changes (newest first). Contract = /docs spec + OpenAPI. AI overview: /docs/llms.txt.

This page documents changes to the public SpotpriceAPI in chronological order (newest first). Breaking changes are announced at least 30 days before removal, with a deprecation notice.

2026-08-30

  • Sparvo/Portal — WhatsApp referral: “Share via WhatsApp” / referral WhatsApp forms use data-sf-no-page-loading — no “Loading …” overlay before redirect to WhatsApp (fix: overlay stuck after cancel/back in the PWA). Additionally: loading modal dismisses on visibilitychange back to the app when the page was already fully loaded.

2026-08-28

  • Hours v1.11 (hours_demand_v1.11): Reserve (prep) sizing after planned cover/bridge/opp kWh (SOC path, not natural trough only) — basis.forward_prep.energy_kwh never above v0; optional notes: sized_after_cover. Decide + storage tile family B (simulate_week_grid, same predicates). Cover slots unchanged (non-regression). Kill-switch HOURS_PREP_AFTER_COVER=0. Audit-fix: plan_feasibility refreshed after prep trim — cover shortfall stays partial, prep-only trim does not false storage_undersized. All plants/keys. No PicoC repaste.
  • Hours cover slot rank (refactor, hours_demand_v1.10): Cover picker: per calendar day price rank, global cheapest day-head merge — same rule all days. Dominated-hour guard everywhere. Decide + explain. Family B: policy intent (autark, prep predicates, port room) — not the full picker/dominated guard in simulate_week_grid.
  • Portal/Sparvo — dump-price toggle removed: Day navigator (/live-strompreise, login, admin), Sparvo /prices, /plant, /plant-outlook, and /code-samples now display and calculate with model/point price only (price_ct_kwh / price_eur_mwh) — bars, min/max/avg, switch-on planning, grid-charge ranking, FC verification savings sim (/fc-verification, admin), landing #planung-live. No No dump correction | Dump price toggle, no midday hatch overlay. price_view=scenario in URLs is ignored. API fields dump_risk* / dump_scenario_* remain optional on GET /v1/forecast (unchanged). FC verification detail + CSV/PDF dump history unchanged. Cleanup: deleted dump-view-pref.js, removed dead i18n/CSS/JS remnants, code samples no longer inject dump helpers.
  • Wiki audit (lead + PicoC): Regression tests for lead blockquote on all PAGE_SLUGS DE+EN and PicoC `` fences alongside docs-lead` (copy-paste windows unchanged). Concept [API-DOCUMENTATION-PUBLIC-KONZEPT.md](../../API-DOCUMENTATION-PUBLIC-KONZEPT.md) § llms + wiki lead updated.
  • Wiki detail guide lead blockquotes: All Loxone PicoC guides (Hours, telemetry, Flex, legacy Windows, Forecast, PV, Weather) plus Plant telemetry, Webhooks, Weather, Errors, Download and Changelog DE+EN get lead > summaries (endpoint, PicoC version, Community 120/day, Loxone-first). Renderer docs-lead unchanged.
  • llms.txt v2 + wiki agent optimization: /llms.txt, /llms-full.txt, and new /docs/llms.txt follow llmstxt.org (blockquote summary, markdown links, pricing numbers, endpoint overview, cURL/Python/Loxone examples). Wiki hub and lead pages DE+EN consolidated (Loxone as primary EMS path, open REST API). Sparvo /llms.txt with GEO keywords, PWA/no-login, EV/heat-pump USPs.
  • Hours explain cover label: Cover slots show “economical cover hour” only — suffix “not the cheapest hour of the day” removed (portal/Sparvo, poll hours-decision-explain.js).
  • Hours cover slot rank (hotfix 2b / hotfix, hours_demand_v1.10): Dominated-hour guard on follow days; price rank all calendar days. Family B: policy shared, not full picker. No PicoC repaste.
  • Hours autarky gate v1.10 (hours_demand_v1.10): When PV+battery cover the horizon without grid charging (basis.autark_ok), planned charging is 0 kWh (cover, prep, dump, bridge) — Decide and the portal “battery size & spot cost” tile share the same policy. Gate window \(H_{gate}\) = rest-of-today from decide + next calendar day until morning sun (gate_h in autark_notes). All plants/keys. Additive: basis.autark_ok, basis.autark_notes. Kill-switch HOURS_AUTARK_GATE=0. No PicoC repaste (Extract v1.17 / Fetch v1.15).
  • Hours cover short-term v1.9 (hours_demand_v1.9): “Until this morning” SOC projection uses meter actuals (partial hour + 2–4 h recent rate) for cover load/PV and the grid-charge engine — consistent in Portal/Sparvo Hours explain and API (basis.load_refine, hourly_load_cover_kwh). Follow-day load profile unchanged. No PicoC repaste (Extract v1.17 / Fetch v1.15 unchanged).
  • Hours v1.9 audit fix: No double partial-hour in slot picker/consolidate after refine; awaiting_first_delta keeps meter-budget norm; plant-outlook chart uses the same cover load as Hours; SOC slice indices clamped to real hours. Extract v1.17: period up to 48, no 40 h reset of lastOkAbs. ExtractPvDaily v2.2: optional O8–O13 zeroed when JSON fields missing.
  • Hours v1.9 audit fix (2): Snapshot-first outlook patches cover load like live resolve; cross-midnight cover writes D+1 hours; load_kwh recomputed after patch. Extract v1.17 fallback O2 = hours in window (inclusive end hour).
  • Hours explain SoC sync: “Now” in grid-charge explain uses live telemetry SoC (not older decide snapshot); forecast stamps shift by SoC drift. Live-telem poll patches explain client-side.
  • Hours SOC sync audit fix: No cumulative projection drift on telem polls; idempotent server overlay (*_at_decide baselines); outlook patch recomputes pv_kwh.
  • Loxone offline fallback (Forecast · PV · Flex): PicoC fetch blocks use rename() backup instead of truncating JSON; on API outage O1=12 (Forecast/PV) and switching from last JSON (Flex boot phase 30). Versions: DebugSpotpriceFile v5.6, ParseSpotpriceForecast v18, DebugPvForecast v1.3, ExtractPvDaily v2.2, SpotpriceFlexWindows v0.6.11. Wiki DE+EN + code samples updated. No REST API change.

2026-08-27

  • Page-loading modal: Arm on submit only after sync handlers (setTimeout 0) — cancelled forms (empty admin password / dismissed confirm on members) no longer leave “Loading …” stuck over the page.
  • Landing + Sparvo marketing IA (Hours-first): Lower funnel Proof → Sparvo (guest app.sparvo.at/try) → Steps → wiki band /docs → FAQ (7) → CTA. Lead products Hours · PV · Windows Flex · 168h; Weather API not marketed. Portal SEO defaults + legacy refresh on portal boot. sparvo.at: FAQ/VideoObject, wiki footer, hero “specs in the wiki”.
  • Page-loading modal (Sparvo/Portal/websites): Same-origin navigations and slow first paints show a “Loading …” dialog until the HTML is ready (DOMContentLoaded). Fast pages (<≈280 ms) stay without overlay. Opt-out: data-sf-no-page-loading on body/link/form. Embeds unchanged.
  • Lazy-load Anlagenprognose (Sparvo/Portal): First paint uses mode=shell (PV + telem, no Hours Decide); Hours/horizon hydrate via /api/plant-outlook/data or /plant-outlook/data (mode=full). Hours resolve capped by HOURS_RESOLVE_MAX_PARALLEL (default 2, non-blocking); busy slots return JSON status=computing + HTTP 200 + Retry-After with client backoff (body remains parseable; Hours explain and day charge chips are kept on soft-busy — no day clobber). Soft-busy only for status=computing (not pending_hours alone). Incomplete/failed shells set pending_hours=false and do not show loaders without a hydrate mount. HTTP 503 (including outlook_failed) and 429 use the same backoff. Fetch/horizon chains use generation+abort; after Hours failure or horizon abandon (retry exhaust/hard error) only the loading skeleton is cleared (real fragments kept); charge_hours_source warning updates on hydrate. Horizon HTML: empty partial → empty fragment. TTL cache returns deep copies. Empty explain/horizon templates are shell-safe (fmt_num Undefined guard). Docs Markdown renderer process-lru_cache. Public API JSON contracts unchanged.
  • Hotfix PV-day on /plant: Precomputed outlook PV (midnight→…) is realigned from now for Hours/cover/follow-days — morning-sun stamps no longer show 23:00/00:00.
  • Audit fix plant primary / plant-weather: Claims transfer on set-primary runs in the same DB transaction as the primary flag; portal invalidates plan freezes like Sparvo; remove/leave/delete primary likewise. Secondary no longer counts skipped_secondary as a weather error (incl. geo-save). Wiki Weather/PV: refresh 05:20 + 12:20 Vienna (HA primary).
  • Battery size & spot cost (outlook/Sparvo): Chips split price basis (4 typical spot weeks / fallback) and load & PV (meter seasons / hybrid / estimate); 12‑month spot Ø remains meta. Season price state data/state/season_price_basis_latest.json (HA primary soft-fail). PV weather cache 2×/Vienna day (05:20 + 12:20), on-demand writes primary only. Citizen explain for the scale-up. /plant short-TTL + PV/forecast/meter dedupe. Hours Decide: basis.storage_horizon annual fields remain null. Sparvo /llms.txt + /ai.txt (marketing + app).
  • Plant primary user: Setting primary always moves device care and EMS connection (confirm dialog); clear-primary UI removed. Deactivating/deleting a primary returns claims to the plant administrator.
  • Hours auto-decide near min SoC (bidirectional): SOC ping at 10 pp / 5 pp / floor relative to min_soc_pct, and the mirror on recovery (floor → 5 pp → 10 pp → headroom / full O12). Internal async Decide (snapshot + plant.plan_updated on delta). Sparvo/Portal live; webhook immediately; Loxone Extract on the next Hours Decide. No Decision quota. Kill-switch HOURS_SOC_NEAR_MIN_REPLAN=0.

2026-08-26

  • Hours reserve v1.8 (hours_demand_v1.8): Cap = min(target, max(min+10 pp, min(target−10 pp, 85 %))). Lookback only vorrat_wuerdig (P20 ∧ absolute guard; dump on → ≤ limit incl. 0). Fill-day blocks prep including night. Dump before reserve (sizing + placement). Sticky lookback ≤P25. Force D0+Near ∪ D+1. Family B: Cap+port+same predicate. Soft-Stop overnight only cover/prep kWh. PicoC wiring unchanged (O1/O4 values follow engine).
  • Hours v1.8 audit fix: Sticky reads top-level forward_prep (snapshot shape); Force no longer bypasses Fill-day; Dump placement ≤ limit; Dump rank without Force; layer-B only vorrat_wuerdig; bridge separate; Family-B Cap clip. Docs: charge_now instead of charge_active. PicoC wiring unchanged.
  • Hours v1.8 follow-up: Sticky works outside P20 (≤P25); Family-B cheap picks stay in the calendar day; Sticky price from live series; storage tile kWh with 1 decimal.
  • Grid charge O11 vs connection rating: charge_power_kw (Loxone Extract O11) is min(inverter/max_charge, connection × 0.80 − base load) — not the raw grid connection rating. Portal/Sparvo plant profile shows the computed power under the connection slider. Thin Decide without battery.max_charge_kw; after saving the profile, tap Fetch I6. Planned hourly kWh may stay SoC/reserve-limited (not always full cap).
  • Portal navigation Plant: Under Plant, new Devices (SSO → Sparvo /devices, preconfigure devices) and EMS connection (/settings/ems, PicoC slots). EMS connection no longer under Account.
  • Plant primary user (Sparvo + Portal): Settings → Account shows plant administrator and plant primary user with badges (like Admin). The plant administrator can assign or clear the primary role among co-users — only after admin password (Portal: /settings/members; Sparvo: Account or /settings/members). Optional EMS claim transfer.
  • Sparvo/Portal EMS: UI Schedule (API field recipes unchanged). PicoC slots only in Portal EMS connection (/settings/ems) — Sparvo/migration never invent wallbox_*/flex_*. Unbound catalog devices: “EMS pending” chip + Portal link. Roles: Plant administrator / Plant primary user / Co-user. Catalog plant_sparvo_prefs per api_key_id. Binding is the serve source of truth for the slot (schedules / Flex merge).
  • Flex Sparvo merge: flex_pack=0 / I6=0 reads schedules from plant catalog plant_sparvo_prefs (owner prefs fallback). PicoC slot only via Portal EMS; claim preserved on re-bind.
  • EMS bind overlay: Serve/Flex use only bound PicoC slots (plant_ems_bindings); conflict losers and unbound catalog rows expose no slot in merge/schedules/Portal UI.
  • Following-days tile: Planned grid charge line only for planned hours on the tile’s calendar date — not hours listed as skipped cheap hours, and not next-day overnight charge inside the sun→sun window. Without·with grid at morning sun stays the real trajectory.
  • Reserve/cover before a later morning sun: The min+10 pp soft-cap applies before every morning sun (cover and reserve, not only the first night). Reserve fills only to the prep floor, not target SoC/100 % — expensive nights such as Mon 03:00/04:00 do not fill the pack when PV + cheaper daytime hours suffice. Survival (min SoC) stays separate.
  • PV-hour grid cap (hotfix): Re-assigning the same hour must not exceed remaining charge power − PV (no fallback to pack headroom → no 14,9 kWh slots on a 1,7 kW port room). After the picker, chronological clip: no further grid charge once Stopp-SOC is 100 % / pack full (e.g. no 0,8 kWh right after 13:00→100 %).
  • Hours backward-prep (hours_demand_v1.7): Each gap day looks back within pack carry \(H_{eff}\) (basis.carry_hours) — \(H_{prep}\) is the data window only, not clipped at \(t=0+H_{eff}\). A source day already filled by PV without grid (full PV, no 70% discount) takes no prep kWh — including evening after the fill. Far-cover only in [trough−H_{eff}, trough] and not on fill-days (no backdoor). Cover stretch ends at the last complete PV-day. Slot role prep → “reserve hour”. Every successful Decide (ok) runs prep + the slot picker (including when grid charge is off — then energy is zeroed). The battery size & spot cost tile (family B) uses the same sizing. PV hour: grid only charge power − PV (1 h: kWh≡kW); skip pv_fills_charge_power when PV saturates charge power. Ist/Sinnvoll € may change. Telemetry does not plan.

2026-08-25

  • Flex PicoC v0.6.10: I1=−1 clears lastEin; I1 off→on reparses in the same hour. Hours FetchPlantHours v1.15: 3‑minute pause is same-hour only (:00 after a late previous-hour Decide). ExtractHoursDemand v1.17: age in UTC hours — DST/month wrap no longer latches the 12 h fallback. Sparvo: duration 0,25 h on list/today; recipe summary without Loxone link; planner kWh in More disabled (recipe 0 wins); live telemetry day kWh one decimal.
  • Flex PicoC v0.6.9: Window-end stamps lastH only when I1=−1 — with I1 on, the hour reparse still runs so overnight does not stay on after winE. Sparvo: recipe 0,25 h stays 0,25; kWh recipes write target_kwh; weekly chips do not override recipes; oven and similar presets cannot stay api_linked.
  • Flex PicoC v0.6.8: I1=−1 writes the runtime file once at window end; I6=0 wipes leftover hours when the slot turns off (not only at 00:00/06:00); boot/I2/I7 stamp lastAutoHour (no double fetch in the same hour). Hours FetchPlantHours v1.14: I8 :00/:05 uses the 3‑minute cooldown (no Decide storm after FAIL). ExtractHoursDemand v1.16: month wrap no longer latches the 12 h fallback. PV/Weather debug v1.2: 0→10 hold 200 ms.
  • Sparvo/Portal: Empty recipe days stay empty after save/edit. Off-ladder recipe hours (e.g. 7 h) stay. AC preset 1,2 kW. Mix chips and week-glance kWh use a comma; plant-outlook kWh one decimal. EN wiring O3 on/off.
  • Flex PicoC v0.6.7: I6=0 wipes runtime at 00:00 and 06:00 only if the slot is off — leftover evening hours no longer block the next morning window. Hours FetchPlantHours v1.13: lastDecHour only after Decide OK (:05 retries a failed :00); I6 during a fetch queues Decide.
  • Sparvo/portal: same-clock recipe window shows a 24h hint. Week-glance hours use a comma (not 4.5).
  • Flex PicoC v0.6.6: I7 (wallbox Vc) re-arms after a fetch when the input falls to 0 — unplug/plug during a poll fetches again. Hours FetchPlantHours v1.12: O1 pause before Extract is 200 ms (Extract loop 100 ms) so Decide is not swallowed.
  • Sparvo devices: recipe summary in EN uses Mon–Sun; a 00–00 window shows 24h. Duration dropdown and recipe 1 (hours) stay in sync; save copies recipe hours onto device duration.
  • Flex PicoC v0.6.5: I2 (manual) re-arms after the first pulse when the input falls to 0 — a button fetches again. Runtime counts only while idle. Hours FetchPlantHours v1.11: an I5/I6 edge during a fetch is no longer lost.
  • Sparvo device form: Preset duration writes recipe 1 (hours) while that recipe still has the same number.
  • Sparvo device form: “Daytime only (08–22)” removed (it fought overnight wallbox/HP). Tap schedule weekdays to deselect; schedules 2–4 can be removed. All days off stays off (edit does not force Mo–So again). PicoC output O1–O8 was chosen in the Sparvo form then (since 26.08. only Portal EMS connection). With EMS on, More hides planner-only fields (values stay). Overlap 400 keeps days/windows. An existing EMS link stays visible without an API key.
  • Flex PicoC v0.6.4: I6=0 wipes runtime at 06:00 only if this slot is off (a 05–08 morning window keeps hours). I1=−1 no longer swallows I2/I7 edges or the hour change — returning I1 to 0 reparses or fetches.
  • Flex PicoC v0.6.3: I7/I2 edge after a fetch starts again (an edge during the poll is no longer lost). Overnight: do not wipe runtime at midnight (I6=0 resets at 06:00; I6 overnight at window end). I1=−1 also clears error/busy.
  • Flex PicoC v0.6.2: On the hour, on goes off if the new hour is not in slots[] (no stale load_now until :04). Runtime file always writes an ASCII dot (1.25), not a locale comma.
  • Flex PicoC v0.6.1: VO like Hours — {"slot_id":"3","flex_pack":<v.0>} (slot_id typed). Five <v.n> in one command is wrong (Loxone = one analog). I1=−1 clears O1–O8 latches. I6=0 sends progress/plug (segments=0); merge still runs. I7 edge fetches again. On the hour PicoC re-reads JSON locally (:04 stays the HTTP fetch). Omitting mode/role defaults to cheapest/consume. POST body accepts decimal commas. Hours persist is POST-only, ≤70 min.
  • Flex Sparvo/PicoC v0.6.0: Hours = battery, Flex = loads on/off. Sparvo recipes 1–4 + slot_id merge (flex_pack=0 omitted). PicoC O1–O8, I6=0 does not force 7, I1=0 means on. Hours O12 × battery_to_ev_pct (ev_charge_block / ev_charge_limit). Flex wiki rewritten; loxone.md budget 7/8 (skip weather).
  • Flex PicoC v0.5.1: Parse failure keeps LoadNow (wantLoad); I1=0 also clears ViGridChargeReq; Windows docs say Flex v0.5.
  • Flex PicoC v0.5: LoadNow from current slot hour (no stale ems.load_now on hourly reparse); live I7 each loop; no continue; I1=0 resets state; wiki I9+I10 required for hours_completed; flex_pack overrides body segments.
  • Docs UX Flex guide: /docs/loxone-windows-flex rewritten (short steps, step/example callouts, SVG flow, PicoC in appendix). Guide pattern in concept §12. Renderer: step + example callouts.
  • Flex deep-audit v0.4d: ISO window + deadline_hour without window_* infers clock hours from start/end (18:00→06:00, deadline 22 drops 02:00). Naive hour≤deadline removed. A deadline outside the window does not empty it. Flex wiki walkthrough DE+EN (callouts step/example, flow.svg), OpenAPI/concept §8.6 updated.
  • Flex deep-audit v0.4c: deadline_hour (Sparvo latest start) filters Flex candidates overnight-aware; windows_query carries deadline_hour; request echo window_source (flex_pack\|window_hours\|iso); deadline_strict/repeat_daily documented as echo/reserved; PicoC I1=0 also clears Demand/Period; concept §15.1 E = flex_pack.
  • Flex deep-audit v0.4b: device-schedules uses the same rolling overnight logic (post-midnight fix); windows_query carries only window_* hours (no ISO); request echo shows flex_pack/window_*; wiki explains why not multi-VO like Hours; Step 5 without ISO.
  • Hours/Flex deep audit: deadline_hour = latest start (overnight-aware, Sparvo). PV-days ignore brief midday dips; an incomplete last PV-day without the next morning sun gets no \(L_D\); prior-day hours only when \(P_{ref}(D)\) is finite. energy_deficit_kwh = placed need (leftover prep excluded). OpenAPI: start/end optional, flex_pack / window_* documented. PicoC I12 is diagnose-only; repeat_daily is not applied in v0.4.
  • Flex PicoC v0.4 + rolling window: window_start_hour/window_end_hour or Loxone flex_pack (I4|I5<<5|I6<<10|done<<16) in one <v.0>no daily ISO start/end. PicoC I4–I6 are the source of truth. O5 always writes the pack, never raw hours_completed. LoadNow only from ems.load_now (not window.start). prep_extra_energy_kwh = placed prep kWh. A Flex window beyond the tier is no_slots, not deadline.
  • Flex deep audit: live floor (no past hours in flex window); chronological next_slot_start; soft fallback prefers longest block; after end Demand/slots=0 + status deadline; empty flex exits keep ems; PicoC I1=0 clears LoadNow; OverrideEnable documented as reserved.
  • Flex PicoC v0.3 + API hardening: Poll accepts deadline/no_slots; PO Demand = remaining hours (0 when segment_complete or after end); deadline_reached whenever now ≥ end; live slots only from the current hour; chronological overnight slots; I7 gates LoadNow; I1=0 clears LoadNow; window.hours_requested = remaining need; DA baseline empty when remaining = 0; soft takes the longest block (price is tie-break only); ems.next_slot_start = next hour from now. (Historical: first-wallbox auto slot_id wallbox_1 — since 26.08. Portal EMS only.)
  • Flex docs completeness: Concept §19.5/§19.6 → POST + <v.0>; OpenAPI stub GET flex params + POST + device-schedules; PicoC then v0.2; now v0.4.
  • Windows Flex Loxone VO = Hours pattern: POST /v1/decision/windows with JSON body; dynamic values only via <v.0>/<v.2> on the VO Input (v0.4: flex_pack). Named <v.Vi…> dropped. PicoC then v0.2, wiki /docs/loxone-windows-flex updated.
  • Hours forward-prep (hours_demand_v1.6): After cover, every Decide sizes multi-gap prep (layer A \(G_{min}\) + layer B in PV-days \(D-2..D\)) inside \(H_{eff}\) (usable band / load-PV, summer floor 0.25·load, no jump to 168). Fields hours_needed_prep, prep_extra_energy_kwh, basis.forward_prep, basis.prep_horizon_hours. Slot role prep (“forward-prep hour”). Cheap-hold stays cover-only. Near soft-cap applies to cover and to prep hours before morning sun (no fill above min+10 pp). Storage-size tile uses the same policy; Ist/Sinnvoll € may change.
  • Docs/Wiki hub: Flex Windows linked from overview DE/EN (/docs/loxone-windows-flex); Loxone template + integrations README marked live (Wallbox step 1).
  • Loxone Flex Windows wiki: New step-by-step /docs/loxone-windows-flex (DE/EN) · PicoC SpotpriceFlexWindows.
  • Plant Device Schedules (Sparvo Flex 1b): GET /v1/plant/device-schedules returns Sparvo api_linked devices (slot id, segments, window, deadline) for Loxone/EMS. Community+; HTTP 200 with decision_status.
  • Loxone FetchPlantHours v1.10: Auto-Decide at hour :00 (I7+I8), :05 fallback only. Fixes relay gap: Extract clears O3/charge_now on hour tick; previously Decide waited until :05 so manual “fetch plan” was needed. Re-paste PicoC from /docs/loxone-hours.
  • Hours stop-SOC follow-on slots: When several charge hours fall on the same day, displayed stop SOC is non-decreasing in time (later hour ≥ earlier). Slot picker refreshes soc_projected_* from the final charge map (price order previously left stale end SOC).
  • Hours near/far cover (hours_demand_v1.5): Survival and hours until first morning sun (cover_window_hours_pv) only take the near need (chrono to PV + cover buffer, soft-cap morning SOC ≤ min_soc + 10 pp). Reserve-stretch kWh (weekend trough) schedule after morning sun — no more front-loading a full charge-power hour today (symptom: 8.3 kWh “minimum charge level” with morning with-grid ~45 %). Cover buffer again visibly affects the near share. Basis: energy_cover_near_kwh.
  • Decision Windows Flex v1.1 (additive): Optional query params segments, segment_consecutive (off/soft/required), hours_completed, current_segment_index, repeat_daily, deadline_strict, slot_id. With flex: decision_engine: windows_v1.1, ems block right after decision_status (PO Demand = ems.current_segment_hours, Period = ems.period_hours_today until window end). Without flex params, unchanged windows_v1. Deploy: deploy.sh api-only.
  • Explain stop-SOC / balance bars: Survival O4 pins to min_soc_pct only when below that floor. Stop SOC on every plan-slot line. Usable battery · now (night) / · At HH:MM (following day = PV-day start). Clock-only stamp in DE: um 08:00. Poll assets hx22.

2026-08-24

  • Hours DA replan (production): After day-ahead + inference, a batch replans all active plants (resolve_hours_demand, snapshot + plant.plan_updated). Poll hook + hourly timer 15:00–23:00 Vienna. Webhook materiality now includes the full plan (not just today’s slots) — EMS should pull hours_demand_url after the event. Optional plan_hash in payload.
  • Explain cover label: “economical cover hour” instead of “cheapest hour”. Cover slots that are not the day’s minimum get “not the cheapest hour of the day”. The “Cheaper hour skipped: …” line (cheaper_skipped) is not shown in portal/Sparvo (snapshot/diagnose only). Poll assets hx18.
  • P1-v2 same-day relocate: HOURS_CHARGE_DAY_CONSOLIDATE=1 (code default OFF) moves cover including survival onto cheaper chargeable hours of the same calendar day — including a single slot; current hour inclusive; elapsed hours stay. 0 €/MWh counts (not missing). Small survival (under 5 kWh) is omitted only when the SoC path still holds the reserve including slack. Slack below min_soc only with a price advantage. No new API field, no wait_cheap; O12 unchanged. Shadow log hours_consolidate_shadow.jsonl. Ops diagnose: diagnose-hours-charge-plan.py.
  • Fix: skipped-hours full list (portal/Sparvo): “Show all N” on /plant/skipped-hours or /plant-outlook/skipped-hours returned 500 Internal Server Error (Jinja: group.items resolved to the dict method, not the key). Full list renders chronologically by day again.
  • Following days charge effect + ⓘ: Per PV day in portal/Sparvo Explain: line Planned grid charge … kWh · Effect at morning sun: +X % (pv_day_charge_kwh, soc_delta_pct in snapshot rest_day_balances, UI-only). ⓘ explains reserve floor, direct grid supply below min SoC, and morning-sun stamp (not right after the charge hour). Poll assets hx17.
  • Week glance day label: hours_needed_days maps onto the calendar grid (D0…D6), not the sparse day_plan list — a day with charge shows 1 h planned again instead of “No charging” with a visible bar (wg6).
  • Hours API calendar day vs. app PV day: Decide/EMS (hours_needed_today, period_hours_today, prefix_*, day_plan) stay on calendar days 00:00–24:00 (Period until 23:00). Only Explain Following days in the snapshot (rest_day_balances) uses PV days sun→sun — not in the API response.
  • Storage tile expand: control rule clarified (discharge throttle only when demand is not covered autonomously from PV+battery); “Without a battery … kWh/day on the grid” line removed. Prefix-view line (“Optimizer period …”) hidden in Explain (EMS field unchanged).
  • Grid-charge plan summary copy: Replaced “Next PV yield …” (misleading at midday when PV is producing) with Current period: still X hours until … and In this period … grid-charge hours (portal + Sparvo).
  • Following days as PV days (sun→sun): After midnight until morning sun, the night belongs under Until tomorrow morning; the first following day is the current PV day from morning sun to next-day morning sun (not a second night stub). After morning sun / before midnight: following days start at the next morning sun. Bars and without·with grid share that window (portal + Sparvo).
  • Hours O12 when the pack is full: cheap-hold (discharge 0) only if there is a cover gap until the next morning sun. Not at SoC ≥99 % and not in a PV-surplus hour — a later reserve trough (e.g. Wednesday) alone must not close O12.
  • Hours cover/survival not in PV surplus: the slot picker does not grid-charge an hour whose PV exceeds load (and SoC is above min). Stretch must not pick the cheap solar peak (e.g. 10:00) as “minimum charge level”.
  • Hours interim 24 h: “next cheap hour” is only inside the next 24 h (not the cheapest slot in the 168 h horizon). No bridge charge in a PV-surplus hour. Reserve-survival later in the week is kept.
  • Hours dawn cover: a 3-hour lookahead alone does not count as “already in PV”. cover_window_hours_pv ends at today’s first good PV hour (not tomorrow 07:00). Survival stop-SOC (O4) is the reserve floor (min_soc_pct) only when below that floor; otherwise trajectory/target (never below live SOC). Interim grid charge only when there is a real e_gap (not a full hour at 0).
  • Plant outlook expand: plant-specific copy — extra grid kWh + € vs no battery; larger pack kWh + further €/year. Control rule (charge on cover gap; throttle discharge in cheapest hours only when not autonomously covered from PV+battery). Hours JSON unchanged.
  • Plant outlook storage tile: Sensible only if year € is cheaper and average ct/kWh is not higher than current — otherwise current / “fits”. Hours JSON unchanged.

2026-08-23

  • Hours cheap-hold (v1.4): Only when PV+battery cannot cover forecast load (load_covered_by_soc_pv=false): O12 = 0 in the cheapest N hours of the calendar day when not charging (cheap_hold) — house from the grid. If cover is already satisfied, discharge stays on (no speculative hold). Full cap while charge_now. N = ceil(daily load / charge kW). Annual tile uses the same cover gate. Fields cheap_take_hours, hour_is_cheap, cheap_hold.
  • Plant outlook storage tile: Copy is N cheapest hours + winter average (not autonomy days). Sensible only if the year is cheaper than current — otherwise current / “fits”. 24 h daily-load floor only while extra kWh do not raise year cost. Hours JSON still has no annual €.
  • Adaptive Hours cap, no default 36: without a request cap the server uses ceil(usable kWh / kW)+12, max 168. max_hours_today (default 12) is clamped to that cap. basis.storage_horizon omits annual € / size ladder (autonomy, defer, cap only). Annual spot and sensible size live on plant outlook (4 season weeks + 12-month market average).
  • ExtractHoursDemand v1.15: fallback after 12 h without API (summer 11–15 / winter 01–03, target 35 %). Txt2/Txt3: no-charge / X Std, Y kWh. Wiki/wiring aligned. Relay latch reset on hour change; year wrap counts as stale.
  • Plant following-days SoC: Portal/Sparvo show without·with grid per following day at the next morning sun (same as “Until tomorrow morning”), not at midnight. The last day may show a forecast-end stamp.
  • PV day navigation D0–D6: Portal plant outlook and Sparvo Plant PV bar chart show all 7 days (today…D+6) again — the UI had capped at 6 while backend/API already delivered 7.
  • Grid-charge dispatch unified: Annual storage cost (Familie B) and Hours EMS share grid_charge_dispatch — cheap hours are always FORWARD over this pack’s adaptive window (no 36 h default). Adaptive max_hours_horizon: without a request cap, Hours derives it from battery + charge power (need_h+12, max 168). Portal shows planning meta + warning on price heuristic without Hours engine. fc-verification stays a generic archive comparison (slider kWh/kW), not plant SOC simulation.

2026-08-22

  • Plant profile annual load: typical meter day × 365 (ceiled to 100 kWh) is written into the profile (portal/Sparvo open + save, telemetry including SOC-only, Hours, outlook, savings page) — not display-only. A stale form value (e.g. 6000) cannot overwrite the estimate.
  • Adaptive discharge reserve-protect: discharge_power_kw (O12) only throttles near min SoC and when no economical recharge is planned (interim pass / no charge slots). Otherwise full user cap. Charge hours stay at full cap (inverter already takes grid+PV). 0 kW only at/below min SoC with no recharge, or when the user cap is 0. No more spot-hold. Hours + plant.plan_updated include discharge_reason; an O12 cap change is material (webhook).
  • ExtractHoursDemand v1.11 (Breaking): API fields prefix_* instead of loxone_*; new charge_now, charge_stop_soc_pct, target_soc_pct, capacity_kwh. O3 = charge_now (relay), O4 = stop SOC %, O9 = remaining kWh (SOC delta), O1 = 0 when O9=0. Re-paste PicoC from /docs/loxone-hours. Legacy loxone_* in old JSON readable until re-Decide.
  • Hours Interim Econ default ON: HOURS_INTERIM_ECON is on (kill-switch =0). plant.plan_updated includes the same EMS scalars (prefix_*, charge_now, charge_stop_soc_pct, discharge_power_kw, adaptive_discharge, min_soc_pct, charge_power_kw, grid_charge_allowed).
  • Storage horizon is physical: Annual spot € uses PV→battery / battery→load / residual import in the same hour. Cheap hours only fill unused SoC — leftover annual kWh is not repriced onto the cheapest hours (that made 5 kWh look cheaper than 30 kWh).
  • UI decimal separator always comma: Portal/Sparvo/Admin display and Loxone txt_* use , in DE and EN (fmt_num / SpotDecimal). Machine values (data-*, JSON, CSS vars) keep ASCII dots.
  • Sparvo bar focus: Tap again shows kWh/ct (raw number in data-price, format display-only).
  • Plant explain backup reserve: “Without grid” rolls with profile min SoC (backup reserve), not a 0 % floor. Interim pass no longer strips survival slots — reserve charging stays in the plan. Bridge-charge copy + {min} % reserve only when SoC+PV do not already cover the window (otherwise “covered”). Following days: without·with grid always shown; with grid grayed when equal (&lt;1 % diff). O12 kW hint under the plan card removed.
  • Grid-charge explain plan summary: Portal/Sparvo replace chip/period pill with: next PV yield in X h from HH:MM · grid-charge hours until then · later charge list (date, day kWh, start·kWh). ⓘ only when cover is stretched → minimum charge level. Dump/bridge/off/none keep chip + short copy.
  • Charge-hour hint: Each planned hour shows a short reason (survival → hold min charge level, cover → cheapest hour, opp → opportunistic fill, bridge → bridge charge).

2026-08-21

  • Plant UI V1: Sparvo/Portal order Live → PV (day PV kWh stats only) → Plan/Explain → rest. Plan-span chart load + SoC with/without grid until morning sun; KPI at morning end. Live meter label “since {date}” (meter_baseline_at / reset fallback).
  • Hours Interim Econ (opt-in): Env HOURS_INTERIM_ECON (default off). When on: if SoC would breach min before the next cheap hour, compare bridge-charge € vs spot pass-through; only charge when strictly cheaper (+0.02 € EPS). period_hours_today may shrink (cap 5 h); EMS charge_hours_today then has at most one interim slot (later same-day cover stays in day_plan / charge_hours). Additive fields: period_hours_today_default, interim_period_active, interim_needed, interim_decision, interim_period_cap_h, interim_cost_*_eur, interim_slot_start, interim_reason. Extract O2 unchanged. Details: Hours Demand.
  • Explain: next planned grid charge clarity: Chip/headline for later show day kWh + planned HH:MM of the next charge day (not EMS total target and not the night-end stamp). Following-days stamp is a from–to range (night_end → reserve / last rest charge morning). Both cards list day blocks (kWh + time chips); survival slots marked (survival) with a short tip. 10‑min poll hx11.
  • Plant explain two horizons: Portal/Sparvo split Until tomorrow morning (load/PV/battery bars only through cover_window_hours_pv) and Following days (cover remainder when stretched). Battery always With·Without grid. PV week: dual EOD D0…D6 + stats row load·PV·battery With/Without. Skip copy in future tense; 10‑min poll redraws both cards (hx10).
  • Hours ↔ Loxone grid charge bidirectional: Decide JSON top-level grid_charge_allowed (EMS front). ExtractHoursDemand v1.17O10 = 0/1. Write: partial POST /v1/plant/telemetry {"grid_charge_allowed":0|1} (VO like SOC/meter). Omit field = profile unchanged. Last-write-wins with Sparvo/portal.
  • Hours night vs reserve: Explain splits Tonight (cover_window_hours_pv, first morning sun) and Reserve holds (cover_window_hours only when cover_extended_for_reserve). SoC without/with grid at both stamps. Chip stays “Today N h · M h in total”. Today 0 / week > 0 stays charge_kind=later (with-grid still shown at the reserve stamp).
  • Master switch grid_charge_allowed: Default on. Off → hours_needed*=0, empty slots, kind grid_off / reason grid_charge_disabled. Dump has no effect. An explicit telemetry field may set the profile; Decide without the field is read-only. Sparvo + portal location + plant badge.
  • Midday skip pv_will_fill_today: Look-ahead (PV×0.70, the slot’s calendar day, fresh SoC) replaces the single-hour PV formula. Leftover headroom instead of a binary skip. Survival candidates before fill. SNAP stays a device layer.
  • PV card day-end: D0 shows With grid / Without grid (soc_end_pct_with_grid / soc_end_pct_no_grid; alias soc_end_pct = with grid).
  • Portal/Sparvo grid-charge explain: Chip/headline now separate today’s EMS hours from hours until planning-window end (no more “32 kWh in 1 hour”). Skipped cheap hours are chronological with weekday+date; more than 6 rows link to /plant/skipped-hours or /plant-outlook/skipped-hours.
  • Hours cover on a weak weekend: Min SoC applies across D0…D6, not only until the first morning sun. If Saturday/Sunday sit on the reserve without PV carrying the pack, the engine stretches the cover window (cover_extended_for_reserve, cover_window_hours_pv = first PV recovery) and schedules mandatory grid charge (trough below the reserve, not the week’s net load). Raising min SoC (e.g. 20→40 %) must not merely pin end-of-day levels to the new floor. Portal/Sparvo week glance and the Hours API share this path.
  • Loxone d0_soc_eod load shape: End-of-day SoC now rolls the same hourly load/PV shape as plant outlook (meter/profile, D0 from the current hour). Flat 1/24 only as fallback without meter/shape. Meaning stays “midnight today”; values can differ from the old even split.
  • Portal/Sparvo timeline label (DE): German UI now reads “Zu Planende am {time}” (was “Am Planende um …”). English remains “At window end / at {time}”.
  • Plant outlook D0 SoC from now: End-of-day roll starts from the live SoC at the current local hour (no replaying midnight→now). After Hours day_plan, the SOC path is re-chained with the same charge chips. Loxone display pack uses the same D0-from-now logic. Prevents implausible calendar EOD vs plan-end when no grid charge is planned.

2026-08-20

  • Wiki access.tier: documented values are basic, community, full_trial, full_active (not professional/oem as JSON enum). Rate-limit table uses the same codes; Professional/OEM remain product labels. Telemetry softcaps: Community 2000/day, paid 10000/day.
  • Webhooks: registration and dispatch require HTTPS to a public host (HTTP, loopback, and RFC1918 rejected; redirects not followed). GET /v1/status no longer includes cache_path.
  • Hours cover load with sparse meter telemetry: WD/WE hourly shape no longer treats missing samples (None) as 0 kWh. Days with &lt;12 observed hours are skipped for the shape (flat 1/24 fallback); never-seen hours get a flat prior. Flat same-day overlay keeps rest-of-today positive (so_far + typical × remaining clock share) so cover evenings are not zeroed. Stops plan-end SoC stuck near 100% when the cover window includes the night (e.g. EMS posts only in the afternoon).
  • Portal/Sparvo plan-end battery level: “At window end” / Without·With grid projects SoC hour-by-hour over the cover window (no longer a bulk PV−load window sum). Surplus solar while the battery is already full is clipped — overnight drain shows a plausible plan-end level. Basis includes hourly_load_cover_kwh / hourly_pv_cover_kwh / hourly_grid_charge_cover_kwh. Cover shortfall also uses the same chronological check (max with bulk) so “no grid charge” is not claimed when the night would breach min SoC. Plan-end clock = hour floor + cover length (end of the last rolled hour). Rest-of-today load is spread across all remaining today hours (not only hour 0). Dump/Opp after the cover window does not raise plan-end SoC. Engine cover load/PV = sum of the hourly series (no parallel flat cover total). Legacy snapshots missing projected_soc_pct_with_grid no longer invent With-grid via an energy lump; Opp cap uses chronological cover need. Bulk fallback also respects allow_untimed_grid_lump.

2026-08-19

  • Hours Demand v1.3 — SOC-feasible grid charge: Engine hours_demand_v1.3 picks charge slots only when the battery has headroom and PV does not already fill the hour. Cheap but impossible hours appear in skipped_slots[] (always included); shifted charging in later feasible slots. plan_feasibility reports partial / storage_undersized when not all kWh can be scheduled. P1 survival before price; hourly load profile (WD/WE shape) in the SOC roll. Portal/Sparvo explain: new reason codes slots_skipped, storage_undersized plus lines like “16:00 cheap, battery full → next charge 03:00” in the Grid charge block (live resolve). PicoC/Extract unchanged (additive). Details: Hours Demand.
  • Plant weather for new sites: Daily spotforecast-plant-weather scans active API keys with Lat/Lon in user_plant_locations (discovery without a second timer) and writes data/plant_weather/{api_key_id}/. Also: portal geo-save and first PV/Weather request (on-demand). Directory ownership *:forecast mode 2775. PV Forecast Loxone pack uses the same request-path weather payload for Tmin/Tmax even if a disk write fails once.
  • Live strip day use after first meter ping: Portal/Sparvo Day use so far stays waiting for meter data (API day_import_kwh=0) until the first positive delta. The first cumulative total (or a 0 placeholder then the real total) is baseline only — not today’s kWh. No portal Reset meter needed for a new API key.

2026-08-18

  • Hours EMS Period until midnight: period_hours_today is hours remaining until 23:00 (00:00 → 23, 13:00 → 10, 22:00 → 1). At 23:00 it resets to 24. Demand/charge_hours_today only include slots in that window (hour 23 only from 23:00). Extract O2 maps the field (missing/<1 → 24).
  • Portal/Sparvo grid-charge blocks: Cover headline and cheapest charge times come from the same live Hours plan as the week glance (hours_decision in build_plant_outlook). Battery rules, dump, and location saves refresh the explain snapshot. A stale EMS snapshot may still update charge_power_kw, but not the hour count without new slots.
  • Hours grid-charge power: charge_power_kw is min(battery.max_charge_kw, grid connection × 0.80 − base load) (20 % reserve, same as Sparvo devices). hours_needed splits the kWh target across as many cheapest hours as that power allows (20 kWh at a 10 kW connection → 3 h at ~8 kW headroom, not 1 h × 20 kW).
  • Hours/profile min SOC default 20 %: When request and plant profile omit battery.min_soc_pct, the engine default is 20 (was 15). Stored profile values are unchanged. UI: portal /settings/location and Sparvo Settings → Battery rules (/settings#sv-storage-rules) with sliders for min/target battery level (0–100 %) and grid buffer (0–50 %, default 10 %).
  • Hours validation: battery.min_soc_pct / target_soc_pct outside 0…100invalid_input (same pattern as cover buffer 0…50).
  • Portal/Sparvo plant UI — less duplication: The live strip is the only display for battery level, day import, and meter total (portal /plant-outlook, Sparvo /plant). Below it: controls only — manual starting battery level (slider, fallback without live telemetry) and Reset meter baseline — no second value grid when live telemetry is active.
  • Hours explain block: Chip + headline only — the extra net summary under the balance chart is removed (same deficit was shown three times).
  • Sparvo /plant: Order is Live → Hours explain → PV day chart; Planned grid charge lists price/kWh per hour (switch days); need/rationale stays in the explain block above.

2026-08-17

  • Hours/portal load profile — same-day overlay: Estimated day use and remaining-today blend typical with meter-so-far using the WD/WE hour shape (not clock × 24). Incomplete today never counts as a full day, including for D+1. Same number in Hours, Sparvo live strip, and outlook D0. Engine tag stays hours_demand_v1.2. PicoC unchanged (fields hours_needed* / d0_load_kwh unchanged).
  • Loxone docs consolidation + PicoC audit: Canonical Loxone overview (one host VO, minute plan, max 8 PicoCs). Weather v1.1 start+:10 (no longer :05 next to Hours Decide). Forecast Debug v5.5 start+:01. Windows v2.2 auto :03. Hours Extract v1.8 reads JSON on start. Re-paste PicoCs from the guides.
  • Loxone PV Forecast auto-fetch v1.1 / Extract v2.1: Debug fetches on start (~3 s) and then hourly at :08 (not :05, so Hours Decide stays clear). Extract reads an existing spotprice_pv.json immediately after Miniserver reboot. Hours users: reuse the same VO parent and add only command FetchPvForecast. Re-paste both PicoCs from /docs/loxone-pv-forecast.
  • Loxone PV Forecast Extract v2.0: One GET /v1/plant/pv-forecast adds ready-made txt_d0/txt_d1 lines (weekday, date, PV, optional load, end-of-day SoC, Tmin–Tmax) plus week_kwh, d0_load_kwh, d1_load_kwh, d0_soc_eod, d0_tmax, d0_tmin next to d0_kwhd6_kwh. Missing parts are omitted (no default SoC 30%). End-of-day SoC includes grid charge only with a fresh Hours snapshot; otherwise PV vs load. loxone{} is at the start of the JSON. PicoC Extract v2.0 (O1…O13, Txt1…Txt3); Debug stays v1.0. Guide: /docs/loxone-pv-forecast.
  • Hours Demand cover buffer: Default 10 % on a positive cover shortfall (battery.cover_buffer_pct / plant profile; portal location + Sparvo Settings → Cover buffer, 0–50 %). energy_charge_kwh and hours include the buffer; a zero shortfall stays 0. Engine tag remains hours_demand_v1.2.
  • Sparvo cover buffer in Settings: Field under Settings → Cover buffer (/settings#sv-cover-buffer) and Cheap grid charging (/settings/dump) — not only Plant → location.
  • Grid-charge copy: Portal/Sparvo plant chip and headline show target kWh in the planned hour (charge only until that amount is in), not “for 1 h”.
  • Loxone FetchPlantHours v1.9 + ExtractHoursDemand v1.7: SOC 10% bands up and down → Telemetry+Decide; I7 every 15 min Telemetry, Decide only smart (today still needs charge and SOC rising); I8 :05 fallback; 3 min cooldown. Extract O1/O9 follow the API down as well (grid charge can stop). Re-paste PicoC from /docs/loxone-hours.
  • Hours Demand — slots from now: Charge times and price ranking start at the current local hour (no leftover midnight-window slots). hours_needed_today=0 stays 0 (no fallback to the week total). Portal/Sparvo clear charge chips on days without engine day_plan; D0 drops hours before *now*.
  • energy_charge_kwh: Grid-charge target rounded up to the next whole kWh (1.4 → 2), not max kW × hours. EMS fields sit at the start of the JSON (Loxone Extract ~2.3 KB fread).
  • Portal/Sparvo grid-charge chip: When today=0 but later days >0, no longer “No grid charging needed” — shows next grid charge (next_charge_start / next_charge_hours), same semantics as Extract Txt3. Week-glance chip Next ….
  • Loxone ExtractHoursDemand v1.5: new output O3 = energy_charge_kwh (optional kWh limiter) plus energy ratchet. Fetch stays v1.8. Re-paste PicoC from /docs/loxone-hours.

2026-08-16

  • Docs sync: Loxone overview / Hours / Telemetry / Plant Telemetry bumped to Fetch v1.8 + Extract v1.4; Hours Demand documents cover/dump/bridge; Telemetry guide links to Hours for the PicoC paste (no duplicate embed).
  • Loxone FetchPlantHours v1.8 + ExtractHoursDemand v1.4: Downward SOC bands 90→80→…→0 trigger Telemetry+Decide (in addition to hourly :05); Extract ratchets Demand upward within the calendar day (N_locked), midnight reset. Docs DE/EN Hours + Telemetry + code samples synced.
  • Hours Demand bridge fix: Bridge charge (hours_needed_bridge) only when Dump/Opp is on. With Dump off and cover satisfied → hours_needed = 0 (no spurious 1h bridge). Engine tag remains hours_demand_v1.2.
  • Portal/Sparvo grid-charge UI: Cover shortfall vs dump top-up separated (chip/headline/net); dump status + threshold in the section; Sparvo Settings → Cheap grid charging (/settings/dump).

2026-08-12

  • PV/Weather audit fix: Request-path Open-Meteo timeout 8 s (no 60 s worker freeze); cache_needs_refresh without empty-daily refresh loop; wind_speed_unit=kmh; Loxone double-GET coalesce for pv/weather; not_available before quota reserve + middleware quota_class (access_denied/pv/weather) so basic does not burn decision fair-use.
  • Plant-weather schema v2 live: Cache includes display fields (humidity, pressure, wind, weather code, daily min/max/sun); timer spotforecast-plant-weather 05:20 Vienna; deploy starts a background refresh for schema heal.
  • PV Forecast + Weather APIs (public): GET /v1/plant/pv-forecast (7-day yield kWh, class pv, Community 48/day) and GET /v1/plant/weather (site weather, class weather, 48/day). Docs DE/EN: /docs/pv-forecast, /docs/weather; Loxone guides /docs/loxone-pv-forecast, /docs/loxone-weather with PicoC Debug/Extract v1.0 + flow SVGs.
  • Hours info ⓘ UX: Tips on portal/Sparvo appear next to the tapped ⓘ (fixed) and close on re-tap/click, outside pointer, scroll, resize, or Escape.
  • Week-glance copy: Removed “(shared engine)” from visible portal/Sparvo strings (source line + charge hint).
  • Live strip UX: Removed method subtitle under “Estimated day total” (meter history / load profile) on portal /plant-outlook and Sparvo — tile shows the value only.
  • Portal/Sparvo week glance — audit fixes: missing strip_aria i18n, demo hint instead of silent hide, explain link only when week glance is present, bar height/CSS, Sparvo glance refresh, Loxone Hours prose O1/O2 → today-slice v1.3, DE Hours aligned to EN.
  • Portal/Sparvo Hours week glance: Plant outlook and Sparvo Plant show the 7-day plan (day_plan, default horizon 168 h) from the shared engine — separate from the cover planning window / last EMS decide. Docs DE/EN Hours + Loxone Extract table synced.
  • Hours Demand v1.2 — dual horizon: Default plan horizon 168 (request overrides). Caps max_hours_today=12 / max_hours_horizon=36. Additive response: hours_needed_today, charge_hours_today, period_hours_today, day_plan. EMS/Loxone Extract v1.3 reads the today slice (optimizer Period stays 24). Portal/Sparvo plant outlook charge chips from shared Hours engine (side_effects=False). Webhook plant.plan_updated compact (today + URL). Opp still only below Grenzpreis; cover still PV-recovery.

2026-08-10

  • Lead-aware dump scenario: dump_scenario_ct_kwh / dump_scenario_eur_mwh blend toward price × pct/100 when pct > 0 with lead weights D+1=1.0 / D+2=0.45 / D+3+=0.30 (never above the model price). Scope stays midday (midday_11_16) — no evening dump correction. price_ct_kwh unchanged. Clients should use API dump_scenario_*, not recompute locally.

2026-08-06

  • Live strip auto-refresh: Portal + Sparvo Live-Anlage strip refreshes ~every 15 min while the tab is visible (/plant-outlook/live-telem, Sparvo /api/live-telem) with an updated timestamp — no full page reload.
  • Estimated day use sooner from meter: Portal (/plant-outlook), Sparvo live telemetry, and Hours/load profile use meter history after ≥1 full meter day (was ≥2); until then annual÷365. Docs DE/EN + code samples synced.

2026-08-05

  • Docs / code-samples sync (Hours v1.1): /docs/hours-demand + /docs/plant-telemetry (DE/EN) and portal /code-samples Hours explain cover-until-PV, spike damping, and ≥2 full meter days; samples print decision_engine, cover_window_hours, remaining_today_load_kwh.
  • Portal live-telemetry hint: estimated day use correctly detects site_meter_history_* (previously exact match site_meter_history only → false annual÷365 hint).
  • Plant Telemetry / Outlook: SOC pings store history (plant_soc_samples); plant outlook shows hourly load/PV/SOC simulation (soc_model=hourly_v1); day chart: toggle Last/SOC, PV bars always on.
  • Hours Demand — load-learning spike damping: meter-day typical uses a soft cap (≤2× median of last 4 days) + 25 % robust blend — sustained load jumps still follow; one-off EV/spike days do not overdrive grid-charge planning.
  • Hours Demand v1.1 — cover until PV recovery: engine charges only the energy gap until the next good PV block (rest-of-today + D0/D1 window, cap ≈ rest-today+36 h), not the full 7-day load. Load profile: recency-weighted daily mean (half-life ~2 d, WD/WE). charge_hours prefer slots inside the cover window. New basis fields: cover_window_hours, remaining_today_load_kwh, horizon_load_kwh; engine tag hours_demand_v1.1.
  • Portal plant-outlook Load/PV/SOC: chart load from meter-delta day buckets (+ Hours estimate for D0…D6); D0 SOC = live; client refresh every 15 min via /plant-outlook/data; week line = grid charge cost (not household use).
  • Portal plant-outlook meter total: restored Import meter + day-so-far values in the “Live telemetry (EMS)” card (regression after the live strip).
  • Loxone telemetry-only guide: new Community page /docs/loxone-telemetry (DE/EN) after Overview — Analog Memory wiring, screenshot, FetchPlantHours v1.7 copy-paste; nav + pager + /docs-assets/….
  • FetchPlantHours v1.7: ~1 s O4 pulse for Analog Memory Set; Txt points to Memory→VO <v.2>; removed dead pulseTel path; meter magnitude for VI/checks (meterAbs).
  • Portal SOC slider vs live telemetry: Hours/telemetry SOC (hours_api) overrides manual slider values and locks the slider (~36 h freshness) on /plant-outlook and location settings; without fresh API SOC the slider stays available as fallback.
  • Telemetry rate limit: softcap for /v1/plant/telemetry raised to 2000/day (Community) / 10000/day (other) — still does not count against Decision fair-use.
  • Loxone telemetry <v.2> + partial POST: API accepts SOC-only / meter-only bodies; docs/VO guide use official Input placeholders instead of <v.ViName>; FetchPlantHours v1.6.
  • Live telemetry UI (portal + Sparvo): strip with battery SOC %, day import so far, estimated day total (meter history or load profile), and current meter total — Sparvo home, /plant, /plant-outlook.
  • Loxone FetchPlantHours v1.5 + Telemetry diag: API detects unsubstituted <v.…> tags (hint=loxone_vi_not_substituted) and returns quote-free diag for Txt2/Txt3; aggressive decimal-comma sanitization; PicoC v1.5 reads diag first.
  • Loxone FetchPlantHours v1.3: telemetry polls /user/common/spotprice_telemetry.json (like Decide) — Txt1/Txt2 + O13 show OK/FAIL/timeout instead of only “Telemetry done”.
  • Plant Telemetry API: empty/invalid body → HTTP 200 with telemetry_status + hint (no more FastAPI 422); accepts missing Content-Type and locale comma decimals.
  • Portal plant outlook — live telemetry: /plant-outlook shows SOC source/time, import meter total, day import so far, meter timestamp; Reset meter baseline button (next EMS ping = new start value). First meter total (e.g. 3725 kWh) is always baseline (meter.is_baseline).
  • Telemetry API response: explicit meter.is_baseline, meter.import_kwh_total, meter.observed_at; docs DE/EN synced.
  • Rate-limit headers on success: successful /v1/* responses now include X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, and X-RateLimit-Scope (same headers as on 429; Retry-After still 429-only).
  • Decision Windows missing params: missing start/end/mode/role return HTTP 400 incomplete_request (aligned with docs; no longer FastAPI 422).
  • API usage — Loxone double-GET coalesce: Identical api_key + path + method within 3 s is logged as quota_class=duplicate and does not increment portal/rate-limit counters (response still returned). Fixes Miniserver Virtual Output analog double-fire. Loxone tip: enable Use as digital output, leave Command OFF empty. DebugSpotpriceFile v5.4 keeps O4 high during fetch.
  • Loxone Forecast DebugSpotpriceFile v5.4: keeps O4 high during fetch (no mid-pulse 1→0); I1-rising trigger only + cooldown. Docs/samples synced.
  • Loxone Forecast — double API count: Not a server double-count bug — the Miniserver sent two real GET /v1/forecast calls (~2 s apart). Typical cause: Virtual Output Command OFF filled with the same URL as ON (PicoC pulse ON→OFF = 2 GETs). Fix: leave Command OFF + Header OFF empty; DebugSpotpriceFile v5.3 triggers manually only on I1 rising edge (not every nEvents). Docs DE/EN + /code-samples synced.

2026-08-04

  • Landing #planung-live: removed No dump correction \| Dump price toggle; ranking/sums again always use the model price (same as /fc-verification). Day navigator, Sparvo, and /code-samples keep their dump toggle.
  • Sparvo /prices + PDN: negative prices draw bars below the zero line (signed scale); PDN negative bar height fixed (more negative → taller downward).
  • Loxone Forecast PicoC v5.2 / v17 (live-verified): Debug requires a real forecast payload ("forecast": + price_ct_kwh + file length ≥ ~7 KB) — no false OK on forecast_status. Parse v17 reads price now/+1 h via start needles without pointer walks (v11–v16 hung on Miniservers after dump-JSON growth). Portal /code-samples Loxone Forecast ships both programs. Docs DE/EN /docs/loxone + /docs/loxone-forecast synced.
  • PDN UI: removed duplicate hour/price label in the chart header on hover/touch (#pdn-chart-focus); floating tooltip remains the sole detail surface (landing #strompreise, /forecast, /admin/forecast)
  • API hygiene — dump_scenario_* aligned to row price: After copying onto Decision / charge_hours / Windows slots, dump_scenario_ct_kwh / dump_scenario_eur_mwh are always recomputed from that row’s price × dump_risk_pct (no float drift from EUR÷10). Windows slots strip internal _ keys; public ranking stays on the model price.
  • PDN/Sparvo UI declutter: removed the “Dump risk” chip, help sheet, risk dot, Sparvo hint, home line, and tooltip “Possible dump (illustration)” — No dump correction \| Dump price toggle and midday hatching remain. API dump_risk* fields unchanged.
  • Sparvo tap focus: with Dump price active the focus line shows the dump price; with No dump correction it shows the point forecast.
  • Portal /fc-verification: removed the No dump correction \| Dump price toggle; savings simulation and chart again always rank on the model price (dump ranking skewed the savings % for end users). Dump history remains on /fc-verification/detail + CSV/PDF. Day navigator, Sparvo, and /code-samples keep their dump toggle; landing #planung-live also has no dump toggle (model price).
  • Forecast API — dump_scenario_* always usable: dump_scenario_ct_kwh / dump_scenario_eur_mwh hold the dump price when dump_risk_pct > 0, otherwise the point price (never null only because there is no dump). Clients need no null-check; whether a dump is active is shown by dump_risk_pct / dump_risk. Public Windows ranking stays on the model price. Loxone ParseSpotpriceForecast bumped to v14 (O6 = always-usable scenario/point price; show “Dump price” only when pct > 0). Docs + code samples synced.
  • Forecast API — dump_risk_pct + dump_scenario_* always on hours: every hour object on GET /v1/forecast (and inherited on decision[]/forecast[] in Decision, slots in Windows, charge_hours[] in Hours Demand) now always carries dump_risk_pct (0…100, never null) and dump_scenario_ct_kwh / dump_scenario_eur_mwh. dump_risk_p stays 0…1 unchanged (compat). price_ct_kwh / price_eur_mwh are never rewritten.
  • Portal dump-price toggle (Decision demo, /code-samples): same Overlay/Dump-price view as the day navigator/Sparvo on the landing planning demo and code samples — display/ranking only, in the portal UI or in the generated sample code. Public endpoints (GET /v1/forecast, GET /v1/decision/windows, …) keep returning the point price unchanged; price_ct_kwh never changes.
  • Docs/samples sync — dump risk & field start: Forecast docs DE/EN fix timestampstart; dump risk only on ML hours (forecast_d*), no soft-dump; Loxone ParseSpotpriceForecast v12 (O4 = risk code, O1/O2 unchanged); portal /code-samples print optional dump_risk/dump_risk_p
  • UI Dump price default: Day navigator (landing/user/admin) + Sparvo default to Dump price; Min/Max/Avg follow displayed dump/point prices
  • Sparvo/PDN focus: Tap/touch on dump-risk bars shows the displayed price in the floating tooltip (PDN); Sparvo keeps its tap focus line (toggle: dump vs point)
  • Forecast API — Dump risk (additive): GET /v1/forecast may include dump_risk, dump_risk_p, dump_risk_scope, dump_risk_version on midday ML hours (11–16 Vienna). No effect on price_ct_kwh / price_eur_mwh. Live experiment (ML_DUMP_RISK=live); kill-switch 0. Portal bar toggle Overlay \| Dump price.

2026-08-01

  • /docs Loxone wiring plan: overview + detailed plans (ASCII + output→input checklist) for Hours, Windows, Forecast; heading fragment anchors
  • Loxone FetchPlantHours v1.1: after Decide wait ~3 s then O1 0→10 for Parse (fix: O1 stuck at 10 → no hourly re-parse); Telemetry no longer triggers Parse; diagrams separate Telemetry vs Decide file
  • Loxone PicoC harden v1.2: FetchPlantHours polls decision_status (backup/truncate/timeout restore); Parse Hours/Windows/Forecast trigger only on O1 ≥10 (not fail=9)
  • Loxone PicoC harden v1.3: Parse keeps last Demand if file missing; Windows/Forecast VO pulse ~200 ms (v2.1/v5.1); Fetch poll requires status plus hours_needed/charge_hours
  • Loxone PicoC harden v1.4: commit Demand/slots only on decision_status=ok / valid Windows JSON — empty/invalid file no longer zeroes the optimizer
  • /docs Loxone version table: overview lists current PicoC versions (Fetch v1.2, Parse Hours/Windows v1.4, Debug Windows v2.1, Forecast v5.1/v11); guides re-synced with embedded sources
  • /docs beginner rewrite: full plain-language rewrite with everyday examples; Loxone guides step-by-step for users who have never used PicoC
  • /docs prev/next: every docs page including the hub has bottom Previous / Next controls (order = sidebar / PAGE_SLUGS)
  • /docs mobile UX: mobile-first layout, burger for the docs table of contents (same pattern as portal main nav), and a top-right copy-to-clipboard control on every code block
  • Loxone integration guides (new): public docs menu Loxone with overview, Hours & telemetry, Decision Windows, Forecast — step-by-step wiring and PicoC copy-paste at /docs/loxone
  • Hours Demand — charge_hours[]: POST /v1/decision/hours-demand in decide mode now always returns concrete start/end times and prices for every recommended charging hour when decision_status: ok, not just the count (hours_needed)
  • Plant Telemetry (new): POST /v1/plant/telemetry — submit battery SOC% and cumulative import meter readings; own quota class telemetry, does not count against the Decision fair-use limit
  • Hours Demand — mode: "telemetry": the same ingest path as Plant Telemetry is now also reachable directly via POST /v1/decision/hours-demand with mode: "telemetry"
  • Bridge breakdown in Hours Demand: new fields hours_needed_cover, hours_needed_opp, hours_needed_bridge, and plant_freshness in the decide response
  • Webhook plant.plan_updated (new): sent to your registered webhook URL whenever hours_needed or charge_hours[] change materially — same URL and secret as forecast.updated
  • Public API documentation (new): a full developer wiki at /docs, in German and English, crawlable and without login — replaces the previous plain status link in the footer

Earlier

  • Decision Windows API (GET /v1/decision/windows, engine windows_v1) — contiguous time windows with a full constraint set (min_gap_hours, max_consecutive, allowed_hours, weekdays, allocation)
  • Decision API (GET /v1/decision, engine quartile_v1) — quartile-based hourly signals charge/discharge/hold
  • Hours Demand Core (POST /v1/decision/hours-demand, engine hours_demand_v1) — first version with hours_needed derived from a SOC/load/PV balance
  • Forecast webhook (forecast.updated) — push notification after every successful forecast update
  • Forecast API (GET /v1/forecast) — hourly EPEX AT price series, 48h Basic / 168h full version

Version notes

  • API version: v1 (in the api_version response field)
  • Engine tags per endpoint: quartile_v1 (Decision), windows_v1 (Windows), hours_demand_v1hours_demand_v1.11 (Hours Demand; prep after cover v1.11, autark v1.10, prep v1.8)
  • Breaking changes are recorded here with date, affected endpoint, and migration window

Next steps

Start with SpotpriceAPI

Register for Community or code samples with your personal key.

Live API status