Added
- WebSocket mode selector (
ws_mode): replaced the booleanws_all_sessionstoggle with a 3-state dropdown — Auto (WS only during paced forced discharge), All smart sessions (any smart session or force op), Always connected (WS preferred at all times with watchdog recovery). Existing configurations migrate automatically. - Data freshness sensor:
sensor.foxess_data_freshnessexposes the current data source (ws,api, ormodbus) as its state, withlast_updateandage_secondsattributes for staleness detection. - Data staleness indicator on Lovelace cards: both cards compute data age client-side; badge turns red with elapsed time (e.g. "API · 2m") when data exceeds 30 seconds old.
- Structured session logging: session context (ID, type, SoC, power) enriched via
logging.Filter; debug log sensor exposes structured data for E2E tests and power users. - Target power display: Lovelace card shows current vs target discharge rate when they differ during feed-in pacing.
- Entity-mode E2E tests: input helpers simulate modbus entities;
connection_modefixture parametrizes cloud vs entity modes with function-scoped containers for full isolation. - Reconfigure flow: add or update web portal credentials without re-creating the config entry. Accepts both raw password and pre-computed MD5 hash.
- Structural tests: AST-based verification of synchronous cancel functions (C-016) and brand import boundary (C-021).
Changed
- SoC display precision matches confidence: Lovelace card shows integer SoC until the first confirmed integer change (e.g. 93→92), then switches to 2 decimal places. Before the first change, interpolation is just an estimate; after, the real SoC is known to be near X.5, making interpolation meaningful.
- Interpolated SoC stored at full float precision: rounding applied only for change detection (2dp gate to prevent entity update storms), not storage.
- Session construction via factory functions:
create_charge_session()andcreate_discharge_session()ensure consistent field defaults and reduce duplication across callers. - Min SoC floor lowered to 0%:
min_socandmin_soc_on_gridnow accept 0, removing the previous 5% floor. - Unified cancel functions:
_cancel_smart_chargeand_cancel_smart_dischargereplaced with delegates to brand-agnosticcancel_smart_session, ensuring the_on_session_cancelhook fires from all cancel paths. - Simulator fidelity: charge taper above 90% SoC, discharge taper below 15% SoC, per-app state isolation, stale-stream behaviour matching FoxESS cloud.
- E2E config uses production defaults: tests needing non-default options set them explicitly via the options flow, matching real user setup.
- GitHub Actions updated: checkout v4→v6, setup-python v5→v6, upload-artifact v4→v7, download-artifact v4→v8.
Fixed
- WS linger race captured stale forced-discharge data (D-009):
_on_session_cancelnow returns the WS stop coroutine; callers await it after override removal completes, so the linger captures post-session self-use data. Also fixed theclear_overridesservice path which used fire-and-forget. - Entity-mode service domain detection:
apply_mode()used hardcoded"select"and"number"domains, breakinginput_select/input_numberentities from foxess_modbus. Added_entity_service_domain()helper to derive the correct domain from the entity ID prefix. - Charge fdSoc regression: listener must pass
fd_soc=100to prevent FoxESS API validation failure (C-008). - Smart discharge starting before scheduled window: deferred discharge listener omitted the
start=parameter, bypassing the floor clamp. The inverter receivedfdPwr=0but ignored it and discharged at full power. - Force operations not cancelling opposite smart session: both force operations now cancel both session types, preventing leftover listeners from fighting the schedule.
- WS not connecting after deferred discharge start: timer now fires the WS-aware wrapper, so WebSocket connects as soon as forced discharge begins.
- WS reconnect during smart charge: charge listener wrapper wasn't triggering
_maybe_start_realtime_ws. - Session sensors delayed by ~30s: now subscribe via
coordinator.async_add_listenerfor instant state propagation. - Stale work mode badge after failed cleanup: override removal retries on each successful REST poll; cancel paths clear
_work_modeimmediately. - Smart sessions survive transient API errors: errors retried on next timer tick; only 3 consecutive failures trigger abort. Previously any transient cloud outage killed a multi-hour session.
- SoC interpolation overshooting entity value: clamp tightened to
[tick − 0.5, tick + 0.44]so the rounded display always matches the entity. - REST poll starvation from SoC extrapolation: now updates entity data directly without resetting the poll timer.
- Feed-in pacing stuck at initial power: switches to self-use when target is below
min_power_changethreshold, enabling ramp-up on the next tick. - Feed-in energy inflated at session start: baseline deferred to the listener's first tick when fresh data is available.
- Schedule horizon not set on immediate discharge start: computed inline before state dict creation.
- WS data_source badge stuck during stale stream: coordinator notified immediately when reconnecting, so badge shows "API" until fresh WS data resumes.
- WS stream-stolen recovery: tracks last useful data timestamp; reconnects after 30s of only stale frames. Token invalidated on handshake error, forcing fresh login.
- SoC interpolation stuck between ticks: timestamp set after integration, made unconditional.
- SoC clamp rounding: upper bound changed to 0.94 to prevent displayed value exceeding authoritative tick.
- Progress bar start SoC wrong after deferral: updated to actual SoC when session begins.