Skip to content

feat(solax): cache plant and device info in storage and refresh it by data age - #4366

Merged
springfall2008 merged 3 commits into
mainfrom
fix/solax-cache-static-info
Jul 29, 2026
Merged

feat(solax): cache plant and device info in storage and refresh it by data age#4366
springfall2008 merged 3 commits into
mainfrom
fix/solax-cache-static-info

Conversation

@springfall2008

Copy link
Copy Markdown
Owner

Problem

Every restart re-read the full plant list and every device from the SolaX cloud before Predbat could do anything, even though that information describes the hardware and barely changes. Other integrations already avoid this — gecloud.py restores its settings from storage on startup.

Separately, realtime data was published to Home Assistant whether or not the read succeeded. realtime_device_data is only written on a successful read, so a failed poll republished the previous values, and before any successful read the plant totals were published as 0.0 from the .get(..., 0.0) defaults. Those totals feed import_today / export_today / load_today, so publishing zeros or stale values corrupts what Predbat consumes.

Change

Plant and device info are cached in storage under solax/plant_info and solax/device_info, and restored on startup. Two entries rather than one, because a single file's timestamp would be refreshed by every 30 minute device save, and the plant info age rule would then never fire.

The refresh is driven by the age of the data, not the time since startup. Previously seconds % (30 * 60) == 0 meant a restart began a fresh 30 minute interval regardless of how old the data actually was. Now:

Entry Contents Re-read once older than
plant_info plant list 8 hours
device_info device info and the plant to inverter/battery maps 30 minutes

Restoring from the cache carries the age over, so a restart neither re-reads data that is still current nor waits a full interval to refresh data that was already nearly due — 25 minute old device info refreshes 5 minutes later, not 30. Entries are written with a 24 hour expiry so an abandoned cache is discarded by the storage layer.

Realtime data is not published when the read failed. Failures are recorded per plant and per device and cleared on the next success. Tracking failures rather than successes matters: it distinguishes "never polled" from "poll failed", and a missing update simply leaves the entity at its last value in HA, which is the desired outcome. Plant totals, battery sensors and per-device sensors are gated independently, so one failing device does not suppress the rest. Static sensors — capacity, PV capacity, max power — are always published.

Realtime data is deliberately still not cached to storage, as it is polled every 60 seconds.

Behaviour notes

  • A plant info refresh that fails now keeps the previously known plants and logs a warning rather than aborting the run. Returning False on an 8 hourly refresh blip would take out an otherwise healthy cycle. It remains fatal when nothing has ever been read.
  • plant_list is now recomputed whenever plant info is successfully refreshed, not only on the first run, so a plant added to the account is picked up within 8 hours.
  • With no storage component available the behaviour is unchanged and everything is polled.

Testing

./run_all --test solax and ./run_pre_commit both pass.

  • test_static_info_cache — fresh cache restored with no polling, each entry ageing out independently, the age carrying across a restart rather than restarting the interval, missing cache, no storage configured, a failed refresh keeping the previous data, and the 24 hour expiry.
  • test_realtime_publish_gating — successful reads publish, a failed plant read holds back the totals while static sensors still publish, a failed battery read holds back the battery sensors, per-device publishing skips only the failed device, and failures are recorded on a bad read and cleared on a good one.
  • Two existing run loop tests needed seeding with plant_info_updated / device_info_updated, since "subsequent run" no longer implies "never polls plant info".

🤖 Generated with Claude Code

… data age

Every restart re-read the full plant list and every device from the cloud before
Predbat could do anything, even though that information describes the hardware and
barely changes. Both are now kept in storage, as gecloud does with its settings,
and restored on startup when the data is still current.

The refresh is driven by the age of the data rather than the time since startup:
plant info is re-read once it is more than 8 hours old, device info once it is more
than 30 minutes old. Restoring from the cache carries the age over, so a restart
neither re-reads data that is still good nor waits a full interval to refresh data
that was already nearly due. Entries are written with a 24 hour expiry so an
abandoned cache is discarded by the storage layer rather than lingering.

A plant info refresh that fails now keeps the previously known plants instead of
aborting the run, which only remains fatal when nothing has ever been read.

Realtime data is deliberately not cached, it is polled every 60 seconds, but it is
no longer published when the read failed. Previously a failed poll republished the
last known values, and before any successful read the plant totals were published
as zero, which corrupts the energy totals Predbat consumes. Plant totals, battery
sensors and per-device sensors are each held back independently, so one failing
device does not suppress the rest, and static sensors such as capacity are always
published.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 29, 2026 12:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves the SolaX cloud integration startup/runtime behaviour by persisting largely-static “plant” and “device” metadata in the Storage component and by preventing Home Assistant sensor updates from republishing stale/zero realtime data when polls fail.

Changes:

  • Cache and restore SolaX plant_info and device_info via Storage, refreshing based on cached data age (8h / 30m) and writing with a 24h expiry.
  • Track per-plant and per-device realtime poll failures and gate sensor publishing so failed reads do not republish stale/zero totals.
  • Extend the SolaX test suite to cover static-info caching/ageing and realtime publish gating behaviour.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
apps/predbat/solax.py Implements storage-backed caching/age-based refresh of static info and failure-gated publishing of realtime sensors.
apps/predbat/tests/test_solax.py Adds/updates tests validating cache restore/refresh semantics and publish gating on failed realtime reads.

Comment thread apps/predbat/solax.py Outdated
springfall2008 and others added 2 commits July 29, 2026 15:06
…eded

query_device_info returns None on an API failure, but the run loop advanced
device_info_updated and wrote the cache regardless. A transient failure therefore
marked the data fresh for 30 minutes, and on a cold start with no cache it locked
in an empty device list for that long, leaving the plant with no inverters or
batteries to control.

The read time is now only advanced, and the cache only written, when every
query_device_info call succeeded and there was at least one plant to read.

Gating on success alone would have replaced one problem with another, since run is
called every few seconds and a failing read would then retry on every cycle. Both
paths now also record when a read was last attempted and hold off for five minutes
before trying again. That applies to plant info too, which had the same retry storm
because a failed refresh left plant_info_updated unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Battery and PV capacity come from the plant record, so adding hardware changes both
the device list and the plant info. Device info is re-read every 30 minutes but
plant info only every 8 hours, which left the capacities stale for hours after a
battery was added.

A device list that differs from the one held before the read now clears the plant
info read and attempt times, so the plant record is re-read on the next cycle rather
than waiting out its maximum age or the retry interval.

The comparison is skipped when there was no previous device list, so the first read
after a cold start does not trigger a pointless re-read of plant info that was just
fetched. It detects devices appearing rather than disappearing, since device_info is
only ever added to, which is the case that matters for capacity.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@springfall2008
springfall2008 merged commit 61f98d6 into main Jul 29, 2026
2 checks passed
@springfall2008
springfall2008 deleted the fix/solax-cache-static-info branch July 29, 2026 13:17
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