Skip to content

feat: v4.4.0 — balance rounding fix, desired range persistence, Tessie resync, Forecast to EV Capture Factor sensor - #51

Merged
Patrick1610 merged 6 commits into
developfrom
copilot/version-bump-4-8-0-again
Mar 11, 2026
Merged

feat: v4.4.0 — balance rounding fix, desired range persistence, Tessie resync, Forecast to EV Capture Factor sensor#51
Patrick1610 merged 6 commits into
developfrom
copilot/version-bump-4-8-0-again

Conversation

Copilot AI commented Mar 9, 2026

Copy link
Copy Markdown
Contributor

Version bump to 4.4.0 with several bug fixes, a new diagnostic sensor, and merge-readiness polish based on review feedback.

Breaking / Behavior Notes

  • Balanced mode rounding: balance priority no longer forces a minimum +1A step on upward modulation. A step only occurs when the EMA actually rounds to a higher integer (EMA ≥ 5.5A to step from 5A → 6A). Same clean-up applied to zero_prefer_export (floor) and zero_prefer_import (ceil).
  • Desired range persistence: desired_range is persisted in .storage/adaptive_charge and restored before the first tick, eliminating the momentary 100 km glitch on reload.
  • EV Charge Energy Added Sensor: fully removed from setup/reconfigure UI, all runtime data flow, coordinator data dict, sensor attributes, and translation strings. CONF_EV_ENERGY_ADDED_SENSOR is retained in const.py only for silent backward-compat deserialization of existing config entries — the value is never read or used.
  • Forecast to EV Capture Factor: measurement factor (range 0.0–1.0) returns 0.0 until sufficient history exists (denominator = 0). Storage keys forecast_capture_solar_wh and forecast_capture_opportunity_wh are new (default 0.0, merged on load from older stores). Utility meters remain coupled to Energy Charged / Battery Delta — not to this factor.

Changes

manifest.json

  • Version: 4.3.74.4.0

Balance mode rounding fix (coordinator.py)

  • Removed the forced max(current_int + 1, quantized) minimum step in _commit_current for modulate_up
  • Balance mode now uses pure round() quantization: EMA=5.27A with committed=5A correctly stays at 5A instead of spuriously jumping to 6A
  • A step only occurs when the EMA actually rounds to a higher integer (e.g. EMA ≥ 5.5A → steps to 6A)
  • Same correction applies to zero_prefer_export (floor) and zero_prefer_import (ceil) modes

Desired range reload persistence (coordinator.py, storage.py)

  • Added desired_range_km to the persistent store
  • Restored from store before the first tick fires, eliminating the momentary 100 km glitch on reload before the number entity's RestoreEntity hook runs
  • Both set_desired_range() and async_service_set_desired_range() now persist the value

Tessie / external current resync (coordinator.py)

  • Added _detect_external_current_override() with a two-tier detection strategy:
    • Within 120 s of last current set (_RESYNC_POST_COMMIT_WINDOW_S): 3 stable ticks required — covers Tessie overriding within seconds of our command
    • Outside that window: 6 stable ticks required — reduces false positives from EMA noise
  • Logging consolidated via local _reset(reason) helper; debug logging at every mismatch tick explains tick count, diff, and window state
  • Resyncs _committed_current to the EMA-implied value, correcting the permanent 1A offset

New sensor: Forecast to EV Capture Factor (sensor.py, coordinator.py, storage.py)

  • New ForecastToEvCaptureFactorSensor with entity key forecast_to_ev_capture_factor (measurement factor, range 0.0–1.0)
  • Semantically independent from the existing Solar-to-EV Ratio
  • Uses dedicated persistent accumulators: forecast_capture_solar_wh (numerator) and forecast_capture_opportunity_wh (denominator)
  • Opportunity energy accumulates only under EV-relevant conditions: vehicle present, battery < 90%, cable connected if configured, priority ≠ PRIORITY_EXPORT
  • Opportunity source: internal surplus_w (solar available to EV, clamped ≥ 0), falling back to solar_w
  • Intended use: remaining_forecast_today_kwh × forecast_to_ev_capture_factor
  • Utility meters (Energy Charged, Battery Delta) are not coupled to this factor

EV Charge Energy Added Sensor (coordinator.py, sensor.py, config_flow.py, strings.json, translations/en.json)

  • Removed CONF_EV_ENERGY_ADDED_SENSOR from both the initial setup flow and the options/reconfigure flow
  • ev_energy_added_kwh is no longer read at runtime, no longer included in the coordinator data dict, and no longer exposed in any sensor attributes
  • Removed orphaned ev_energy_added_sensor label and description strings from strings.json and translations/en.json — setup UI, runtime, and docs now consistently reflect the removal
  • self._ev_energy_added_sensor and CONF_EV_ENERGY_ADDED_SENSOR are retained silently only to avoid breaking existing config entries on load — the value is never used

Tests (tests/test_coordinator.py, tests/test_storage.py)

  • Updated quantization test helpers and all affected tests to reflect the corrected no-forced-step behavior
  • Added scenario-style flow tests: TestExternalResyncScenario (multi-tick Tessie override → resync → no lasting offset) and TestForecastCaptureAccumulationScenario (tick-flow accumulation with EV-relevant gating, including denominator=0 → 0.0 and clamp 0..1)
  • Updated TestBuildDataDictBatteryFields to reflect removal of ev_energy_added_kwh from the data dict
  • 780 tests, all passing

Documentation (README.md)

  • Added ### v4.4.0 changelog section with behavior notes, feature description, and migration notes

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Co-authored-by: Patrick1610 <6585375+Patrick1610@users.noreply.github.com>
Copilot AI changed the title [WIP] Prepare integration data export for analysis chore: bump version to 4.8.0 Mar 9, 2026
@Patrick1610

Copy link
Copy Markdown
Owner

Regarding the question "Wat heb je verder nodig?" (What else do you need?) for the analysis — here is the data that would be most useful alongside the energy dashboard CSV and history CSV exports:

From the Energy Dashboard export:
Grid import (kWh) — per hour/day
Grid export (kWh) — per hour/day
Solar production (kWh) — per hour/day
EV charger consumption (kWh) — per hour/day
Home battery charge/discharge (kWh, if present)

From the History export (all entities used in the integration setup):
sensor._power / sensor._current — the net power sensor
sensor._solar_power — solar forecast / actual solar
sensor.
_soc or similar — EV State of Charge
sensor._status — charger/EV status (charging, connected, idle)
number.
_current / input_number.* — the current setpoint entity
select.*_charging_priority — charging priority select
Any import guard triggers or grid power sensors

Additional context that would help:
The integration's stored state (.storage/adaptive_charge) at a few points during the period, if accessible
Timestamps of any manual interventions (app overrides, manual charging start/stop)
Your local timezone and sunrise/sunset times for the test period
Whether a home battery is present and its capacity

@Patrick1610

Copy link
Copy Markdown
Owner

Tessie charge current can get out of sync, sometimes an external source sets the A one step back within 10s of a new setting. The app does not resync after this resulting in an offset in stable conditions

@Patrick1610

Copy link
Copy Markdown
Owner

On reload the range sensors calculate based on 100km (or maybe the setting during setup) for a moment. Make sure the desired range is not an input during setup and is persistent until the desired range sensor is available.

@Patrick1610

Copy link
Copy Markdown
Owner
{C7F3F9F4-EBCF-4A6C-A796-B7C05260086E} priority is balanced, dus dan zou de afronding naar 6 niet plaats mogen vinden

@Patrick1610

Copy link
Copy Markdown
Owner
{97A893E4-1044-4510-9658-72C22FE3C57D} hier is de current decission hoger dan de lader zelf, en hoger dan hij zou moeten zijn (balanced mode) vanaf 10:55:15. De beschikbare stroom zit structureel onder de 5.5 en zou dus 5 moeten zijn (round)

@Patrick1610

Copy link
Copy Markdown
Owner

Implement a new diagnostic + forecasting-oriented sensor named:

Forecast to EV Capture Factor
entity key: forecast_to_ev_capture_factor

Goal

Add a new sensor that answers this question as simply and reliably as possible:

“What fraction of the remaining solar forecast today is likely still usable for EV charging?”

This sensor must be designed specifically for forecast-to-EV estimation.

Important:
Do NOT base this new sensor on the existing Solar-to-EV Ratio.
The existing Solar-to-EV Ratio should remain available as a broad lifetime KPI, but this new sensor must have its own explicit semantics and its own dedicated calculation path.

Reason

The current Solar-to-EV Ratio is conceptually too broad for forecast estimation because it represents solar energy that reached the EV versus total produced solar energy, which dilutes the value with many periods that are not EV-relevant (vehicle away, battery already high, cable disconnected, etc.).

For forecast estimation we want a different question:

“Of the solar opportunity that existed while the EV was actually in a position to benefit, what fraction was historically captured by the EV?”

That is the value we want to multiply against Remaining Forecast Today.

Required design principles

Prioritize:

  • simplicity
  • robustness
  • transparency
  • low false precision
  • stable output

Do NOT introduce a complex predictive model.
Do NOT use hourly matching, household-load forecasting, charger phase modeling, or many new tunables.
Keep the design intentionally simple and reliable.

Use existing configured integration inputs

Use the entities/concepts already configured in the integration, by their integration meaning, not by hardcoded user-specific entity IDs:

  • EV Power Sensor
  • Vehicle Presence
  • Cable Connected Sensor
  • Battery Level Sensor
  • Solar Generation Sensor(s)
  • Remaining Forecast Today (kWh)
  • Charging Priority / charging mode logic already present in the integration

New sensor meaning

The new sensor must represent:

historical EV capture factor under EV-relevant solar opportunity conditions

This is NOT:

  • EV solar energy / total solar production

This IS:

  • actual EV solar capture / EV-relevant solar opportunity

Recommended implementation

Implement this as a ratio of two cumulative internal energy counters.

  1. Numerator:
    actual_ev_solar_capture_energy

    Definition:
    cumulative energy that truly reached the EV from solar opportunity under the integration’s own logic.

    Reuse existing raw/internal tracking if appropriate, but do NOT simply reuse the existing Solar-to-EV Ratio or make this new sensor depend semantically on that KPI.

  2. Denominator:
    ev_solar_opportunity_energy

    Definition:
    cumulative solar opportunity energy that existed only during EV-relevant conditions.

    This denominator should accumulate only when all of the following are true:

    • Vehicle Presence indicates the vehicle is home/present
    • Battery Level Sensor exists and battery level is below 90%
    • Cable Connected Sensor exists and indicates connected
      • if Cable Connected Sensor is configured, require it
      • if it is not configured, fall back gracefully without hard failure
    • charging priority / mode is one where EV solar capture is relevant
      • do not treat modes that intentionally suppress EV solar usage as equal solar opportunity
    • solar opportunity input must never be negative

Solar opportunity source

For the denominator, prefer the most EV-relevant internal source available:

Preferred:

  • an internal surplus/opportunity value that represents solar available to the EV, ideally excluding EV self-counting and clamped at zero

Fallback:

  • summed Solar Generation Sensor(s)

If a surplus-style internal source exists and is reliable, use that.
If not, fall back to current solar generation.

In all cases:

  • clamp negative values to zero
  • the denominator must represent realistic EV-relevant solar opportunity, not generic household solar production

Output sensor behavior

Expose:

Forecast to EV Capture Factor
entity key: forecast_to_ev_capture_factor

State:

  • numeric factor between 0.0 and 1.0
  • not a percentage sensor by default
  • clamp to [0, 1]
  • if denominator is 0, return 0

Examples:

  • 0.00 = historically none of the EV-relevant solar opportunity was captured
  • 0.50 = about half was captured
  • 1.00 = all was captured

This should be a cumulative/stable historical factor, not a rapidly oscillating real-time percentage.

Optional supporting diagnostic sensor

If useful for debugging, also expose:

Forecast to EV Opportunity Energy
entity key: forecast_to_ev_opportunity_energy

Only add this if it materially improves transparency/debuggability.

Intended use

This new sensor should become the preferred multiplier for estimating remaining forecast usable by the EV.

Conceptual usage:
remaining_forecast_today_kwh * forecast_to_ev_capture_factor

Optionally, downstream logic may additionally gate this by simple real-time availability conditions such as:

  • vehicle present
  • battery below threshold
  • cable connected if available

But the capture factor itself should remain a historical stable factor.

What NOT to do

  • Do NOT alias this to Solar-to-EV Ratio
  • Do NOT define it as EV solar energy / total solar production
  • Do NOT make it depend on utility meters as the primary calculation method
  • Do NOT make it a daily-only reset metric
  • Do NOT overfit to one exact charger minimum current or one exact household pattern
  • Do NOT build a fragile “smart” forecast model with many assumptions

Backward compatibility / UX

  • Keep the existing Solar-to-EV Ratio unchanged as a general lifetime KPI
  • Add Forecast to EV Capture Factor as a separate forecasting-oriented diagnostic sensor
  • Make the distinction clear in names/descriptions:
    • Solar-to-EV Ratio = broad lifetime solar KPI
    • Forecast to EV Capture Factor = EV-relevant solar opportunity capture factor for forecast estimation

Implementation preference

Use the simplest implementation that fits the current architecture:

  • accumulate actual EV solar capture energy
  • accumulate EV-relevant solar opportunity energy
  • expose forecast_to_ev_capture_factor = actual / opportunity
  • clamp to 0..1
  • keep semantics fully independent from the existing Solar-to-EV Ratio

Final priority

The most important requirement is semantic quality and reliability.

This sensor must give us full control over a trustworthy forecast-oriented output.
It is better to have a simpler but well-defined and robust sensor than a more advanced-looking sensor that depends on broad or diluted assumptions.

@Patrick1610
Patrick1610 deleted the branch develop March 10, 2026 11:13
@Patrick1610 Patrick1610 reopened this Mar 10, 2026
@Patrick1610

Copy link
Copy Markdown
Owner

de version bump van 4.3.7 moet naar 4.4.0, niet 4.8.0

@Patrick1610

Copy link
Copy Markdown
Owner

Implement a full simplification/rebuild of the charging overhead and charged-energy model.

Main objective

Replace the current mixed / partially session-based overhead logic with a simpler, more explicit and more reliable model based on:

  1. wall energy delivered to the vehicle, derived internally from EV Power Sensor
  2. battery energy delta, derived primarily from EV Battery Energy Sensor

This change should also make the EV Charge Energy Added Sensor obsolete in setup and implementation.

The result should be:

  • clearer semantics
  • fewer moving parts
  • more trustworthy output
  • full control over data quality
  • one consistent wall-kWh source for overhead and charged-energy reporting

Core design decision

The integration must no longer treat EV Charge Energy Added Sensor as a required or primary source.

Remove EV Charge Energy Added Sensor from the config/setup flow.

Charging overhead and charged-energy reporting should instead be based on:

  • EV Power Sensor -> internally integrated wall energy in kWh
  • EV Battery Energy Sensor -> battery-side delta in kWh

If EV Battery Energy Sensor is not configured, allow a fallback based on:

  • Battery Level Sensor
  • usable battery capacity / estimated battery capacity already present in the integration

But the preferred and primary model must be battery-kWh based.

Semantic definition

Redefine Charging Overhead as:

the difference between:

  • what leaves the house via the charger
    and
  • what actually ends up in the EV battery

Everything between those two is overhead.

This explicitly includes:

  • charger losses
  • cable losses
  • AC/DC conversion losses
  • battery heating/cooling during charge
  • BMS balancing
  • pre-charge battery conditioning during an actual charging session
  • all other battery-side overhead

Do NOT try to separate these categories.
All of them count as overhead.

Formula

Use:

overhead_factor = 1 - (battery_delta_kwh / wall_energy_kwh)
overhead_pct = overhead_factor * 100

Where:

  • wall_energy_kwh = integrated EV Power Sensor energy during qualified charging
  • battery_delta_kwh = current battery energy - session start battery energy

Clamp nonsensical results safely where appropriate.

Qualified charging session

A charging session must only start when charging is genuinely happening under the integration’s own control logic.

This is required to exclude situations like:

  • vehicle wake-up draw
  • defrost / preconditioning draw without actual charging session
  • standby consumption
  • cable connected but not truly charging

Create a clear internal condition similar to:

qualified_charging_active =

  • Charge Switch is ON
  • AND (charging_active OR force_active) is true
  • AND EV Power Sensor is above a configurable / internal minimum threshold
  • optionally also require Cable Connected Sensor if configured

Session start snapshot

When qualified_charging_active transitions from false to true, create a session snapshot:

  • session_start_battery_kwh
  • session_start_timestamp
  • reset / initialize session_wall_energy_kwh accumulator

This snapshot must be robust and deterministic.

Session wall energy

Internally integrate EV Power Sensor into wall energy kWh.

Do this inside the integration, not by relying on an external HA Integral helper.

This should become the canonical source of charger-delivered session energy.

Suggested internal behavior:

  • accumulate delta_kwh from EV Power Sensor over time
  • only accumulate while qualified_charging_active is true
  • preserve state cleanly across updates/reloads if the integration already has session persistence patterns

This internal wall-energy kWh should then become the primary source for:

  • charged energy reporting
  • charging overhead reporting
  • utility sensors related to charged energy

Battery energy source priority

Use this source priority for battery-side energy:

  1. Primary:
    EV Battery Energy Sensor

    • current actual battery kWh
    • compute battery_delta_kwh from session start snapshot
  2. Fallback:
    if EV Battery Energy Sensor is unavailable or not configured,
    but Battery Level Sensor and battery capacity are available:
    estimate battery energy as:
    battery_energy_kwh = soc_pct / 100 * usable_capacity_kwh

  3. If neither path is available:
    overhead must gracefully report insufficient data rather than fabricate a value

Important:
Do NOT keep EV Charge Energy Added Sensor as a hidden primary/secondary truth for overhead.

EV Charge Energy Added Sensor removal

Remove EV Charge Energy Added Sensor from setup/configuration.

This sensor should no longer be selectable in the integration options/config flow.

Also remove any logic where charging overhead, charged energy, capacity estimation, diagnostics, or session math depend primarily on EV Charge Energy Added Sensor.

If there is any remaining use that is still valuable for diagnostics, it may remain only as a low-priority optional internal auxiliary source, but it must not shape the main semantics anymore.

Preferred outcome:

  • EV Charge Energy Added Sensor fully removed from user setup
  • no user dependence on it
  • no main calculations depending on it

Charged energy sensor rebuild

Rebuild the integration’s “charged energy” output so that it is based on the new internal wall-energy kWh accumulator derived from EV Power Sensor.

This means:

  • the integration should expose a wall-energy-based charged energy sensor
  • this becomes the canonical “energy delivered by charger” value
  • any utility sensors / utility tracking derived from charged energy should use this new wall-kWh source

In other words:
“charged energy” should now consistently mean charger-delivered wall energy, calculated internally from EV Power Sensor.

This creates one coherent foundation:

  • charged energy = wall-side delivered energy
  • overhead = wall-side energy vs battery-side delta

Session vs historical overhead

Separate session and historical concepts clearly.

  1. Session overhead

    • calculated only from current qualified charging session
    • based on:
      session_wall_energy_kwh
      session_battery_delta_kwh
  2. Historical overhead

    • based on finalized sessions only
    • use cumulative finalized totals:
      lifetime_wall_energy_kwh
      lifetime_battery_delta_kwh

Historical overhead should be the stable main value used by the integration for planning and calculations.

Session overhead may exist as a diagnostic/live sensor, but it should not be the main truth used everywhere.

Session finalization

At end of a qualified charging session, finalize:

  • session_wall_energy_kwh
  • session_battery_delta_kwh
  • session_overhead
  • add finalized values to lifetime totals

Use finalized session totals to build the historical overhead value.

This is preferred over continuously blending partial session data into one mixed overhead value.

Quality / robustness rules

  • keep semantics explicit
  • prefer simple deterministic math
  • avoid hidden blending between session and lifetime values
  • avoid dependence on resetting / session-fragile EV-reported energy-added sensors
  • preserve behavior cleanly across reloads/restarts where possible
  • handle unavailable/unknown values gracefully
  • avoid nonsense outputs when wall_energy_kwh <= 0 or battery_delta_kwh <= 0
  • clamp impossible ratios where useful
  • expose clear source/fallback state for debugging

Recommended diagnostics

Add or preserve diagnostics that make the system auditable:

  • Session Wall Energy
  • Session Battery Delta
  • Charging Overhead Source
  • Historical Wall Energy Total
  • Historical Battery Delta Total

Charging Overhead Source should clearly indicate for example:

  • battery_energy_sensor
  • soc_capacity_fallback
  • insufficient_data

Optional:
also expose whether a session is currently in qualified charging state.

Naming / semantics

Use names/descriptions that make the distinction obvious:

  • Charged Energy = charger-delivered wall energy
  • Charging Overhead = difference between wall energy and battery energy
  • Historical Charging Overhead = stable long-term planning value
  • Session Charging Overhead = current-session diagnostic value

The wording should make it impossible to confuse:

  • wall-side charged energy
    with
  • battery-side energy gain

What NOT to do

  • Do NOT keep EV Charge Energy Added Sensor in setup as a primary option
  • Do NOT continue to define charged energy using EV-reported “energy added” if EV Power Sensor is available
  • Do NOT continue to use a blended mixed model if a simpler session-finalized model can be used
  • Do NOT try to split charger losses vs BMS losses vs thermal losses
  • Do NOT count non-qualified vehicle draw (wake-up / defrost / idle draw) as charging session energy
  • Do NOT hide whether overhead is measured from battery kWh or estimated from SOC fallback

Intent

We want one clean and trustworthy energy model:

  1. wall energy is derived internally from EV Power Sensor
  2. battery energy is derived primarily from EV Battery Energy Sensor
  3. overhead is the gap between those two
  4. charged energy sensors and utility sensors are based on the same new internal wall-kWh source
  5. EV Charge Energy Added Sensor is removed from setup because it is no longer needed for a high-quality implementation

Final priority

Favor semantic clarity and reliability over cleverness.

It is better to have a simple, explicit and internally consistent wall-kWh vs battery-kWh model than a more complicated model that depends on ambiguous or resetting vehicle-reported “energy added” values.

@Patrick1610

Copy link
Copy Markdown
Owner

@copilot

PR Plan — Alleen verwerkt uit de 7 meegegeven PR-comments

Bronnen voor dit plan (exact deze comments):

  • #4030972756
  • #4030595823
  • #4031302233
  • #4022957732
  • #4022580726
  • #4022441732
  • #4022430315

Alles hieronder is direct afgeleid van bovenstaande comments. Geen extra roadmap-items.


1) Scope (alleen deze commentpunten)

  1. Version bump corrigeren

    • Versie moet van 4.3.7 naar 4.4.0.
    • Niet naar 4.8.0.
  2. Nieuwe sensor: Forecast to EV Capture Factor

    • Nieuwe forecasting/diagnostic sensor met key: forecast_to_ev_capture_factor.
    • Semantiek: historisch aandeel van EV-relevante zonne-opportunity dat effectief door EV is benut.
    • Mag niet semantisch leunen op bestaande Solar-to-EV Ratio.
  3. Rebuild charging overhead + charged-energy model

    • Vereenvoudigen/herbouwen naar één consistent model:
      • wall-side energy intern afgeleid uit EV Power Sensor,
      • battery-side delta primair uit EV Battery Energy Sensor,
      • overhead = verschil tussen wall-side en battery-side.
    • EV Charge Energy Added Sensor uit setup/hoofdsemantiek verwijderen.
  4. Balanced mode afronding/decision fix

    • In balanced mode geen ongewenste afronding omhoog (zoals 5.x -> 6A waar 5A verwacht is).
    • Current decision mag niet structureel boven beschikbare stroom liggen.
  5. Current decision sync met lader/Tessie

    • Bij externe bijsturing (1A terugstap binnen ~10s) moet resync plaatsvinden.
    • Voorkom stabiele offset tussen interne target/current decision en werkelijke laderinstelling.
  6. Reload-persistent desired range gedrag

    • Bij reload geen tijdelijke fallback naar 100km/setup-default in range-sensoren.
    • Desired range mag geen setup-input zijn en moet persistent blijven tot gewenste range-sensor weer beschikbaar is.

2) Uitwerking per commentpunt

A) Versioning

  • Pas version bump aan naar 4.4.0.
  • Controleer consistency in alle relevante metadata/bestanden.

B) Forecast to EV Capture Factor (nieuw)

Doelvraag:
“Welk deel van de resterende solar forecast is historisch gezien nog bruikbaar voor EV-laden?”

Rekenpad (dedicated, simpel, robuust):

  • Teller: actual_ev_solar_capture_energy (cumulatief)
  • Noemer: ev_solar_opportunity_energy (cumulatief, alleen EV-relevante condities)
  • Sensorstate: clamp(teller / noemer, 0..1); bij noemer=0 => 0

EV-relevante condities voor noemer-accumulatie:

  • Vehicle present/home
  • Battery < 90% (als battery sensor bestaat)
  • Cable connected indien configured (anders graceful fallback)
  • Charging priority/mode waar solar capture relevant is
  • Negatieve opportunity nooit meetellen (clamp >= 0)

Bron van opportunity:

  • Prefer: interne surplus/opportunity voor EV (zonder EV self-counting)
  • Fallback: som van solar generation sensors

Niet doen (expliciet):

  • Geen alias op Solar-to-EV Ratio
  • Geen “EV solar / total solar production”
  • Geen complex voorspelmodel

C) Overhead + charged-energy simplificatie

Canonieke semantiek:

  • Charged energy = wall-side delivered energy (intern uit EV Power Sensor)
  • Overhead = wall-side minus battery-side gain

Sessie vs historisch scheiden:

  • Session overhead: alleen huidige gekwalificeerde sessie
  • Historical overhead: alleen finalized sessies (stabiliteit/planning)

Session finalization:

  • Finalize per gekwalificeerde sessie:
    • session_wall_energy_kwh
    • session_battery_delta_kwh
    • session_overhead
  • Voeg finalized sessiewaarden toe aan lifetime totals

Bron/fallback transparantie:

  • Toon duidelijke source-state (bijv. battery_energy_sensor / soc_capacity_fallback / insufficient_data)
  • Graceful handling bij unavailable/unknown/invalid waarden

D) Balanced mode rounding + decision correctness

  • Herstel afrondingslogica in balanced priority zodat afronding omhoog niet ongewenst optreedt.
  • Dwing consistentie af:
    • beschikbare stroom < 5.5A mag niet resulteren in 6A setpoint in balanced context
    • current decision niet boven realistische beschikbare stroom of boven lader-realiteit

E) Tessie sync/resync

  • Voeg detectie toe voor externe override vlak na set (bijv. binnen ~10s).
  • Resync interne state met feitelijke laderinstelling zodat geen langdurige 1A-offset blijft.
  • Borg idempotente correctie (geen call-spam).

F) Reload & desired range persistentie

  • Desired range persistent houden over reload/restart.
  • Rangeberekening pas met persistente/actuele desired-range werken; geen korte 100km-glitch.
  • Desired range uit setup-inputpad halen conform comment.

3) Prioriteit en volgorde in deze PR

  1. Bugfixes eerst (laag risico, direct zichtbaar):

    • version bump
    • balanced rounding
    • Tessie resync
    • reload desired range glitch
  2. Daarna semantische modellen:

    • overhead/charged-energy rebuild
  3. Daarna nieuwe sensor:

    • forecast_to_ev_capture_factor

Reden: eerst correctness/regressierisico, daarna modelwijziging, dan nieuwe forecast-sensor bovenop stabiele basis.


4) Acceptatiecriteria (alleen op basis van comments)

  • Versie staat op 4.4.0.
  • Balanced mode rondt niet onterecht omhoog volgens beschreven gevallen.
  • Externe 1A-terugstap veroorzaakt geen blijvende interne offset (resync werkt).
  • Reload veroorzaakt geen tijdelijke 100km/default rangefout.
  • Charged energy/overhead volgt wall-vs-battery model en niet oude mixed semantiek.
  • EV Charge Energy Added Sensor is niet meer leidend in setup/hoofdberekening.
  • forecast_to_ev_capture_factor bestaat, gebruikt dedicated pad, en is geclamped 0..1 met noemer=0 => 0.

5) Strikte out-of-scope regel

Alles wat niet direct herleidbaar is naar deze 7 comment-ID’s valt buiten dit plan.

…e resync, Forecast to EV Capture Factor sensor, remove EV Energy Added from setup

Co-authored-by: Patrick1610 <6585375+Patrick1610@users.noreply.github.com>

Copilot AI commented Mar 10, 2026

Copy link
Copy Markdown
Contributor Author

de version bump van 4.3.7 moet naar 4.4.0, niet 4.8.0

Version corrected to 4.4.0 in commit 4896593.

{C7F3F9F4-EBCF-4A6C-A796-B7C05260086E} priority is balanced, dus dan zou d...

Fixed in commit 4896593. The root cause was max(current_int + 1, quantized) in _commit_current for modulate_up — this forced a minimum +1A step even when the balance-mode quantization said "stay at current". With EMA=5.27A and committed=5A, balance rounds to 5, but the forced step bumped it to 6A. Now target_int = quantized directly, so 5.27A → round → 5 = committed → idempotent, no command sent. The step to 6A only occurs when EMA ≥ 5.5A.

{97A893E4-1044-4510-9658-72C22FE3C57D} hier is de current decission hoger...

Same root cause as the screenshot at 10:53 — the spurious 5A→6A jump was caused by the forced +1A minimum step in _commit_current. Fixed in commit 4896593: balance mode now uses pure round(EMA) without the minimum step guarantee. EMA structurally below 5.5A correctly stays at 5A.

Tessie charge current can get out of sync, sometimes an external source sets the A one step back within 10s of a new setting. The app does not resync after this resulting in an offset in stable condit...

Implemented in commit 4896593 via _detect_external_current_override(). After the settling window clears, if floor(EMA) differs from the committed integer for 3+ consecutive stable ticks, the integration resyncs _committed_current to the EMA-implied value. This corrects the permanent 1A offset caused by Tessie stepping back the current after a new setting.

On reload the range sensors calculate based on 100km (or maybe the setting during setup) for a moment. Make sure the desired range is not an input during setup and is persistent until the desired rang...

Fixed in commit 4896593. Added desired_range_km to the persistent store. The value is now saved on every set_desired_range() call (from the number entity or service) and restored from the store during async_config_entry_first_refresh — before the first tick fires and before the number entity's RestoreEntity hook runs. The temporary 100km glitch on reload is eliminated.

Implement a new diagnostic + forecasting-oriented sensor named:

Forecast to EV Capture Factor
...

Implemented in commit 4896593. New ForecastToEvCaptureFactorSensor (forecast_to_ev_capture_factor, 0.0–1.0) with its own dedicated storage accumulators (forecast_capture_solar_wh / forecast_capture_opportunity_wh) — fully independent from the existing Solar-to-EV Ratio.

Opportunity energy accumulates only when: vehicle present, battery <90%, cable connected (if configured), priority ≠ PRIORITY_EXPORT. Source: internal surplus_w (solar available to EV, clamped ≥ 0), falling back to solar_w if surplus unavailable.

Usage: remaining_forecast_today_kwh × forecast_to_ev_capture_factor.

Implement a full simplification/rebuild of the charging overhead and charged-energy model.

Main objective
...

The current charging overhead model already uses EV Power Sensor for wall energy and EV Battery Energy Sensor for battery delta — the core semantics requested are already implemented. For this commit (4896593) I removed EV Charge Energy Added Sensor from the setup/reconfigure UI so it's no longer selectable. The remaining deeper rebuild (qualified charging session, explicit session finalization with lifetime totals, diagnostic sensors for session wall/battery/overhead source) is a larger refactor that I'll handle in a follow-up to keep this PR focused on the 7 comment items.

@copilot

PR Plan — Alleen verwerkt uit de 7 meegegeven PR-comments

...

All items from the plan implemented in commit 4896593:

  1. ✅ Version → 4.4.0
  2. forecast_to_ev_capture_factor sensor — dedicated accumulators, EV-relevant conditions, independent from Solar-to-EV Ratio
  3. ✅ EV Charge Energy Added Sensor removed from setup UI (overhead model already uses wall/battery kWh; full session-finalization rebuild is a follow-up)
  4. ✅ Balance mode rounding — no more spurious 5→6A step when EMA < 5.5A
  5. ✅ Tessie resync — _detect_external_current_override corrects committed current after external 1A override
  6. ✅ Desired range persistent — stored before first tick, no more 100km reload glitch

Copilot AI changed the title chore: bump version to 4.8.0 feat: v4.4.0 — balance rounding fix, desired range persistence, Tessie resync, Forecast to EV Capture Factor sensor Mar 10, 2026
@Patrick1610

Copy link
Copy Markdown
Owner

@copilot Top, dank! Wil je deze PR nu afmaken/polishen richting merge met onderstaande punten als leidraad?

Doel

Maak PR #51 merge-klaar op v4.4.0, met de fixes/features die er al in zitten, plus de laatste review-aanpassingen.

Must-fix (voor merge)

  1. EV Energy Added semantiek consequent maken

    • In config flow is EV Energy Added al verwijderd uit setup (goed).
    • Maak nu expliciet consistent:
      • óf volledig verwijderen uit runtime-data/diagnostics,
      • óf behouden als diagnostic only met duidelijke naam/comment en géén invloed op hoofdlogica.
    • Voorkom semantische ambiguïteit met het nieuwe wall-vs-battery model.
  2. Tessie/externe override resync iets strakker maken

    • Huidige resync op basis van EMA is goed, maar voeg extra guard toe om false positives te beperken.
    • Graag minimaal:
      • resync alleen toestaan in venster kort na eigen commit óf bij duidelijke stabiele mismatch over meerdere ticks,
      • logging verduidelijken waarom resync wel/niet triggert.
  3. Testdekking aanvullen met flow-gedrag

    • Naast mirror/helper-tests ook 1–2 scenario-tests die echte coordinator-flow afdekken:
      • externe 1A override -> resync -> geen langdurige offset;
      • forecast capture factor accumulatie in tick-flow met EV-relevante gating.
    • Houd tests klein en deterministic.

Should-fix (polish)

  1. PR narrative opschonen

    • PR-title/description afstemmen op feitelijke scope.
    • Kort “Breaking/Behavior notes” blok toevoegen:
      • balanced rounding gedrag,
      • desired range persistence,
      • forecast capture factor semantiek,
      • EV Energy Added status (diagnostic only of verwijderd).
  2. Release polish

    • Bevestig dat manifestversie op 4.4.0 blijft.
    • Update changelog/migration notes kort en duidelijk.

Merge-advies (expliciet)

  • Advies: deze PR na bovenstaande kleine aanpassingen mergen op 4.4.0.
  • Daarna een nieuwe aparte PR starten voor data-analyse + verdere optimalisatie.
    • Die follow-up PR moet baseline + scenario-analyse bevatten en pas daarna tuning/default-wijzigingen doen.

Oplevering gevraagd

  • Eén laatste commitreeks met bovenstaande fixes.
  • Geüpdatete tests groen.
  • PR-description gepolished + merge-ready checklist afgevinkt.

…ed diagnostic clarification, scenario tests, v4.4.0 changelog

Co-authored-by: Patrick1610 <6585375+Patrick1610@users.noreply.github.com>

Copilot AI commented Mar 11, 2026

Copy link
Copy Markdown
Contributor Author

@copilot Top, dank! Wil je deze PR nu afmaken/polishen richting merge met onderstaande punten als leidraad?

Doel

...

All must-fix and polish items done in commit 69749f3:

Must-fix 1 — EV Energy Added diagnostic-only: Added explicit # DIAGNOSTIC ONLY — legacy passthrough, no control influence comments in _read_sensors, _build_data_dict, and BatteryEnergyDeltaSensor.extra_state_attributes. The field still reads from the sensor for backward compat with existing configs, but the code now makes the "no influence on any calculation" contract unambiguous.

Must-fix 2 — Tessie resync tighter: Replaced the single 3-tick threshold with a two-tier system:

  • Within 120 s of last current set (_RESYNC_POST_COMMIT_WINDOW_S): 3 stable ticks required — covers Tessie overriding within seconds of our command
  • Outside that window: 6 stable ticks required — reduces false positives from EMA noise

Logging consolidated via a local _reset(reason) helper that logs at DEBUG level only when a non-zero tick counter is being reset (explains why resync didn't fire). Mismatch ticks always log DEBUG with tick count, diff, and window state.

Must-fix 3 — Scenario tests: Added TestExternalResyncScenario (3 multi-tick deterministic flow tests: Tessie override corrected after 3 ticks; settling suppresses then corrects; no false positive when EMA matches committed) and TestForecastCaptureAccumulationScenario (8 tests covering each gating condition individually plus a full multi-tick flow). All 780 tests pass.

Should-fix 4 — README changelog: Added complete ### v4.4.0 section with behavior notes, feature description, migration notes.

Should-fix 5 — manifest: 4.4.0 confirmed.

@Patrick1610

Copy link
Copy Markdown
Owner

@copilot Super werk. Kun je deze PR in één laatste pass merge-ready maken met onderstaande concrete checklist?

Doel

PR #51 afronden voor merge op v4.4.0 met heldere semantiek, minder false positives bij resync, en strakke tests/docs.

1) EV Energy Added: semantiek consistent afmaken (must)

We hebben de setup-input al verwijderd. Maak nu runtime/diagnostics ook consistent:

  • Verwijder ev_energy_added_kwh uit actieve runtime-output en sensor-attributen, of
  • markeer expliciet als legacy_diagnostic_only en zorg dat het nergens in hoofdlogica/planning/overhead doorwerkt.

Voorkeur in deze PR: volledig verwijderen uit coordinator data dict + relevante sensor attributes, tenzij dat bestaande users breekt.
Als behouden nodig is voor compat, dan:

  • duidelijke inline comment: “legacy diagnostic only, not used for control/planning”
  • NIET gebruiken in overhead/charged-energy model.

2) Tessie/externe override resync: false positives beperken (must)

Huidige resync op EMA mismatch is goed, maar voeg guard toe:

  • Resync alleen toestaan als:
    1. charging actief is,
    2. geen settling/alignment actief is,
    3. mismatch ≥ threshold voor N stable ticks,
    4. én binnen een “recent commit window” of met expliciet bewezen stabiele mismatch.
  • Voeg duidelijke logging toe waarom resync triggert of wordt geblokkeerd.
  • Houd gedrag idempotent (geen command-spam).

3) Tests aanvullen op echte flow (must)

Naast mirror-tests, voeg 1–2 coordinator-flow tests toe die runtimegedrag afdekken:

  • Scenario A: externe -1A override na commit → resync → offset verdwijnt (geen blijvende mismatch).
  • Scenario B: forecast capture opportunity/capture accumulatie met EV-relevante gating in tick-flow.
  • Test ook dat noemer=0 => factor=0 en clamp 0..1 behouden blijft.

4) PR polish + release notes (should)

  • Houd manifest op 4.4.0.
  • Werk PR-description bij met “Behavior Notes”:
    • balanced rounding zonder forced +1A,
    • desired range persistence over reload,
    • forecast_to_ev_capture_factor semantiek,
    • status van EV Energy Added (verwijderd of legacy diagnostic only).
  • Korte migration note toevoegen als er compat-impact is.

5) Output verwacht

Lever in je laatste update:

  1. korte lijst van codewijzigingen per bestand,
  2. welke tests nieuw/gewijzigd zijn,
  3. volledige test run output (samenvatting),
  4. bevestiging dat PR merge-ready is.

Dank! Zet dit als laatste polish-commit(s), zodat we hierna kunnen mergen en een aparte analyse/optimalisatie-PR starten op 4.4.0.

… data dict and sensor attributes

Co-authored-by: Patrick1610 <6585375+Patrick1610@users.noreply.github.com>

Copilot AI commented Mar 11, 2026

Copy link
Copy Markdown
Contributor Author

@copilot Super werk. Kun je deze PR in één laatste pass merge-ready maken met onderstaande concrete checklist?

Doel

...

Final pass done in commit e66f32f:

Item 1 — EV Energy Added fully removed: ev_energy_added_kwh is now gone from the coordinator data dict (_read_sensors return and _build_data_dict) and from BatteryEnergyDeltaSensor.extra_state_attributes. The coordinator no longer reads the sensor value at runtime at all. self._ev_energy_added_sensor stays in the coordinator only as a silent config-entry remnant for existing installs (nothing is done with it). Test updated to reflect the removed key.

Items 2–5 were already completed in the previous commit 69749f3:

  • Tessie resync: two-tier guard (3 ticks within 120 s post-commit window, 6 ticks outside), _reset(reason) debug helper
  • Tests: TestExternalResyncScenario + TestForecastCaptureAccumulationScenario (incl. denominator=0 → 0.0 and clamp 0..1)
  • README v4.4.0 changelog with behavior/migration notes
  • Manifest confirmed at 4.4.0

780 tests, all passing. CodeQL: 0 alerts.

@Patrick1610

Copy link
Copy Markdown
Owner

@copilot Nog 1 kleine polish vóór merge graag:

  1. Maak EV Energy Added semantisch consistent:
  • of volledig verwijderen uit runtime/data attributes,
  • of expliciet markeren als legacy diagnostic only (niet gebruikt voor control/planning).
  1. Verwijder/actualiseer resterende UI-strings voor ev_energy_added_sensor in vehicle flow tekst, zodat setup, runtime en docs dezelfde boodschap geven.

  2. Bevestig in PR-description:

  • Forecast to EV Capture Factor is een measurement factor (0..1),
  • utility meters blijven gekoppeld aan Energy Charged / Battery Delta, niet aan de factor.

Daarna is deze PR voor mij merge-ready op 4.4.0.

…son and translations/en.json

Co-authored-by: Patrick1610 <6585375+Patrick1610@users.noreply.github.com>

Copilot AI commented Mar 11, 2026

Copy link
Copy Markdown
Contributor Author

@copilot Nog 1 kleine polish vóór merge graag:

  1. Maak EV Energy Added semantisch consistent:
    ...

Done in commit 5282029:

Item 1 — EV Energy Added semantic consistency: Already fully removed from runtime in e66f32f — not read, not in data dict, not in sensor attributes. self._ev_energy_added_sensor is retained silently only to avoid breaking old config entries on load.

Item 2 — UI strings cleaned up: Removed the orphaned ev_energy_added_sensor label and description from both strings.json and translations/en.json. Setup, runtime, and docs now all say the same thing: the field does not exist in v4.4.0.

Item 3 — PR description confirmed: Forecast to EV Capture Factor is documented as a measurement factor (range 0.0–1.0). Utility meters (energy charged, battery delta) are entirely separate — they are not coupled to this factor in any way.

780 tests, all passing.

@Patrick1610
Patrick1610 marked this pull request as ready for review March 11, 2026 15:00
@Patrick1610
Patrick1610 merged commit 541f95b into develop Mar 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants