Skip to content

feat(gecloud): use the customer account timezone for the start/end time registers - #4460

Merged
springfall2008 merged 3 commits into
mainfrom
feat/gecloud-account-timezone
Aug 8, 2026
Merged

feat(gecloud): use the customer account timezone for the start/end time registers#4460
springfall2008 merged 3 commits into
mainfrom
feat/gecloud-account-timezone

Conversation

@springfall2008

Copy link
Copy Markdown
Owner

Problem

The GivEnergy charge/export slot start and end times are held in the timezone set on the customer's GivEnergy account, which is not necessarily the timezone Predbat is running in. Predbat read and wrote those registers as if they were already in its own timezone, so for anyone whose two timezones differ the slots landed at the wrong time of day.

Changes

Fetch the account details — new /v1/account call (async_get_account), recording the timezone from standard_timezone (IANA, e.g. Europe/London), falling back to timezone. Unknown or missing names are logged and ignored.

Translate the time registers at the API boundary, so the rest of Predbat is untouched:

  • publish_registers() converts date_format:H:i registers from account time into Predbat time before publishing the select entity
  • select_event() converts back into account time before writing
  • get_timezone_offset_minutes() is evaluated at call time, so DST is handled on both sides
  • shift_time_string() wraps correctly at midnight

When the account timezone is unknown the offset is 0 and nothing shifts, so existing behaviour is preserved.

Cache the account in storage — restored on startup and only re-fetched once a day (ACCOUNT_MAX_AGE_MINUTES). A stale cache is still loaded as a fallback, so if the API call then fails the timezone conversion keeps working with the last known values rather than silently reverting to no conversion.

Publish two sensors:

Entity State data attribute
sensor.predbat_gecloud_account account name everything else from the response
sensor.predbat_gecloud_timezone IANA timezone name timezone, standard_timezone, predbat_timezone, offset_minutes

offset_minutes makes it visible at a glance whether any shift is being applied.

enable_default_options() is deliberately untouched — the 00:00 it writes to unused slots is a disable sentinel (start == end), so shifting it would serve no purpose.

Version bumped to v8.47.7.

User-visible change

For anyone whose GivEnergy account timezone differs from their Predbat timezone, the HA select entities will now show times shifted relative to the GivEnergy portal. That is the point of the change, but it is a visible difference when cross-checking the two. Documented in docs/inverter-setup.md.

Testing

./run_all --test ge_cloud   → RESULTS: 79 passed, 0 failed out of 79 tests
./run_all --quick           → All tests passed (5 slow tests skipped)
pre-commit run --all-files  → exit 0

Ten new sub-tests cover the account fetch and its failure path, timezone parsing and fallbacks, the time-string shift (including midnight wrap and malformed input), the round-trip conversion through publish/select with and without a known timezone, both sensors, and the four storage-cache paths (save, fresh restore with no API call, stale re-fetch, no cache).

🤖 Generated with Claude Code

…me registers

The GivEnergy charge/export slot start and end times are held in the timezone
set on the customer's GivEnergy account, which is not necessarily the timezone
Predbat is running in. Predbat was reading and writing them as if they were
already in its own timezone, so the slots landed at the wrong time of day for
anyone whose two timezones differ.

Fetch the account details from /v1/account and translate the time registers at
the API boundary: values are published to the select entities in the Predbat
timezone and converted back to the account timezone on write, leaving the rest
of Predbat unchanged. When the account timezone is unknown no shift is applied,
so existing behaviour is preserved.

The account details are cached in storage and only re-fetched once a day, and a
stale cache is kept as a fallback so a failed fetch still leaves the timezone
usable. Also publish two sensors: predbat_gecloud_account (account name, with
the remaining values in a data attribute) and predbat_gecloud_timezone (the IANA
timezone name, with the raw values and the live offset from the Predbat timezone
in a data attribute).

Bump version to v8.47.7.

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

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

Adjusts the GivEnergy GE Cloud integration to interpret and present charge/export slot time registers using the customer account timezone, while keeping Predbat’s internal logic operating in the configured Predbat timezone.

Changes:

  • Added GE Cloud /v1/account fetch with timezone parsing and daily caching in storage.
  • Translated date_format:H:i register values at the GE Cloud API boundary when publishing selects and when writing back register values.
  • Published new GE Cloud account/timezone sensors and updated docs; bumped version to v8.47.7.

Reviewed changes

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

File Description
docs/inverter-setup.md Documents that GE Cloud slot times are stored in the account timezone and may display shifted in Predbat.
apps/predbat/tests/test_ge_cloud.py Adds coverage for account fetch/caching, timezone parsing, shifting logic, sensors, and round-trip register conversions.
apps/predbat/predbat.py Version bump to v8.47.7.
apps/predbat/gecloud.py Implements account timezone fetch/cache, time shifting helpers, boundary conversions, and new sensors.
Suppressed comments (2)

apps/predbat/gecloud.py:503

  • publish_account() sets the timezone sensor state from the raw account fields even if the timezone name was unknown/ignored (and therefore no conversion is applied). This can mislead users into thinking conversion is active when offset_minutes is 0; prefer publishing the resolved timezone (self.account_timezone_name) and fall back to "unknown" when not resolved.
        timezone_name = self.account_timezone_name or account.get("standard_timezone", None) or account.get("timezone", None)
        timezone_data = {
            "timezone": account.get("timezone", None),
            "standard_timezone": account.get("standard_timezone", None),
            "predbat_timezone": str(self.local_tz) if self.local_tz else None,

apps/predbat/gecloud.py:1687

  • The async_get_account() docstring embeds a full example response including email/address/telephone-like fields. Even as an example, it’s better to avoid including personal-data-shaped content in code comments; a minimal subset (id/name/timezone fields) conveys the intent without that risk.
        {'id': 2, 'name': 'francesca.holmes.285', 'first_name': 'Maisie', 'surname': 'Walker', 'role': 'VIEWER',
         'email': 'joshua94@martin.com', 'address': '18 Hunt Landing', 'postcode': 'CT6 9AR', 'country': 'UNITED_KINGDOM',
         'telephone_number': '+44(0)7559 260236', 'timezone': 'GMT', 'standard_timezone': 'Europe/London',
         'company': None, 'flags': []}

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread apps/predbat/gecloud.py
Comment thread apps/predbat/gecloud.py Outdated
springfall2008 and others added 2 commits August 8, 2026 10:33
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
update_account() advanced account_stamp before the fetch, so if there was no
cached account and the first fetch failed, nothing retried for 24 hours and the
timezone conversion stayed disabled for that whole period.

Only mark the details fresh once a fetch actually returns something. A failure
now retries after ACCOUNT_RETRY_MINUTES, tracked separately from the freshness
stamp so a sustained API outage does not turn the 60 second run() tick into a
poll loop against the account endpoint.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@springfall2008
springfall2008 merged commit 3abd0fe into main Aug 8, 2026
2 checks passed
@springfall2008
springfall2008 deleted the feat/gecloud-account-timezone branch August 8, 2026 09:40
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