Skip to content

fix(gecloud): report API access-denied instead of false inverter clock skew#4001

Merged
springfall2008 merged 1 commit into
mainfrom
fix/gecloud-premium-auth-denied
Jun 4, 2026
Merged

fix(gecloud): report API access-denied instead of false inverter clock skew#4001
springfall2008 merged 1 commit into
mainfrom
fix/gecloud-premium-auth-denied

Conversation

@mgazza
Copy link
Copy Markdown
Collaborator

@mgazza mgazza commented Jun 3, 2026

Problem

Since GivEnergy moved cloud API access behind a paid Premium tier (May 2026), accounts without an active subscription now get HTTP 401/403 from the cloud API. PredBat misdiagnoses this as an "inverter clock skew" error and enters an auto-restart loop, telling users to fix their inverter clock / HA sync / timezone — none of which is the real cause.

Root cause (traced)

  1. gecloud.py async_get_inverter_data returned {} for a 401/403 — indistinguishable from a successful empty response. So async_get_inverter_status kept serving it and publish_status no-op'd, leaving the GE cloud time sensor (sensor.{prefix}_gecloud_{device}_time) frozen at its last value.
  2. As wall-clock time advanced, the frozen timestamp drifted past the 30-minute threshold in Inverter.__init__, which called record_status(... "minutes skewed", had_errors=True) and auto_restart() — repeatedly.

Fix

  • gecloud: track auth failure (api_auth_failed); split 401/403 (auth) from 404/422 (client_error); clear the flag on success.
  • gecloud: when auth has failed, surface a correct status — "GivEnergy cloud API access denied — a GivEnergy Premium subscription is now required for API access" — and mark the time sensor unavailable instead of leaving it stale.
  • inverter: treat an unavailable/unknown/empty time reading as "no reading" → skip skew detection, no auto-restart. A genuine clock skew is still detected.

Tests (TDD)

New, all passing (full quick suite green; ruff/black/cspell pass):

  • ge_cloud: api_auth_sets_flag (403 sets the flag), api_success_clears_auth_flag, publish_status_auth_unavailable.
  • inverter: inverter_time_handling — an unavailable inverter time no longer triggers skew or auto-restart, while a real 2-hour skew still is detected.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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 fixes a misdiagnosis in the GivEnergy cloud integration where HTTP 401/403 (now commonly returned for non-Premium accounts) was treated as missing data, leaving the GE cloud “time” sensor stale and triggering false inverter clock-skew detection and auto-restart loops.

Changes:

  • Track and expose GE cloud API auth failures (api_auth_failed), mark the GE cloud time sensor as unavailable on access-denied to avoid “frozen timestamp” skew.
  • Update inverter time parsing to treat unavailable/unknown/empty readings as “no reading” and skip clock-skew detection.
  • Add tests covering the new GE cloud auth behavior and inverter time handling.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
apps/predbat/gecloud.py Track auth failures, publish unavailable time sensor, and surface a clearer status for access-denied scenarios.
apps/predbat/inverter.py Treat unavailable/unknown inverter time readings as absent so skew detection and auto-restart are skipped.
apps/predbat/tests/test_ge_cloud.py Add tests validating auth flag behavior and that auth failure marks the time sensor unavailable.
apps/predbat/tests/test_inverter.py Add test ensuring unavailable time doesn’t trigger skew/restart while real skew is still detected.

Comment thread apps/predbat/gecloud.py Outdated
Comment thread apps/predbat/gecloud.py
…k skew

GivEnergy moved cloud API access behind a paid Premium tier (May 2026).
Accounts without an active subscription now get HTTP 401/403, but PredBat
misdiagnosed this as an "inverter clock skew" error and entered an
auto-restart loop:

- A 401/403 returned {} (indistinguishable from a successful empty
  response), so the GE cloud time sensor was left holding a frozen
  timestamp. As wall-clock advanced, the frozen time drifted past the
  30-minute threshold, so inverter.py reported clock skew (had_errors) and
  called auto_restart() — wrong cause, wrong advice, restart loop.

Changes:
- gecloud: track auth failure in api_auth_failed. The flag is set ONLY for
  401/403 and cleared for every other outcome (success, 404/422, 429, 5xx,
  connection error) so a transient failure after an auth failure is not
  reported as an ongoing access-denied condition.
- gecloud: on auth failure, mark the time sensor unavailable (so it is not
  left stale) and surface a correct status — "GivEnergy cloud API access
  denied — a GivEnergy Premium subscription is now required". The status is
  emitted inside the 120s poll guard, scoped to inverter (not EVC) auth
  failures, and reported only once per episode (on transition) to avoid
  inflating the HA error_count.
- inverter: treat an unavailable/unknown/empty time reading as "no reading"
  (skip skew detection, no auto-restart); a genuine clock skew is still
  detected.

Tests (TDD): 403 sets the flag and a non-401/403 response clears it;
success clears it; auth failure marks the time sensor unavailable; the
access-denied status is scoped to the inverter poll cycle and reported once
per episode; unavailable inverter time no longer triggers skew/auto-restart
while a real 2-hour skew still is.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mgazza mgazza force-pushed the fix/gecloud-premium-auth-denied branch from 91aa1ba to ceb9fd6 Compare June 4, 2026 09:03
@mgazza
Copy link
Copy Markdown
Collaborator Author

mgazza commented Jun 4, 2026

Thanks @copilot — both points addressed (history squashed into a single commit ceb9fd68):

  1. error_count inflation / repeated status: the access-denied record_status(had_errors=True) is now emitted only once per episode (on transition into the denied state, reset on recovery), and only inside the 120s poll guard rather than on every 60s tick. New test auth_status_transition_only asserts a persistent denial reports once and a new episode after recovery reports again.

  2. api_auth_failed getting stuck True: the flag is now set only for 401/403 and cleared for every other outcome (success, 404/422, 429, 5xx, connection error), via self.api_auth_failed = status in [401, 403] plus a clear on the connection-error path. New test non_auth_clears_auth_flag covers 404/429/500 clearing a previously-set flag.

Also scoped the status to inverter (not EVC) auth failures so an EVC-only 403 can't raise a false "cannot read inverter data". Full quick suite green; ruff/black/cspell pass.

@mgazza mgazza requested a review from springfall2008 June 4, 2026 10:59
@springfall2008 springfall2008 merged commit 3541576 into main Jun 4, 2026
1 check passed
@springfall2008 springfall2008 deleted the fix/gecloud-premium-auth-denied branch June 4, 2026 18:46
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.

3 participants