Skip to content

Octopus: Support dual night rate tariffs with hard-wired times#3900

Merged
springfall2008 merged 4 commits intomainfrom
fix/octopus_dual_rate
May 10, 2026
Merged

Octopus: Support dual night rate tariffs with hard-wired times#3900
springfall2008 merged 4 commits intomainfrom
fix/octopus_dual_rate

Conversation

@springfall2008
Copy link
Copy Markdown
Owner

No description provided.

Copilot AI review requested due to automatic review settings May 10, 2026 13:21
@springfall2008 springfall2008 changed the title Support dual night rate tariffs with hard-wired times for now Octopus: Support dual night rate tariffs with hard-wired times May 10, 2026
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 updates the Octopus tariff-fetching logic to support dual-register (day/night) electricity tariffs by detecting endpoint types via product metadata and generating hard-wired night-rate windows (IOG TOU / GO / Economy 7), alongside adding a dedicated unit test suite for the day/night window selection.

Changes:

  • Add product-info lookup + in-memory caching to detect whether a tariff exposes standard_unit_rates vs day_unit_rates/night_unit_rates, and fetch accordingly.
  • Replace single hard-wired night window constants with a set of tariff-family window definitions (IOG/GO/Eco7) and update day/night schedule generation.
  • Add/adjust unit tests and mocks to accommodate the new json_only plumbing and validate window selection.

Reviewed changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
apps/predbat/octopus.py Adds product-info link inspection, new night-window definitions, json_only fetch mode, and day/night rate schedule generation updates.
apps/predbat/tests/test_octopus_day_night_rates.py New tests validating correct night window selection for IOG TOU, INTELLI, GO-style, and Economy 7 tariffs.
apps/predbat/tests/test_octopus_url.py Updates download-url tests to reflect removal of 400-based day/night detection behavior.
apps/predbat/tests/test_octopus_misc.py Updates fetch_tariffs mocks to accept new kwargs (json_only) and simulate product-info lookups.
apps/predbat/tests/test_fetch_url_cached.py Updates mocked downloader signature to accept kwargs passed through caching.
apps/predbat/unit_test.py Registers the new day/night rate test wrapper in the unit test runner.
.gitignore Ignores temp_octopus directory used by local/manual Octopus testing.
Comments suppressed due to low confidence (1)

apps/predbat/octopus.py:1291

  • async_download_octopus_url() no longer accepts HTTP 400 responses. If the product-info lookup fails (or is unavailable) and a dual-register tariff still returns 400 for standard-unit-rates, fetch_tariffs() will now fail to retrieve any rates. Consider restoring 400 handling (e.g., parse the JSON "detail" and fall back to async_get_day_night_rates for day/night tariffs, or at least treat 400 as a handled client error rather than an immediate hard failure).
                        if response.status not in [200, 201]:
                            self.failures_total += 1
                            self.log("Warn: OctopusAPI: Error downloading Octopus data from URL {}, code {}".format(url, response.status))
                            record_api_call("octopus_url", False, "server_error")
                            return {}

Comment thread apps/predbat/octopus.py
Comment on lines +1426 to +1428
# Standard rates, or product info unavailable — fall back to existing path
# (which handles the 400 "This tariff has day and night rates" error for Economy 7)
tariffs[tariff]["data"] = await self.fetch_url_cached(standard_url)
Comment thread apps/predbat/octopus.py
elif tariff_code and tariff_code.startswith("E-2R-"):
window = OCTOPUS_NIGHT_RATE_WINDOWS["eco7"]
else:
self.log("Warn: OctopusAPI: Unknown tariff code {}, defaulting to GO night rate window".format(tariff_code))
Comment thread apps/predbat/octopus.py
Get day and night rates from Octopus.

Selects the correct night/day window based on the tariff type:
- IOG TOU (product_code contains INTELLI+IOG+TOU): 23:30 to 05:30 (crosses midnight)
Comment thread apps/predbat/octopus.py
Comment on lines +1344 to 1348
async def fetch_url_cached(self, url, json_only=False):
"""
Fetch a URL from the cache or reload it
Uses individual file per URL in shared cache directory
Implements stale-while-revalidate to prevent thundering herd
Comment thread apps/predbat/octopus.py
Comment on lines +1418 to +1424
# Always check product links first to determine the correct rate endpoint type,
# avoiding the 400 round-trip for tariffs that only expose day/night rate endpoints.
link_types = await self._async_get_product_rate_link_types(product_code, tariff_code)
if link_types is not None and "standard_unit_rates" not in link_types and "day_unit_rates" in link_types:
# Day/night tariff (e.g. IOG-TOU, GO): fetch directly without hitting standard-unit-rates
self.log("Info: OctopusAPI: Product {} tariff {} has day/night rate endpoints (no standard-unit-rates), fetching directly".format(product_code, tariff_code))
tariffs[tariff]["data"] = await self.async_get_day_night_rates(standard_url, product_code=product_code, tariff_code=tariff_code)


def _extract_schedule(mdata):
"""Return a sorted list of (start_hour, start_min, end_hour, end_min, rate) tuples from mdata."""
@springfall2008 springfall2008 merged commit 5fe313a into main May 10, 2026
1 check passed
@springfall2008 springfall2008 deleted the fix/octopus_dual_rate branch May 10, 2026 13:44
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