Skip to content

Improve local API reliability, telemetry, and control stability#18

Open
uid0c0der wants to merge 39 commits into
MarstekEnergy:mainfrom
uid0c0der:main
Open

Improve local API reliability, telemetry, and control stability#18
uid0c0der wants to merge 39 commits into
MarstekEnergy:mainfrom
uid0c0der:main

Conversation

@uid0c0der

@uid0c0der uid0c0der commented Apr 16, 2026

Copy link
Copy Markdown

Summary

  • improve coordinator resilience against transient default/zero snapshots by retaining last valid values instead of publishing temporary 0/unknown spikes
  • carry forward intermittently missing ES.GetStatus/ES.GetMode fields (energy counters, CT power fields, pv_power) to avoid entity flicker in Home Assistant
  • harden PV channel normalization with firmware-quirk handling; fix persistent PV1 10x outlier behavior on Venus D devices
  • keep device metadata current by refreshing firmware/device info during setup (supports version/ver payload variants)
  • use stable device naming (without firmware/IP in the device name) to avoid brittle identifiers after updates
  • add derived Battery Stored Energy sensor (kWh) from bat_cap * bat_soc

Test plan

  • verify raw UDP payloads from PV.GetStatus / ES.GetStatus / ES.GetMode on device 10.1.1.26
  • confirm PV1 correction from ~333W to ~33.3W in HA sensor state
  • confirm transient unknown/0 flicker no longer appears for energy and CT sensors during intermittent response drops
  • confirm Battery Stored Energy value matches expected formula from API fields (bat_cap and bat_soc)
  • verify device metadata refresh picks latest firmware from live payloads
  • verify write entities still behave as expected (mode select + passive power)

Tested on Venus D (app reports firmware v147).

bastian added 10 commits April 16, 2026 20:19
Poll ES.GetStatus and ES.GetMode energy fields, expose them as Home Assistant total-increasing kWh sensors, and normalize PV power when payload units are inconsistent.

Made-with: Cursor
Expose both summed PV input power across PV1-PV4 and raw ES.GetStatus pv_power as dedicated sensors, including coordinator mapping for pv_power.

Made-with: Cursor
Expose ES.SetMode controls as Home Assistant select and number entities so users can switch operation mode and set passive power directly from the UI.

Made-with: Cursor
Serialize mode/power apply tasks per entity, keep rollback path intact on final retry failure, and send UPS mode in canonical uppercase to improve device compatibility.

Made-with: Cursor
Drop temporary readout/sniffer utilities from version control so upstream contribution stays focused on integration features.

Made-with: Cursor
Validate ES.SetMode set_result responses, confirm mode transitions via ES.GetMode, and keep optimistic UI state consistent by rolling back when writes are not applied.

Made-with: Cursor
Normalize mode string variants and retain the last confirmed mode so the select does not go empty when the device briefly returns unknown/empty mode states.

Made-with: Cursor
@uid0c0der uid0c0der changed the title Improve local API reliability, PV/Energy telemetry, and controls Improve local API reliability, telemetry, and control stability Apr 16, 2026
@uid0c0der

Copy link
Copy Markdown
Author

Tested locally on a Venus D device; the Marstek app reports firmware v147.

@uid0c0der

Copy link
Copy Markdown
Author

Update: final fixes are now included and verified locally.

  • PV1 10x outlier handling is active and confirmed against raw payload behavior
  • transient unknown/0 flicker is mitigated by retaining last valid snapshot values for intermittent missing fields
  • validated on Venus D (app reports firmware v147)

bastian and others added 12 commits April 17, 2026 08:54
Use tiered polling with safer defaults, configurable options, and mark entities unavailable after repeated poll failures instead of holding stale values indefinitely.

Co-authored-by: Cursor <cursoragent@cursor.com>
Use per-category staleness for unknown values, unreachable-only unavailable after long silence, partial UDP failure recovery, and signed grid power from ongrid_power.

Co-authored-by: Cursor <cursoragent@cursor.com>
Poll ES.GetStatus on every fast cycle for ongrid_power and derive non-negative export from the jaapp sign convention, with GetMode fallback and glitch smoothing.

Co-authored-by: Cursor <cursoragent@cursor.com>
Channel sums from PV.GetStatus often over-report; align with jaapp and use es.pv_power as the primary total solar power value.

Co-authored-by: Cursor <cursoragent@cursor.com>
Compare PV1 against active PV2–PV4 readings and apply deciwatt correction
conditionally so a future firmware fix is not double-scaled.

Co-authored-by: Cursor <cursoragent@cursor.com>
…aps.

Derive Selling/Charging/Idle from bat_power and ES.GetStatus grid export
instead of ES.GetMode ongrid alone, and keep PV category fresh when cached
channel data is still valid after a missed PV.GetStatus poll.

Co-authored-by: Cursor <cursoragent@cursor.com>
Treat positive ongrid_power from ES.GetStatus as export on Venus A/D,
hold the last ongrid reading across brief 0 W UDP glitches, and centralize
export calculation for grid power and battery status.

Co-authored-by: Cursor <cursoragent@cursor.com>
Defer the first poll by 45s (configurable), skip redundant GetDevice/discovery
and connection test on reload, delay scanner's initial broadcast, remove the
misleading Passive Power 100 W default, and log ES.SetMode only on real writes.

Co-authored-by: Cursor <cursoragent@cursor.com>
ES.GetStatus pv_power is often zero on MPPT devices; only use it when
positive and otherwise sum corrected PV1–PV4 from PV.GetStatus.

Co-authored-by: Cursor <cursoragent@cursor.com>
bastian and others added 2 commits June 18, 2026 22:02
Prefer PV channel sum including retained snapshots; only report 0 W after a
fresh PV.GetStatus poll, never from ES aggregate zero alone.

Co-authored-by: Cursor <cursoragent@cursor.com>
Total PV now sums PV1–4 because GetStatus swears 0W while the app still
shows 14W at dusk — same firmware that panics when HA dares to say hello.

Co-authored-by: Cursor <cursoragent@cursor.com>
bastian and others added 10 commits June 19, 2026 07:57
Drop indefinite sensor hold and limit coordinator ongrid glitch preserve to
a single poll cycle so feed-in correctly returns to 0 W when export stops.

Co-authored-by: Cursor <cursoragent@cursor.com>
Suspicious-zero rollback kept the full previous frame including export
power; now accept zero ongrid/PV/CT readings while still protecting SOC.

Co-authored-by: Cursor <cursoragent@cursor.com>
Scale PV1 only against reliable sibling MPPT power readings, fall back to ES.GetMode ongrid when GetStatus reports zero export, and add maintainer docs so firmware glitches are not reintroduced.
Keep README and Open API quirks documentation in English so contributors share one reference language.
- Add detailed debug logging for every scaling decision/skip in _scale_pv1_power_if_needed
- Relax ratio check to 3.0-30.0 when sibling baseline < 80 W (common when PV2-PV4 drop near zero)
- Update quirks documentation to mention symmetric low-light limitation

Addresses cases where PV1 remained incorrectly scaled due to ratio not matching at very low power.
…or set_passive_mode and manual schedules (modeled after jaapp)

- Replace fragile hard-coded power=0 in select Manual (caused idle)
- Add button entities for quick mode switching
- Add services: set_passive_mode, set_manual_schedule, set_manual_schedules, clear_manual_schedules
- Update select to use neutral Manual config and safe Passive default
- Add Platform.BUTTON and service registration
- Hoist MarstekRuntimeData / MarstekConfigEntry type alias early in __init__.py
- Move coordinator/services imports after the alias is published
- Switch platform + services files to if TYPE_CHECKING: import of the alias
  (prevents 'cannot import name ... from partially initialized module' when
   services/button/select etc. are pulled in during package init)

This was triggered by the recent addition of button/services mode controls.
- Extend _build_mode_button_config to handle Passive and UPS (was incorrectly falling back to Auto for Ups)
- Select now pushes commanded mode into coordinator.data on success (consistent with buttons + services)
- Add 8-second protection on _last_confirmed_option + time tracking:
  recent user selections stick in the select UI even if a concurrent poll or device lag temporarily reports a different value
- Clean up _build_mode_command and failure paths
- Keeps last stable value during unknowns (as before)

Attack on the 'always jumps back to Auto' issue. Auto/AI should stick reliably; Manual/Passive still benefit from services for non-neutral configs.
- Refactor async_setup_entry: avoid blocking sleeps and long first refresh.
  Use fast UDP probe for immediate ConfigEntryNotReady (delay=0) and schedule
  the full spaced poll via async_request_refresh() (or after startup_delay).
  This prevents asyncio.CancelledError from surfacing as 'setup cancelled'.
- Slow discovery scanner to 300s (less UDP bursts after reload).
- Preserve last-known device_mode and ct_state across transient ES data gaps.
- Accept non-numeric ct_state values from ES.GetMode.
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.

1 participant