From 804cd9d02ca40ba5145af273405188ab29ec3db4 Mon Sep 17 00:00:00 2001 From: David Kendall Date: Sun, 2 Jun 2024 07:29:03 +0100 Subject: [PATCH] feat: Added support for business tariffs (5 hours dev time) --- _docs/entities/electricity.md | 2 +- _docs/events.md | 4 +- _docs/repairs/unknown_product.md | 3 + _docs/repairs/unknown_tariff.md | 3 - _docs/repairs/unknown_tariff_format.md | 3 - custom_components/octopus_energy/__init__.py | 30 ++++---- .../octopus_energy/api_client/__init__.py | 43 +++-------- .../octopus_energy/binary_sensor.py | 6 +- .../octopus_energy/config/__init__.py | 10 +-- .../octopus_energy/config/target_rates.py | 2 +- .../octopus_energy/config_flow.py | 6 +- .../octopus_energy/coordinators/__init__.py | 59 ++++++--------- .../octopus_energy/coordinators/account.py | 12 ++-- .../coordinators/electricity_rates.py | 20 +++--- .../electricity_standing_charges.py | 16 ++--- .../octopus_energy/coordinators/gas_rates.py | 14 ++-- .../coordinators/gas_standing_charges.py | 16 ++--- .../previous_consumption_and_rates.py | 32 ++++----- .../cost_tracker/cost_tracker.py | 2 +- .../previous_accumulative_cost_override.py | 10 ++- custom_components/octopus_energy/event.py | 10 +-- .../previous_accumulative_cost_override.py | 10 ++- .../octopus_energy/intelligent/__init__.py | 18 +++-- custom_components/octopus_energy/sensor.py | 32 ++++----- .../octopus_energy/statistics/__init__.py | 10 +-- .../octopus_energy/statistics/refresh.py | 14 ++-- custom_components/octopus_energy/text.py | 14 ++-- .../octopus_energy/translations/en.json | 6 +- .../octopus_energy/utils/__init__.py | 19 ++++- .../octopus_energy/utils/tariff_overrides.py | 7 +- home_pro_server/oeha_server.py | 71 +++++++++++++++++++ mkdocs.yml | 3 +- .../api_client/test_get_electricity_rates.py | 63 +++++++++------- .../test_get_electricity_standing_charge.py | 32 +++++---- .../api_client/test_get_gas_rates.py | 24 ++++--- .../test_get_gas_standing_charge.py | 22 +++--- ...culate_electricity_consumption_and_cost.py | 5 +- ...test_calculate_gas_consumption_and_cost.py | 3 +- .../unit/config/test_validate_main_config.py | 2 +- .../test_validate_target_rate_config.py | 2 +- ...st_async_refresh_electricity_rates_data.py | 10 +-- ...efresh_electricity_standing_charge_data.py | 4 +- .../test_async_refresh_gas_rates_data.py | 4 +- ..._async_refresh_gas_standing_charge_data.py | 4 +- ...st_async_refresh_intelligent_dispatches.py | 9 +-- ...test_async_refresh_intelligent_settings.py | 7 +- .../test_previous_consumption_and_rates.py | 40 +++++++---- .../test_has_intelligent_tariff.py | 26 +++---- .../test_is_intelligent_product.py | 27 +++++++ .../intelligent/test_is_intelligent_tariff.py | 27 ------- .../test_get_statistic_ids_to_remove.py | 4 +- ...riff_code.py => test_get_active_tariff.py} | 36 ++++++++-- tests/unit/utils/test_is_agile_tariff.py | 2 +- tests/unit/utils/test_is_day_night_tariff.py | 13 ++++ 54 files changed, 497 insertions(+), 376 deletions(-) create mode 100644 _docs/repairs/unknown_product.md delete mode 100644 _docs/repairs/unknown_tariff.md delete mode 100644 _docs/repairs/unknown_tariff_format.md create mode 100644 home_pro_server/oeha_server.py create mode 100644 tests/unit/intelligent/test_is_intelligent_product.py delete mode 100644 tests/unit/intelligent/test_is_intelligent_tariff.py rename tests/unit/utils/{test_get_active_tariff_code.py => test_get_active_tariff.py} (76%) create mode 100644 tests/unit/utils/test_is_day_night_tariff.py diff --git a/_docs/entities/electricity.md b/_docs/entities/electricity.md index 6986e819..bd9d1936 100644 --- a/_docs/entities/electricity.md +++ b/_docs/entities/electricity.md @@ -611,7 +611,7 @@ The total cost reported by the meter for the current day during peak hours (the You may be on an existing tariff but want to know if the grass is greener (or cheaper) on the other side. The following entities are available in a disabled state, which when enabled can give you an indication what you'd be paying if you were on a different tariff and didn't change your energy habits. -See [below](#previous-accumulative-cost-override-tariff-electricity) for instructions on how to set up. +See [below](#previous-accumulative-cost-override-tariff) for instructions on how to set up. !!! info diff --git a/_docs/events.md b/_docs/events.md index 1ffed8de..ae6168b5 100644 --- a/_docs/events.md +++ b/_docs/events.md @@ -251,7 +251,7 @@ This is fired when the next day rates are updated. `octopus_energy_gas_previous_consumption_rates` -This is fired when the [previous consumption's](./entities/gas.md#previous-accumulative-consumption) rates are updated. +This is fired when the [previous consumption's](./entities/gas.md#previous-accumulative-consumption-m3) rates are updated. | Attribute | Type | Description | |-----------|------|-------------| @@ -315,7 +315,7 @@ This event is raised when a new saving session is discovered. | Attribute | Type | Description | |-----------|------|-------------| | `account_id` | `string` | The id of the account the new saving session is for | -| `event_code` | `string` | The code of the new saving session event. This is required if you wishing to use the [join event service](./services.md#join_octoplus_saving_session_event) | +| `event_code` | `string` | The code of the new saving session event. This is required if you wishing to use the [join event service](./services.md#octopus_energyjoin_octoplus_saving_session_event) | | `event_id` | `string` | The id of the event | | `event_start` | `datetime` | The date/time the event starts | | `event_end` | `datetime` | The date/time the event ends | diff --git a/_docs/repairs/unknown_product.md b/_docs/repairs/unknown_product.md new file mode 100644 index 00000000..2c3c0103 --- /dev/null +++ b/_docs/repairs/unknown_product.md @@ -0,0 +1,3 @@ +# Repairs - Unknown product + +If you receive this error around one or more of your tariffs, it's because the Octopus Energy API can not find the product associated with your tariff. This usually occurs if you're on a tariff which is currently internal and has not been exposed. In this scenario, you should [raise an issue](https://github.com/BottlecapDave/HomeAssistant-OctopusEnergy/issues) with the tariff code and your meter information, which can be obtained by following the [FAQ](../faq.md#ive-been-asked-for-my-meter-information-in-a-bug-request-how-do-i-obtain-this). \ No newline at end of file diff --git a/_docs/repairs/unknown_tariff.md b/_docs/repairs/unknown_tariff.md deleted file mode 100644 index 17d052e4..00000000 --- a/_docs/repairs/unknown_tariff.md +++ /dev/null @@ -1,3 +0,0 @@ -# Repairs - Unknown tariff - -If you receive this error around one or more of your tariffs, it's because the Octopus Energy API can not find the tariff. This usually occurs if you're on a tariff which is currently internal and has not been exposed. In this scenario, you should [raise an issue](https://github.com/BottlecapDave/HomeAssistant-OctopusEnergy/issues) with the tariff code and your meter information, which can be obtained by following the [FAQ](../faq.md#ive-been-asked-for-my-meter-information-in-a-bug-request-how-do-i-obtain-this). \ No newline at end of file diff --git a/_docs/repairs/unknown_tariff_format.md b/_docs/repairs/unknown_tariff_format.md deleted file mode 100644 index aa2bf045..00000000 --- a/_docs/repairs/unknown_tariff_format.md +++ /dev/null @@ -1,3 +0,0 @@ -# Repairs - Unknown tariff format - -If you receive this error around one or more of your tariffs, it's because it doesn't fit the format that Octopus Energy traditionally uses. In this scenario, you should [raise an issue](https://github.com/BottlecapDave/HomeAssistant-OctopusEnergy/issues) with the tariff code and your meter information, which can be obtained by following the [FAQ](../faq.md#ive-been-asked-for-my-meter-information-in-a-bug-request-how-do-i-obtain-this) \ No newline at end of file diff --git a/custom_components/octopus_energy/__init__.py b/custom_components/octopus_energy/__init__.py index 8971f42c..d91f3f75 100644 --- a/custom_components/octopus_energy/__init__.py +++ b/custom_components/octopus_energy/__init__.py @@ -17,11 +17,11 @@ from .coordinators.saving_sessions import async_setup_saving_sessions_coordinators from .coordinators.greenness_forecast import async_setup_greenness_forecast_coordinator from .statistics import get_statistic_ids_to_remove -from .intelligent import async_mock_intelligent_data, get_intelligent_features, is_intelligent_tariff, mock_intelligent_device +from .intelligent import async_mock_intelligent_data, get_intelligent_features, is_intelligent_product, mock_intelligent_device from .config.main import async_migrate_main_config from .config.target_rates import async_migrate_target_config -from .utils import get_active_tariff_code +from .utils import get_active_tariff from .utils.tariff_overrides import async_get_tariff_override from .const import ( @@ -132,8 +132,8 @@ async def async_close_connection(_) -> None: account_info = account_result.account if account_result is not None else None for point in account_info["electricity_meter_points"]: # We only care about points that have active agreements - electricity_tariff_code = get_active_tariff_code(now, point["agreements"]) - if electricity_tariff_code is not None: + electricity_tariff = get_active_tariff(now, point["agreements"]) + if electricity_tariff is not None: for meter in point["meters"]: mpan = point["mpan"] serial_number = meter["serial_number"] @@ -151,8 +151,8 @@ async def async_close_connection(_) -> None: account_info = account_result.account if account_result is not None else None for point in account_info["electricity_meter_points"]: # We only care about points that have active agreements - electricity_tariff_code = get_active_tariff_code(now, point["agreements"]) - if electricity_tariff_code is not None: + electricity_tariff = get_active_tariff(now, point["agreements"]) + if electricity_tariff is not None: for meter in point["meters"]: mpan = point["mpan"] serial_number = meter["serial_number"] @@ -219,8 +219,8 @@ async def async_setup_dependencies(hass, config): for meter in point["meters"]: serial_number = meter["serial_number"] - tariff_code = get_active_tariff_code(now, point["agreements"]) - if tariff_code is None: + tariff = get_active_tariff(now, point["agreements"]) + if tariff is None: gas_device = device_registry.async_get_device(identifiers={(DOMAIN, f"gas_{serial_number}_{mprn}")}) if gas_device is not None: _LOGGER.debug(f'Removed gas device {serial_number}/{mprn} due to no active tariff') @@ -236,14 +236,14 @@ async def async_setup_dependencies(hass, config): intelligent_serial_number = None for point in account_info["electricity_meter_points"]: mpan = point["mpan"] - electricity_tariff_code = get_active_tariff_code(now, point["agreements"]) + electricity_tariff = get_active_tariff(now, point["agreements"]) for meter in point["meters"]: serial_number = meter["serial_number"] - if electricity_tariff_code is not None: + if electricity_tariff is not None: if meter["is_export"] == False: - if is_intelligent_tariff(electricity_tariff_code): + if is_intelligent_product(electricity_tariff.product): intelligent_mpan = mpan intelligent_serial_number = serial_number has_intelligent_tariff = True @@ -257,8 +257,8 @@ async def async_setup_dependencies(hass, config): if should_mock_intelligent_data: # Pick the first meter if we're mocking our intelligent data for point in account_info["electricity_meter_points"]: - tariff_code = get_active_tariff_code(now, point["agreements"]) - if tariff_code is not None: + tariff = get_active_tariff(now, point["agreements"]) + if tariff is not None: for meter in point["meters"]: intelligent_mpan = point["mpan"] intelligent_serial_number = meter["serial_number"] @@ -280,8 +280,8 @@ async def async_setup_dependencies(hass, config): for point in account_info["electricity_meter_points"]: # We only care about points that have active agreements - electricity_tariff_code = get_active_tariff_code(now, point["agreements"]) - if electricity_tariff_code is not None: + electricity_tariff = get_active_tariff(now, point["agreements"]) + if electricity_tariff is not None: for meter in point["meters"]: mpan = point["mpan"] serial_number = meter["serial_number"] diff --git a/custom_components/octopus_energy/api_client/__init__.py b/custom_components/octopus_energy/api_client/__init__.py index 4c2e7ce3..8575dba9 100644 --- a/custom_components/octopus_energy/api_client/__init__.py +++ b/custom_components/octopus_energy/api_client/__init__.py @@ -10,10 +10,9 @@ from ..const import INTEGRATION_VERSION from ..utils import ( - get_tariff_parts, + is_day_night_tariff, ) - from .intelligent_device import IntelligentDevice from .octoplus import RedeemOctoplusPointsResponse from .intelligent_settings import IntelligentSettings @@ -774,20 +773,14 @@ async def async_get_electricity_day_night_rates(self, product_code, tariff_code, return results - async def async_get_electricity_rates(self, tariff_code: str, is_smart_meter: bool, period_from: datetime, period_to: datetime): + async def async_get_electricity_rates(self, product_code: str, tariff_code: str, is_smart_meter: bool, period_from: datetime, period_to: datetime): """Get the current rates""" - tariff_parts = get_tariff_parts(tariff_code) - if tariff_parts is None: - return None - - product_code = tariff_parts.product_code - - if (tariff_parts.rate.startswith("1")): - return await self.async_get_electricity_standard_rates(product_code, tariff_code, period_from, period_to) - else: + if is_day_night_tariff(tariff_code): return await self.async_get_electricity_day_night_rates(product_code, tariff_code, is_smart_meter, period_from, period_to) - + else: + return await self.async_get_electricity_standard_rates(product_code, tariff_code, period_from, period_to) + async def async_get_electricity_consumption(self, mpan, serial_number, period_from, period_to, page_size: int | None = None): """Get the current electricity consumption""" @@ -831,14 +824,8 @@ async def async_get_electricity_consumption(self, mpan, serial_number, period_fr _LOGGER.warning(f'Failed to connect. Timeout of {self._timeout} exceeded.') raise TimeoutException() - async def async_get_gas_rates(self, tariff_code, period_from, period_to): + async def async_get_gas_rates(self, product_code: str, tariff_code: str, period_from, period_to): """Get the gas rates""" - tariff_parts = get_tariff_parts(tariff_code) - if tariff_parts is None: - return None - - product_code = tariff_parts.product_code - results = [] try: @@ -912,14 +899,8 @@ async def async_get_product(self, product_code): _LOGGER.warning(f'Failed to connect. Timeout of {self._timeout} exceeded.') raise TimeoutException() - async def async_get_electricity_standing_charge(self, tariff_code, period_from, period_to): + async def async_get_electricity_standing_charge(self, product_code, tariff_code, period_from, period_to): """Get the electricity standing charges""" - tariff_parts = get_tariff_parts(tariff_code) - if tariff_parts is None: - return None - - product_code = tariff_parts.product_code - result = None try: @@ -940,14 +921,8 @@ async def async_get_electricity_standing_charge(self, tariff_code, period_from, _LOGGER.warning(f'Failed to connect. Timeout of {self._timeout} exceeded.') raise TimeoutException() - async def async_get_gas_standing_charge(self, tariff_code, period_from, period_to): + async def async_get_gas_standing_charge(self, product_code, tariff_code, period_from, period_to): """Get the gas standing charges""" - tariff_parts = get_tariff_parts(tariff_code) - if tariff_parts is None: - return None - - product_code = tariff_parts.product_code - result = None try: diff --git a/custom_components/octopus_energy/binary_sensor.py b/custom_components/octopus_energy/binary_sensor.py index 1783fcf4..21375f99 100644 --- a/custom_components/octopus_energy/binary_sensor.py +++ b/custom_components/octopus_energy/binary_sensor.py @@ -10,7 +10,7 @@ from .target_rates.target_rate import OctopusEnergyTargetRate from .intelligent.dispatching import OctopusEnergyIntelligentDispatching from .greenness_forecast.highlighted import OctopusEnergyGreennessForecastHighlighted -from .utils import get_active_tariff_code +from .utils import get_active_tariff from .intelligent import get_intelligent_features from .api_client.intelligent_device import IntelligentDevice @@ -91,7 +91,7 @@ async def async_setup_main_sensors(hass, entry, async_add_entities): for point in account_info["electricity_meter_points"]: # We only care about points that have active agreements - tariff_code = get_active_tariff_code(now, point["agreements"]) + tariff_code = get_active_tariff(now, point["agreements"]) if tariff_code is not None: for meter in point["meters"]: mpan = point["mpan"] @@ -128,7 +128,7 @@ async def async_setup_target_sensors(hass, entry, async_add_entities): now = utcnow() is_export = False for point in account_info["electricity_meter_points"]: - tariff_code = get_active_tariff_code(now, point["agreements"]) + tariff_code = get_active_tariff(now, point["agreements"]) if tariff_code is not None: # For backwards compatibility, pick the first applicable meter if point["mpan"] == mpan or mpan is None: diff --git a/custom_components/octopus_energy/config/__init__.py b/custom_components/octopus_energy/config/__init__.py index a9136fe7..291fcfe0 100644 --- a/custom_components/octopus_energy/config/__init__.py +++ b/custom_components/octopus_energy/config/__init__.py @@ -1,11 +1,11 @@ -from ..utils import get_active_tariff_code +from ..utils import Tariff, get_active_tariff -def get_meter_tariffs(account_info, now): +def get_meter_tariffs(account_info, now) -> "dict[str, Tariff]": meters = {} if account_info is not None and len(account_info["electricity_meter_points"]) > 0: for point in account_info["electricity_meter_points"]: - active_tariff_code = get_active_tariff_code(now, point["agreements"]) - if active_tariff_code is not None: - meters[point["mpan"]] = active_tariff_code + active_tariff = get_active_tariff(now, point["agreements"]) + if active_tariff is not None: + meters[point["mpan"]] = active_tariff return meters \ No newline at end of file diff --git a/custom_components/octopus_energy/config/target_rates.py b/custom_components/octopus_energy/config/target_rates.py index 90755618..1835bf0a 100644 --- a/custom_components/octopus_energy/config/target_rates.py +++ b/custom_components/octopus_energy/config/target_rates.py @@ -207,7 +207,7 @@ def validate_target_rate_config(data, account_info, now): errors[CONFIG_TARGET_MPAN] = "invalid_mpan" elif is_time_valid: tariff = meter_tariffs[data[CONFIG_TARGET_MPAN]] - if is_agile_tariff(tariff): + if is_agile_tariff(tariff.code): if is_in_agile_darkzone(start_time, end_time): errors[CONFIG_TARGET_END_TIME] = "invalid_end_time_agile" diff --git a/custom_components/octopus_energy/config_flow.py b/custom_components/octopus_energy/config_flow.py index fb98b32f..7c15bbc8 100644 --- a/custom_components/octopus_energy/config_flow.py +++ b/custom_components/octopus_energy/config_flow.py @@ -62,7 +62,7 @@ DATA_SCHEMA_ACCOUNT, ) -from .utils import get_active_tariff_code +from .utils import get_active_tariff _LOGGER = logging.getLogger(__name__) @@ -70,7 +70,7 @@ def get_target_rate_meters(account_info, now): meters = [] if account_info is not None and len(account_info["electricity_meter_points"]) > 0: for point in account_info["electricity_meter_points"]: - active_tariff_code = get_active_tariff_code(now, point["agreements"]) + active_tariff = get_active_tariff(now, point["agreements"]) is_export = False for meter in point["meters"]: @@ -78,7 +78,7 @@ def get_target_rate_meters(account_info, now): is_export = True break - if active_tariff_code is not None: + if active_tariff is not None: meters.append(selector.SelectOptionDict(value=point["mpan"], label= f'{point["mpan"]} ({"Export" if is_export == True else "Import"})')) return meters diff --git a/custom_components/octopus_energy/coordinators/__init__.py b/custom_components/octopus_energy/coordinators/__init__.py index 685de8a2..4a3c95da 100644 --- a/custom_components/octopus_energy/coordinators/__init__.py +++ b/custom_components/octopus_energy/coordinators/__init__.py @@ -15,8 +15,7 @@ from ..api_client import OctopusEnergyApiClient from ..utils import ( - get_active_tariff_code, - get_tariff_parts + get_active_tariff ) from ..utils.rate_information import get_min_max_average_rates from ..utils.requests import calculate_next_refresh @@ -55,40 +54,26 @@ def __init__(self, last_retrieved: datetime, request_attempts: int, refresh_rate self.next_refresh = calculate_next_refresh(last_retrieved, request_attempts, refresh_rate_in_minutes) _LOGGER.debug(f'last_retrieved: {last_retrieved}; request_attempts: {request_attempts}; refresh_rate_in_minutes: {refresh_rate_in_minutes}; next_refresh: {self.next_refresh}') -async def async_check_valid_tariff(hass, account_id: str, client: OctopusEnergyApiClient, tariff_code: str, is_electricity: bool): - tariff_key = f'{DATA_KNOWN_TARIFF}_{tariff_code}' - if (tariff_key not in hass.data[DOMAIN][account_id]): - tariff_parts = get_tariff_parts(tariff_code) - if tariff_parts is None: +async def async_check_valid_product(hass, account_id: str, client: OctopusEnergyApiClient, product_code: str, is_electricity: bool): + tariff_key = f'{DATA_KNOWN_TARIFF}_{product_code}' + try: + _LOGGER.debug(f"Retrieving product information for '{product_code}'") + product = await client.async_get_product(product_code) + if product is None: ir.async_create_issue( hass, DOMAIN, - f"unknown_tariff_format_{tariff_code}", + f"unknown_product_{product_code}", is_fixable=False, severity=ir.IssueSeverity.ERROR, - learn_more_url="https://bottlecapdave.github.io/HomeAssistant-OctopusEnergy/repairs/unknown_tariff_format", - translation_key="unknown_tariff_format", - translation_placeholders={ "type": "Electricity" if is_electricity else "Gas", "tariff_code": tariff_code }, + learn_more_url="https://bottlecapdave.github.io/HomeAssistant-OctopusEnergy/repairs/unknown_product", + translation_key="unknown_product", + translation_placeholders={ "type": "Electricity" if is_electricity else "Gas", "product_code": product_code }, ) else: - try: - _LOGGER.debug(f"Retrieving product information for '{tariff_parts.product_code}'") - product = await client.async_get_product(tariff_parts.product_code) - if product is None: - ir.async_create_issue( - hass, - DOMAIN, - f"unknown_tariff_{tariff_code}", - is_fixable=False, - severity=ir.IssueSeverity.ERROR, - learn_more_url="https://bottlecapdave.github.io/HomeAssistant-OctopusEnergy/repairs/unknown_tariff", - translation_key="unknown_tariff", - translation_placeholders={ "type": "Electricity" if is_electricity else "Gas", "tariff_code": tariff_code }, - ) - else: - hass.data[DOMAIN][account_id][tariff_key] = True - except: - _LOGGER.debug(f"Failed to retrieve product info for '{tariff_parts.product_code}'") + hass.data[DOMAIN][account_id][tariff_key] = True + except: + _LOGGER.debug(f"Failed to retrieve product info for '{product_code}'") def __raise_rate_event(event_key: str, rates: list, @@ -128,24 +113,24 @@ def raise_rate_events(now: datetime, __raise_rate_event(current_event_key, current_rates, additional_attributes, fire_event) __raise_rate_event(next_event_key, next_rates, additional_attributes, fire_event) -def get_electricity_meter_tariff_code(current: datetime, account_info, target_mpan: str, target_serial_number: str): +def get_electricity_meter_tariff(current: datetime, account_info, target_mpan: str, target_serial_number: str): if len(account_info["electricity_meter_points"]) > 0: for point in account_info["electricity_meter_points"]: - active_tariff_code = get_active_tariff_code(current, point["agreements"]) + active_tariff = get_active_tariff(current, point["agreements"]) # The type of meter (ie smart vs dumb) can change the tariff behaviour, so we # have to enumerate the different meters being used for each tariff as well. for meter in point["meters"]: - if active_tariff_code is not None and point["mpan"] == target_mpan and meter["serial_number"] == target_serial_number: - return active_tariff_code + if active_tariff is not None and point["mpan"] == target_mpan and meter["serial_number"] == target_serial_number: + return active_tariff return None -def get_gas_meter_tariff_code(current: datetime, account_info, target_mprn: str, target_serial_number: str): +def get_gas_meter_tariff(current: datetime, account_info, target_mprn: str, target_serial_number: str): if len(account_info["gas_meter_points"]) > 0: for point in account_info["gas_meter_points"]: - active_tariff_code = get_active_tariff_code(current, point["agreements"]) + active_tariff = get_active_tariff(current, point["agreements"]) for meter in point["meters"]: - if active_tariff_code is not None and point["mprn"] == target_mprn and meter["serial_number"] == target_serial_number: - return active_tariff_code + if active_tariff is not None and point["mprn"] == target_mprn and meter["serial_number"] == target_serial_number: + return active_tariff return None \ No newline at end of file diff --git a/custom_components/octopus_energy/coordinators/account.py b/custom_components/octopus_energy/coordinators/account.py index 38b3cb97..0576f58d 100644 --- a/custom_components/octopus_energy/coordinators/account.py +++ b/custom_components/octopus_energy/coordinators/account.py @@ -1,8 +1,8 @@ import logging from datetime import datetime, timedelta -from . import BaseCoordinatorResult, async_check_valid_tariff -from ..utils import get_active_tariff_code +from . import BaseCoordinatorResult, async_check_valid_product +from ..utils import get_active_tariff from homeassistant.util.dt import (now) from homeassistant.helpers.update_coordinator import ( @@ -63,13 +63,13 @@ async def async_refresh_account( if account_info is not None and len(account_info["electricity_meter_points"]) > 0: for point in account_info["electricity_meter_points"]: - active_tariff_code = get_active_tariff_code(current, point["agreements"]) - await async_check_valid_tariff(hass, account_id, client, active_tariff_code, True) + active_tariff = get_active_tariff(current, point["agreements"]) + await async_check_valid_product(hass, account_id, client, active_tariff.product, True) if account_info is not None and len(account_info["gas_meter_points"]) > 0: for point in account_info["gas_meter_points"]: - active_tariff_code = get_active_tariff_code(current, point["agreements"]) - await async_check_valid_tariff(hass, account_id, client, active_tariff_code, False) + active_tariff = get_active_tariff(current, point["agreements"]) + await async_check_valid_product(hass, account_id, client, active_tariff.product, False) return AccountCoordinatorResult(current, 1, account_info) except Exception as e: diff --git a/custom_components/octopus_energy/coordinators/electricity_rates.py b/custom_components/octopus_energy/coordinators/electricity_rates.py index 59f7c0af..b923d813 100644 --- a/custom_components/octopus_energy/coordinators/electricity_rates.py +++ b/custom_components/octopus_energy/coordinators/electricity_rates.py @@ -24,8 +24,8 @@ from ..api_client import ApiException, OctopusEnergyApiClient from ..coordinators.intelligent_dispatches import IntelligentDispatchesCoordinatorResult from ..utils import private_rates_to_public_rates -from . import BaseCoordinatorResult, get_electricity_meter_tariff_code, raise_rate_events -from ..intelligent import adjust_intelligent_rates, is_intelligent_tariff +from . import BaseCoordinatorResult, get_electricity_meter_tariff, raise_rate_events +from ..intelligent import adjust_intelligent_rates, is_intelligent_product _LOGGER = logging.getLogger(__name__) @@ -58,26 +58,26 @@ async def async_refresh_electricity_rates_data( period_from = as_utc((current - timedelta(days=1)).replace(hour=0, minute=0, second=0, microsecond=0)) period_to = as_utc((current + timedelta(days=2)).replace(hour=0, minute=0, second=0, microsecond=0)) - tariff_code = get_electricity_meter_tariff_code(current, account_info, target_mpan, target_serial_number) if tariff_override is None else tariff_override - if tariff_code is None: + tariff = get_electricity_meter_tariff(current, account_info, target_mpan, target_serial_number) if tariff_override is None else tariff_override + if tariff is None: return None # We'll calculate the wrong value if we don't have our intelligent dispatches - if is_intelligent_tariff(tariff_code) and (dispatches_result is None or dispatches_result.dispatches is None): + if is_intelligent_product(tariff.product) and (dispatches_result is None or dispatches_result.dispatches is None): return existing_rates_result new_rates = None if (existing_rates_result is None or current >= existing_rates_result.next_refresh): try: - new_rates = await client.async_get_electricity_rates(tariff_code, is_smart_meter, period_from, period_to) + new_rates = await client.async_get_electricity_rates(tariff.product, tariff.code, is_smart_meter, period_from, period_to) except Exception as e: if isinstance(e, ApiException) == False: raise - _LOGGER.debug(f'Failed to retrieve electricity rates for {target_mpan}/{target_serial_number} ({tariff_code})') + _LOGGER.debug(f'Failed to retrieve electricity rates for {target_mpan}/{target_serial_number} ({tariff.code})') if new_rates is not None: - _LOGGER.debug(f'Electricity rates retrieved for {target_mpan}/{target_serial_number} ({tariff_code});') + _LOGGER.debug(f'Electricity rates retrieved for {target_mpan}/{target_serial_number} ({tariff.code});') original_rates = new_rates.copy() original_rates.sort(key=lambda rate: rate["start"]) @@ -94,7 +94,7 @@ async def async_refresh_electricity_rates_data( raise_rate_events(current, private_rates_to_public_rates(new_rates), - { "mpan": target_mpan, "serial_number": target_serial_number, "tariff_code": tariff_code }, + { "mpan": target_mpan, "serial_number": target_serial_number, "tariff_code": tariff.code }, fire_event, EVENT_ELECTRICITY_PREVIOUS_DAY_RATES, EVENT_ELECTRICITY_CURRENT_DAY_RATES, @@ -144,7 +144,7 @@ async def async_refresh_electricity_rates_data( raise_rate_events(current, private_rates_to_public_rates(new_rates), - { "mpan": target_mpan, "serial_number": target_serial_number, "tariff_code": tariff_code, "intelligent_dispatches_updated": True }, + { "mpan": target_mpan, "serial_number": target_serial_number, "tariff_code": tariff.code, "intelligent_dispatches_updated": True }, fire_event, EVENT_ELECTRICITY_PREVIOUS_DAY_RATES, EVENT_ELECTRICITY_CURRENT_DAY_RATES, diff --git a/custom_components/octopus_energy/coordinators/electricity_standing_charges.py b/custom_components/octopus_energy/coordinators/electricity_standing_charges.py index 147cafd2..c4ef40b0 100644 --- a/custom_components/octopus_energy/coordinators/electricity_standing_charges.py +++ b/custom_components/octopus_energy/coordinators/electricity_standing_charges.py @@ -16,7 +16,7 @@ ) from ..api_client import ApiException, OctopusEnergyApiClient -from . import BaseCoordinatorResult, get_electricity_meter_tariff_code +from . import BaseCoordinatorResult, get_electricity_meter_tariff _LOGGER = logging.getLogger(__name__) @@ -39,20 +39,20 @@ async def async_refresh_electricity_standing_charges_data( period_to = period_from + timedelta(days=1) if (account_info is not None): - tariff_code = get_electricity_meter_tariff_code(current, account_info, target_mpan, target_serial_number) - if tariff_code is None: + tariff = get_electricity_meter_tariff(current, account_info, target_mpan, target_serial_number) + if tariff is None: return None new_standing_charge = None if (existing_standing_charges_result is None or current >= existing_standing_charges_result.next_refresh): try: - new_standing_charge = await client.async_get_electricity_standing_charge(tariff_code, period_from, period_to) - _LOGGER.debug(f'Electricity standing charges retrieved for {target_mpan}/{target_serial_number} ({tariff_code})') + new_standing_charge = await client.async_get_electricity_standing_charge(tariff.product, tariff.code, period_from, period_to) + _LOGGER.debug(f'Electricity standing charges retrieved for {target_mpan}/{target_serial_number} ({tariff.code})') except Exception as e: if isinstance(e, ApiException) == False: raise - _LOGGER.debug(f'Failed to retrieve electricity standing charges for {target_mpan}/{target_serial_number} ({tariff_code})') + _LOGGER.debug(f'Failed to retrieve electricity standing charges for {target_mpan}/{target_serial_number} ({tariff.code})') if new_standing_charge is not None: return ElectricityStandingChargeCoordinatorResult(current, 1, new_standing_charge) @@ -60,11 +60,11 @@ async def async_refresh_electricity_standing_charges_data( result = None if (existing_standing_charges_result is not None): result = ElectricityStandingChargeCoordinatorResult(existing_standing_charges_result.last_retrieved, existing_standing_charges_result.request_attempts + 1, existing_standing_charges_result.standing_charge) - _LOGGER.warning(f"Failed to retrieve new electricity standing charges for {target_mpan}/{target_serial_number} ({tariff_code}) - using cached standing charges. Next attempt at {result.next_refresh}") + _LOGGER.warning(f"Failed to retrieve new electricity standing charges for {target_mpan}/{target_serial_number} ({tariff.code}) - using cached standing charges. Next attempt at {result.next_refresh}") else: # We want to force into our fallback mode result = ElectricityStandingChargeCoordinatorResult(current - timedelta(minutes=REFRESH_RATE_IN_MINUTES_STANDING_CHARGE), 2, None) - _LOGGER.warning(f"Failed to retrieve new electricity standing charges for {target_mpan}/{target_serial_number} ({tariff_code}). Next attempt at {result.next_refresh}") + _LOGGER.warning(f"Failed to retrieve new electricity standing charges for {target_mpan}/{target_serial_number} ({tariff.code}). Next attempt at {result.next_refresh}") return result diff --git a/custom_components/octopus_energy/coordinators/gas_rates.py b/custom_components/octopus_energy/coordinators/gas_rates.py index 49efac96..f91dbb17 100644 --- a/custom_components/octopus_energy/coordinators/gas_rates.py +++ b/custom_components/octopus_energy/coordinators/gas_rates.py @@ -20,7 +20,7 @@ from ..api_client import ApiException, OctopusEnergyApiClient from ..utils import private_rates_to_public_rates -from . import BaseCoordinatorResult, get_gas_meter_tariff_code, raise_rate_events +from . import BaseCoordinatorResult, get_gas_meter_tariff, raise_rate_events _LOGGER = logging.getLogger(__name__) @@ -44,20 +44,20 @@ async def async_refresh_gas_rates_data( period_from = as_utc((current - timedelta(days=1)).replace(hour=0, minute=0, second=0, microsecond=0)) period_to = as_utc((current + timedelta(days=2)).replace(hour=0, minute=0, second=0, microsecond=0)) - tariff_code = get_gas_meter_tariff_code(current, account_info, target_mprn, target_serial_number) - if tariff_code is None: + tariff = get_gas_meter_tariff(current, account_info, target_mprn, target_serial_number) + if tariff is None: return None new_rates = None if (existing_rates_result is None or current >= existing_rates_result.next_refresh): try: - new_rates = await client.async_get_gas_rates(tariff_code, period_from, period_to) + new_rates = await client.async_get_gas_rates(tariff.product, tariff.code, period_from, period_to) except Exception as e: if isinstance(e, ApiException) == False: raise - _LOGGER.debug(f'Failed to retrieve gas rates for {target_mprn}/{target_serial_number} ({tariff_code})') + _LOGGER.debug(f'Failed to retrieve gas rates for {target_mprn}/{target_serial_number} ({tariff.code})') # Make sure our rate information doesn't contain any negative values https://github.com/BottlecapDave/HomeAssistant-OctopusEnergy/issues/506 if new_rates is not None: @@ -67,11 +67,11 @@ async def async_refresh_gas_rates_data( break if new_rates is not None: - _LOGGER.debug(f'Gas rates retrieved for {target_mprn}/{target_serial_number} ({tariff_code});') + _LOGGER.debug(f'Gas rates retrieved for {target_mprn}/{target_serial_number} ({tariff.code});') raise_rate_events(current, private_rates_to_public_rates(new_rates), - { "mprn": target_mprn, "serial_number": target_serial_number, "tariff_code": tariff_code }, + { "mprn": target_mprn, "serial_number": target_serial_number, "tariff_code": tariff.code }, fire_event, EVENT_GAS_PREVIOUS_DAY_RATES, EVENT_GAS_CURRENT_DAY_RATES, diff --git a/custom_components/octopus_energy/coordinators/gas_standing_charges.py b/custom_components/octopus_energy/coordinators/gas_standing_charges.py index adc6e9a6..13ffa288 100644 --- a/custom_components/octopus_energy/coordinators/gas_standing_charges.py +++ b/custom_components/octopus_energy/coordinators/gas_standing_charges.py @@ -16,7 +16,7 @@ ) from ..api_client import ApiException, OctopusEnergyApiClient -from . import BaseCoordinatorResult, get_gas_meter_tariff_code +from . import BaseCoordinatorResult, get_gas_meter_tariff _LOGGER = logging.getLogger(__name__) @@ -39,20 +39,20 @@ async def async_refresh_gas_standing_charges_data( period_to = period_from + timedelta(days=1) if (account_info is not None): - tariff_code = get_gas_meter_tariff_code(current, account_info, target_mprn, target_serial_number) - if tariff_code is None: + tariff = get_gas_meter_tariff(current, account_info, target_mprn, target_serial_number) + if tariff is None: return None new_standing_charge = None if (existing_standing_charges_result is None or current >= existing_standing_charges_result.next_refresh): try: - new_standing_charge = await client.async_get_gas_standing_charge(tariff_code, period_from, period_to) - _LOGGER.debug(f'Gas standing charges retrieved for {target_mprn}/{target_serial_number} ({tariff_code})') + new_standing_charge = await client.async_get_gas_standing_charge(tariff.product, tariff.code, period_from, period_to) + _LOGGER.debug(f'Gas standing charges retrieved for {target_mprn}/{target_serial_number} ({tariff.code})') except Exception as e: if isinstance(e, ApiException) == False: raise - _LOGGER.debug(f'Failed to retrieve gas standing charges for {target_mprn}/{target_serial_number} ({tariff_code})') + _LOGGER.debug(f'Failed to retrieve gas standing charges for {target_mprn}/{target_serial_number} ({tariff.code})') if new_standing_charge is not None: return GasStandingChargeCoordinatorResult(current, 1, new_standing_charge) @@ -60,11 +60,11 @@ async def async_refresh_gas_standing_charges_data( result = None if (existing_standing_charges_result is not None): result = GasStandingChargeCoordinatorResult(existing_standing_charges_result.last_retrieved, existing_standing_charges_result.request_attempts + 1, existing_standing_charges_result.standing_charge) - _LOGGER.warning(f"Failed to retrieve new gas standing charges for {target_mprn}/{target_serial_number} ({tariff_code}) - using cached standing charges. Next attempt at {result.next_refresh}") + _LOGGER.warning(f"Failed to retrieve new gas standing charges for {target_mprn}/{target_serial_number} ({tariff.code}) - using cached standing charges. Next attempt at {result.next_refresh}") else: # We want to force into our fallback mode result = GasStandingChargeCoordinatorResult(current - timedelta(minutes=REFRESH_RATE_IN_MINUTES_STANDING_CHARGE), 2, None) - _LOGGER.warning(f"Failed to retrieve new gas standing charges for {target_mprn}/{target_serial_number} ({tariff_code}). Next attempt at {result.next_refresh}") + _LOGGER.warning(f"Failed to retrieve new gas standing charges for {target_mprn}/{target_serial_number} ({tariff.code}). Next attempt at {result.next_refresh}") return result diff --git a/custom_components/octopus_energy/coordinators/previous_consumption_and_rates.py b/custom_components/octopus_energy/coordinators/previous_consumption_and_rates.py index 2e8f8bd0..842d3e58 100644 --- a/custom_components/octopus_energy/coordinators/previous_consumption_and_rates.py +++ b/custom_components/octopus_energy/coordinators/previous_consumption_and_rates.py @@ -21,11 +21,11 @@ from ..api_client import (ApiException, OctopusEnergyApiClient) from ..api_client.intelligent_dispatches import IntelligentDispatches -from ..utils import private_rates_to_public_rates +from ..utils import Tariff, private_rates_to_public_rates -from ..intelligent import adjust_intelligent_rates, is_intelligent_tariff +from ..intelligent import adjust_intelligent_rates, is_intelligent_product from ..coordinators.intelligent_dispatches import IntelligentDispatchesCoordinatorResult -from . import BaseCoordinatorResult, get_electricity_meter_tariff_code, get_gas_meter_tariff_code +from . import BaseCoordinatorResult, get_electricity_meter_tariff, get_gas_meter_tariff from ..utils.rate_information import get_min_max_average_rates _LOGGER = logging.getLogger(__name__) @@ -64,7 +64,7 @@ async def async_fetch_consumption_and_rates( is_smart_meter: bool, fire_event: Callable[[str, "dict[str, Any]"], None], intelligent_dispatches: IntelligentDispatches = None, - tariff_override = None + tariff_override: Tariff = None ): """Fetch the previous consumption and rates""" @@ -78,20 +78,20 @@ async def async_fetch_consumption_and_rates( try: if (is_electricity == True): - tariff_code = get_electricity_meter_tariff_code(period_from, account_info, identifier, serial_number) if tariff_override is None else tariff_override - if tariff_code is None: + tariff = get_electricity_meter_tariff(period_from, account_info, identifier, serial_number) if tariff_override is None else tariff_override + if tariff is None: _LOGGER.error(f"Could not determine tariff code for previous consumption for electricity {identifier}/{serial_number}") return previous_data # We'll calculate the wrong value if we don't have our intelligent dispatches - if is_intelligent_tariff(tariff_code) and intelligent_dispatches is None: + if is_intelligent_product(tariff.product) and intelligent_dispatches is None: return previous_data [consumption_data, latest_consumption_data, rate_data, standing_charge] = await asyncio.gather( client.async_get_electricity_consumption(identifier, serial_number, period_from, period_to), client.async_get_electricity_consumption(identifier, serial_number, None, None, 1), - client.async_get_electricity_rates(tariff_code, is_smart_meter, period_from, period_to), - client.async_get_electricity_standing_charge(tariff_code, period_from, period_to) + client.async_get_electricity_rates(tariff.product, tariff.code, is_smart_meter, period_from, period_to), + client.async_get_electricity_standing_charge(tariff.product, tariff.code, period_from, period_to) ) if intelligent_dispatches is not None: @@ -100,16 +100,16 @@ async def async_fetch_consumption_and_rates( intelligent_dispatches.planned, intelligent_dispatches.completed) else: - tariff_code = get_gas_meter_tariff_code(period_from, account_info, identifier, serial_number) if tariff_override is None else tariff_override - if tariff_code is None: + tariff = get_gas_meter_tariff(period_from, account_info, identifier, serial_number) if tariff_override is None else tariff_override + if tariff is None: _LOGGER.error(f"Could not determine tariff code for previous consumption for gas {identifier}/{serial_number}") return previous_data [consumption_data, latest_consumption_data, rate_data, standing_charge] = await asyncio.gather( client.async_get_gas_consumption(identifier, serial_number, period_from, period_to), client.async_get_gas_consumption(identifier, serial_number, None, None, 1), - client.async_get_gas_rates(tariff_code, period_from, period_to), - client.async_get_gas_standing_charge(tariff_code, period_from, period_to) + client.async_get_gas_rates(tariff.product, tariff.code, period_from, period_to), + client.async_get_gas_standing_charge(tariff.product, tariff.code, period_from, period_to) ) if consumption_data is not None and len(consumption_data) >= MINIMUM_CONSUMPTION_DATA_LENGTH and rate_data is not None and len(rate_data) > 0 and standing_charge is not None: @@ -120,9 +120,9 @@ async def async_fetch_consumption_and_rates( min_max_average_rates = get_min_max_average_rates(public_rates) if (is_electricity == True): - fire_event(EVENT_ELECTRICITY_PREVIOUS_CONSUMPTION_RATES, { "mpan": identifier, "serial_number": serial_number, "tariff_code": tariff_code, "rates": public_rates, "min_rate": min_max_average_rates["min"], "max_rate": min_max_average_rates["max"], "average_rate": min_max_average_rates["average"] }) + fire_event(EVENT_ELECTRICITY_PREVIOUS_CONSUMPTION_RATES, { "mpan": identifier, "serial_number": serial_number, "tariff_code": tariff.code, "rates": public_rates, "min_rate": min_max_average_rates["min"], "max_rate": min_max_average_rates["max"], "average_rate": min_max_average_rates["average"] }) else: - fire_event(EVENT_GAS_PREVIOUS_CONSUMPTION_RATES, { "mprn": identifier, "serial_number": serial_number, "tariff_code": tariff_code, "rates": public_rates, "min_rate": min_max_average_rates["min"], "max_rate": min_max_average_rates["max"], "average_rate": min_max_average_rates["average"] }) + fire_event(EVENT_GAS_PREVIOUS_CONSUMPTION_RATES, { "mprn": identifier, "serial_number": serial_number, "tariff_code": tariff.code, "rates": public_rates, "min_rate": min_max_average_rates["min"], "max_rate": min_max_average_rates["max"], "average_rate": min_max_average_rates["average"] }) _LOGGER.debug(f"Fired event for {'electricity' if is_electricity else 'gas'} {identifier}/{serial_number}") @@ -185,7 +185,7 @@ async def async_create_previous_consumption_and_rates_coordinator( is_electricity: bool, is_smart_meter: bool, days_offset: int, - tariff_override = None): + tariff_override: Tariff = None): """Create reading coordinator""" previous_consumption_data_key = f'{identifier}_{serial_number}_previous_consumption_and_rates' diff --git a/custom_components/octopus_energy/cost_tracker/cost_tracker.py b/custom_components/octopus_energy/cost_tracker/cost_tracker.py index 59f7bef4..3aa86303 100644 --- a/custom_components/octopus_energy/cost_tracker/cost_tracker.py +++ b/custom_components/octopus_energy/cost_tracker/cost_tracker.py @@ -178,7 +178,7 @@ async def _async_calculate_cost(self, event: Event[EventStateChangedData]): new_last_reset, old_last_reset, self._config[CONFIG_COST_ENTITY_ACCUMULATIVE_VALUE], - self._attributes["is_tracking"], + self._attributes["is_tracking"] if "is_tracking" in self._attributes else True, new_state.attributes["state_class"] if "state_class" in new_state.attributes else None) diff --git a/custom_components/octopus_energy/electricity/previous_accumulative_cost_override.py b/custom_components/octopus_energy/electricity/previous_accumulative_cost_override.py index 67dd96f2..847df8dc 100644 --- a/custom_components/octopus_energy/electricity/previous_accumulative_cost_override.py +++ b/custom_components/octopus_energy/electricity/previous_accumulative_cost_override.py @@ -27,7 +27,7 @@ from ..utils.attributes import dict_to_typed_dict from ..utils.requests import calculate_next_refresh from ..coordinators.previous_consumption_and_rates import PreviousConsumptionCoordinatorResult -from ..utils import private_rates_to_public_rates +from ..utils import get_tariff_parts, private_rates_to_public_rates from ..api_client import (ApiException, OctopusEnergyApiClient) @@ -136,11 +136,15 @@ async def async_update(self): period_from = consumption_data[0]["start"] period_to = consumption_data[-1]["end"] + tariff_parts = get_tariff_parts(tariff_override) + if tariff_parts is None: + return None + try: _LOGGER.debug(f"Retrieving rates and standing charge overrides for '{self._mpan}/{self._serial_number}' ({period_from} - {period_to})...") [rate_data, standing_charge] = await asyncio.gather( - self._client.async_get_electricity_rates(tariff_override, self._is_smart_meter, period_from, period_to), - self._client.async_get_electricity_standing_charge(tariff_override, period_from, period_to) + self._client.async_get_electricity_rates(tariff_parts.product_code, tariff_override, self._is_smart_meter, period_from, period_to), + self._client.async_get_electricity_standing_charge(tariff_parts.product_code, tariff_override, period_from, period_to) ) _LOGGER.debug(f"Rates and standing charge overrides for '{self._mpan}/{self._serial_number}' ({period_from} - {period_to}) retrieved") diff --git a/custom_components/octopus_energy/event.py b/custom_components/octopus_energy/event.py index b35cf6b1..a1bd1fc5 100644 --- a/custom_components/octopus_energy/event.py +++ b/custom_components/octopus_energy/event.py @@ -4,7 +4,7 @@ from homeassistant.util.dt import (utcnow) from homeassistant.helpers import config_validation as cv, entity_platform -from .utils import get_active_tariff_code +from .utils import get_active_tariff from .electricity.rates_previous_day import OctopusEnergyElectricityPreviousDayRates from .electricity.rates_current_day import OctopusEnergyElectricityCurrentDayRates from .electricity.rates_next_day import OctopusEnergyElectricityNextDayRates @@ -68,8 +68,8 @@ async def async_setup_main_sensors(hass, entry, async_add_entities): if len(account_info["electricity_meter_points"]) > 0: for point in account_info["electricity_meter_points"]: # We only care about points that have active agreements - tariff_code = get_active_tariff_code(now, point["agreements"]) - if tariff_code is not None: + tariff = get_active_tariff(now, point["agreements"]) + if tariff is not None: for meter in point["meters"]: entities.append(OctopusEnergyElectricityPreviousDayRates(hass, meter, point)) entities.append(OctopusEnergyElectricityCurrentDayRates(hass, meter, point)) @@ -80,8 +80,8 @@ async def async_setup_main_sensors(hass, entry, async_add_entities): if len(account_info["gas_meter_points"]) > 0: for point in account_info["gas_meter_points"]: # We only care about points that have active agreements - tariff_code = get_active_tariff_code(now, point["agreements"]) - if tariff_code is not None: + tariff = get_active_tariff(now, point["agreements"]) + if tariff is not None: for meter in point["meters"]: entities.append(OctopusEnergyGasPreviousDayRates(hass, meter, point)) entities.append(OctopusEnergyGasCurrentDayRates(hass, meter, point)) diff --git a/custom_components/octopus_energy/gas/previous_accumulative_cost_override.py b/custom_components/octopus_energy/gas/previous_accumulative_cost_override.py index d88ed913..5e01c310 100644 --- a/custom_components/octopus_energy/gas/previous_accumulative_cost_override.py +++ b/custom_components/octopus_energy/gas/previous_accumulative_cost_override.py @@ -30,7 +30,7 @@ from ..utils.attributes import dict_to_typed_dict from ..utils.requests import calculate_next_refresh from ..coordinators.previous_consumption_and_rates import PreviousConsumptionCoordinatorResult -from ..utils import private_rates_to_public_rates +from ..utils import get_tariff_parts, private_rates_to_public_rates from ..const import DOMAIN, EVENT_GAS_PREVIOUS_CONSUMPTION_OVERRIDE_RATES, MINIMUM_CONSUMPTION_DATA_LENGTH, REFRESH_RATE_IN_MINUTES_PREVIOUS_CONSUMPTION @@ -135,11 +135,15 @@ async def async_update(self): period_from = consumption_data[0]["start"] period_to = consumption_data[-1]["end"] + tariff_parts = get_tariff_parts(tariff_override) + if tariff_parts is None: + return None + try: _LOGGER.debug(f"Retrieving rates and standing charge overrides for '{self._mprn}/{self._serial_number}' ({period_from} - {period_to})...") [rate_data, standing_charge] = await asyncio.gather( - self._client.async_get_gas_rates(tariff_override, period_from, period_to), - self._client.async_get_gas_standing_charge(tariff_override, period_from, period_to) + self._client.async_get_gas_rates(tariff_parts.product_code, tariff_override, period_from, period_to), + self._client.async_get_gas_standing_charge(tariff_parts.product_code, tariff_override, period_from, period_to) ) _LOGGER.debug(f"Rates and standing charge overrides for '{self._mprn}/{self._serial_number}' ({period_from} - {period_to}) retrieved") diff --git a/custom_components/octopus_energy/intelligent/__init__.py b/custom_components/octopus_energy/intelligent/__init__.py index f78e9d6e..b5ef651c 100644 --- a/custom_components/octopus_energy/intelligent/__init__.py +++ b/custom_components/octopus_energy/intelligent/__init__.py @@ -6,7 +6,7 @@ from homeassistant.helpers import storage -from ..utils import OffPeakTime, get_active_tariff_code, get_tariff_parts +from ..utils import get_active_tariff from ..const import DOMAIN, INTELLIGENT_SOURCE_BUMP_CHARGE, INTELLIGENT_SOURCE_SMART_CHARGE, REFRESH_RATE_IN_MINUTES_INTELLIGENT @@ -109,21 +109,19 @@ def mock_intelligent_device(): 6.5 ) -def is_intelligent_tariff(tariff_code: str): - parts = get_tariff_parts(tariff_code.upper()) - +def is_intelligent_product(product_code: str): # Need to ignore Octopus Intelligent Go tariffs - return parts is not None and ( - "INTELLI-BB-VAR" in parts.product_code or - "INTELLI-VAR" in parts.product_code or - re.search("INTELLI-[0-9]", parts.product_code) is not None + return product_code is not None and ( + "INTELLI-BB-VAR" in product_code.upper() or + "INTELLI-VAR" in product_code.upper() or + re.search("INTELLI-[0-9]", product_code.upper()) is not None ) def has_intelligent_tariff(current: datetime, account_info): if account_info is not None and len(account_info["electricity_meter_points"]) > 0: for point in account_info["electricity_meter_points"]: - tariff_code = get_active_tariff_code(current, point["agreements"]) - if tariff_code is not None and is_intelligent_tariff(tariff_code): + tariff = get_active_tariff(current, point["agreements"]) + if tariff is not None and is_intelligent_product(tariff.product): return True return False diff --git a/custom_components/octopus_energy/sensor.py b/custom_components/octopus_energy/sensor.py index 13b75556..b588f988 100644 --- a/custom_components/octopus_energy/sensor.py +++ b/custom_components/octopus_energy/sensor.py @@ -52,7 +52,7 @@ from .octoplus.points import OctopusEnergyOctoplusPoints -from .utils import (get_active_tariff_code) +from .utils import (Tariff, get_active_tariff) from .const import ( CONFIG_COST_MPAN, CONFIG_ACCOUNT_ID, @@ -81,18 +81,18 @@ _LOGGER = logging.getLogger(__name__) -async def get_unique_electricity_rates(hass, client: OctopusEnergyApiClient, tariff_code: str): - total_unique_rates = await async_get_cached_tariff_total_unique_rates(hass, tariff_code) +async def get_unique_electricity_rates(hass, client: OctopusEnergyApiClient, tariff: Tariff): + total_unique_rates = await async_get_cached_tariff_total_unique_rates(hass, tariff) if total_unique_rates is None: current_date = now() period_from = current_date.replace(hour=0, minute=0, second=0, microsecond=0) period_to = period_from + timedelta(days=1) - rates = await client.async_get_electricity_rates(tariff_code, True, period_from, period_to) + rates = await client.async_get_electricity_rates(tariff.product, tariff.code, True, period_from, period_to) if rates is None: - raise Exception(f"Failed to retrieve rates for tariff '{tariff_code}'") + raise Exception(f"Failed to retrieve rates for tariff '{tariff.code}'") total_unique_rates = len(get_unique_rates(current_date, rates)) - await async_save_cached_tariff_total_unique_rates(hass, tariff_code, total_unique_rates) + await async_save_cached_tariff_total_unique_rates(hass, tariff.code, total_unique_rates) return total_unique_rates @@ -243,8 +243,8 @@ async def async_setup_default_sensors(hass: HomeAssistant, config, async_add_ent for point in account_info["electricity_meter_points"]: # We only care about points that have active agreements - electricity_tariff_code = get_active_tariff_code(now, point["agreements"]) - if electricity_tariff_code is not None: + electricity_tariff = get_active_tariff(now, point["agreements"]) + if electricity_tariff is not None: for meter in point["meters"]: mpan = point["mpan"] serial_number = meter["serial_number"] @@ -273,10 +273,10 @@ async def async_setup_default_sensors(hass: HomeAssistant, config, async_add_ent ) entities.append(OctopusEnergyPreviousAccumulativeElectricityConsumption(hass, client, previous_consumption_coordinator, account_id, meter, point)) entities.append(OctopusEnergyPreviousAccumulativeElectricityCost(hass, previous_consumption_coordinator, meter, point)) - entities.append(OctopusEnergyPreviousAccumulativeElectricityCostOverride(hass, account_id, previous_consumption_coordinator, client, electricity_tariff_code, meter, point)) + entities.append(OctopusEnergyPreviousAccumulativeElectricityCostOverride(hass, account_id, previous_consumption_coordinator, client, electricity_tariff, meter, point)) # Create a peak override for each available peak type for our tariff - total_unique_rates = await get_unique_electricity_rates(hass, client, electricity_tariff_code if tariff_override is None else tariff_override) + total_unique_rates = await get_unique_electricity_rates(hass, client, electricity_tariff if tariff_override is None else tariff_override) for unique_rate_index in range(0, total_unique_rates): peak_type = get_peak_type(total_unique_rates, unique_rate_index) if peak_type is not None: @@ -337,8 +337,8 @@ async def async_setup_default_sensors(hass: HomeAssistant, config, async_add_ent for point in account_info["gas_meter_points"]: # We only care about points that have active agreements - gas_tariff_code = get_active_tariff_code(now, point["agreements"]) - if gas_tariff_code is not None: + gas_tariff = get_active_tariff(now, point["agreements"]) + if gas_tariff is not None: for meter in point["meters"]: mprn = point["mprn"] serial_number = meter["serial_number"] @@ -368,7 +368,7 @@ async def async_setup_default_sensors(hass: HomeAssistant, config, async_add_ent entities.append(OctopusEnergyPreviousAccumulativeGasConsumptionCubicMeters(hass, client, previous_consumption_coordinator, account_id, meter, point, calorific_value)) entities.append(OctopusEnergyPreviousAccumulativeGasConsumptionKwh(hass, previous_consumption_coordinator, meter, point, calorific_value)) entities.append(OctopusEnergyPreviousAccumulativeGasCost(hass, previous_consumption_coordinator, meter, point, calorific_value)) - entities.append(OctopusEnergyPreviousAccumulativeGasCostOverride(hass, account_id, previous_consumption_coordinator, client, gas_tariff_code, meter, point, calorific_value)) + entities.append(OctopusEnergyPreviousAccumulativeGasCostOverride(hass, account_id, previous_consumption_coordinator, client, gas_tariff.code, meter, point, calorific_value)) entity_ids_to_migrate.append({ "old": f"octopus_energy_gas_{serial_number}_{mprn}_previous_accumulative_consumption", @@ -435,8 +435,8 @@ async def async_setup_cost_sensors(hass: HomeAssistant, entry, config, async_add now = utcnow() for point in account_info["electricity_meter_points"]: - tariff_code = get_active_tariff_code(now, point["agreements"]) - if tariff_code is not None: + tariff = get_active_tariff(now, point["agreements"]) + if tariff is not None: # For backwards compatibility, pick the first applicable meter if point["mpan"] == mpan or mpan is None: for meter in point["meters"]: @@ -453,7 +453,7 @@ async def async_setup_cost_sensors(hass: HomeAssistant, entry, config, async_add ] tariff_override = await async_get_tariff_override(hass, mpan, serial_number) - total_unique_rates = await get_unique_electricity_rates(hass, client, tariff_code if tariff_override is None else tariff_override) + total_unique_rates = await get_unique_electricity_rates(hass, client, tariff if tariff_override is None else tariff_override) if has_peak_rates(total_unique_rates): for unique_rate_index in range(0, total_unique_rates): peak_type = get_peak_type(total_unique_rates, unique_rate_index) diff --git a/custom_components/octopus_energy/statistics/__init__.py b/custom_components/octopus_energy/statistics/__init__.py index c493a581..1854c383 100644 --- a/custom_components/octopus_energy/statistics/__init__.py +++ b/custom_components/octopus_energy/statistics/__init__.py @@ -9,7 +9,7 @@ ) from ..const import DOMAIN -from ..utils import get_active_tariff_code +from ..utils import get_active_tariff _LOGGER = logging.getLogger(__name__) @@ -121,8 +121,8 @@ def get_statistic_ids_to_remove(now, account_info): if len(account_info["electricity_meter_points"]) > 0: for point in account_info["electricity_meter_points"]: # We only care about points that have active agreements - electricity_tariff_code = get_active_tariff_code(now, point["agreements"]) - if electricity_tariff_code is None: + electricity_tariff = get_active_tariff(now, point["agreements"]) + if electricity_tariff is None: for meter in point["meters"]: external_statistic_ids_to_remove.append(f"{DOMAIN}:electricity_{meter['serial_number']}_{point['mpan']}{'_export' if meter['is_export'] == True else ''}_previous_accumulative_consumption") external_statistic_ids_to_remove.append(f"{DOMAIN}:electricity_{meter['serial_number']}_{point['mpan']}{'_export' if meter['is_export'] == True else ''}_previous_accumulative_cost") @@ -134,8 +134,8 @@ def get_statistic_ids_to_remove(now, account_info): if len(account_info["gas_meter_points"]) > 0: for point in account_info["gas_meter_points"]: # We only care about points that have active agreements - gas_tariff_code = get_active_tariff_code(now, point["agreements"]) - if gas_tariff_code is None: + gas_tariff = get_active_tariff(now, point["agreements"]) + if gas_tariff is None: for meter in point["meters"]: external_statistic_ids_to_remove.append(f"{DOMAIN}:gas_{meter['serial_number']}_{point['mprn']}_previous_accumulative_consumption") external_statistic_ids_to_remove.append(f"{DOMAIN}:gas_{meter['serial_number']}_{point['mprn']}_previous_accumulative_cost") diff --git a/custom_components/octopus_energy/statistics/refresh.py b/custom_components/octopus_energy/statistics/refresh.py index f4a9be16..b940d34e 100644 --- a/custom_components/octopus_energy/statistics/refresh.py +++ b/custom_components/octopus_energy/statistics/refresh.py @@ -17,7 +17,7 @@ from .cost import async_import_external_statistics_from_cost, get_electricity_cost_statistic_name, get_electricity_cost_statistic_unique_id, get_gas_cost_statistic_name, get_gas_cost_statistic_unique_id from ..electricity import calculate_electricity_consumption_and_cost from ..gas import calculate_gas_consumption_and_cost -from ..coordinators import get_electricity_meter_tariff_code, get_gas_meter_tariff_code +from ..coordinators import get_electricity_meter_tariff, get_gas_meter_tariff async def async_refresh_previous_electricity_consumption_data( hass: HomeAssistant, @@ -53,8 +53,8 @@ async def async_refresh_previous_electricity_consumption_data( while period_from < now(): period_to = period_from + timedelta(days=1) - tariff_code = get_electricity_meter_tariff_code(period_from, account_info, mpan, serial_number) - if tariff_code is None: + tariff = get_electricity_meter_tariff(period_from, account_info, mpan, serial_number) + if tariff is None: persistent_notification.async_create( hass, title="Failed to find tariff information", @@ -63,7 +63,7 @@ async def async_refresh_previous_electricity_consumption_data( return consumption_data = await client.async_get_electricity_consumption(mpan, serial_number, period_from, period_to) - rates = await client.async_get_electricity_rates(tariff_code, is_smart_meter, period_from, period_to) + rates = await client.async_get_electricity_rates(tariff.product, tariff.code, is_smart_meter, period_from, period_to) consumption_and_cost = calculate_electricity_consumption_and_cost( consumption_data, @@ -139,8 +139,8 @@ async def async_refresh_previous_gas_consumption_data( while period_from < now(): period_to = period_from + timedelta(days=1) - tariff_code = get_gas_meter_tariff_code(period_from, account_info, mprn, serial_number) - if tariff_code is None: + tariff = get_gas_meter_tariff(period_from, account_info, mprn, serial_number) + if tariff is None: persistent_notification.async_create( hass, title="Failed to find tariff information", @@ -149,7 +149,7 @@ async def async_refresh_previous_gas_consumption_data( return consumption_data = await client.async_get_gas_consumption(mprn, serial_number, period_from, period_to) - rates = await client.async_get_gas_rates(tariff_code, period_from, period_to) + rates = await client.async_get_gas_rates(tariff.product, tariff.code, period_from, period_to) consumption_and_cost = calculate_gas_consumption_and_cost( consumption_data, diff --git a/custom_components/octopus_energy/text.py b/custom_components/octopus_energy/text.py index 12ca8a9b..c827cdf5 100644 --- a/custom_components/octopus_energy/text.py +++ b/custom_components/octopus_energy/text.py @@ -7,7 +7,7 @@ from .electricity.previous_accumulative_cost_override_tariff import OctopusEnergyPreviousAccumulativeElectricityCostTariffOverride from .gas.previous_accumulative_cost_override_tariff import OctopusEnergyPreviousAccumulativeGasCostTariffOverride -from .utils import (get_active_tariff_code) +from .utils import (get_active_tariff) from .const import ( CONFIG_ACCOUNT_ID, DOMAIN, @@ -46,13 +46,13 @@ async def async_setup_default_sensors(hass: HomeAssistant, config, async_add_ent for point in account_info["electricity_meter_points"]: # We only care about points that have active agreements - electricity_tariff_code = get_active_tariff_code(now, point["agreements"]) - if electricity_tariff_code is not None: + electricity_tariff = get_active_tariff(now, point["agreements"]) + if electricity_tariff is not None: for meter in point["meters"]: _LOGGER.info(f'Adding electricity meter; mpan: {point["mpan"]}; serial number: {meter["serial_number"]}') if meter["is_smart_meter"] == True: - entities.append(OctopusEnergyPreviousAccumulativeElectricityCostTariffOverride(hass, account_id, client, electricity_tariff_code, meter, point)) + entities.append(OctopusEnergyPreviousAccumulativeElectricityCostTariffOverride(hass, account_id, client, electricity_tariff.code, meter, point)) else: for meter in point["meters"]: _LOGGER.info(f'Skipping electricity meter due to no active agreement; mpan: {point["mpan"]}; serial number: {meter["serial_number"]}') @@ -63,13 +63,13 @@ async def async_setup_default_sensors(hass: HomeAssistant, config, async_add_ent if len(account_info["gas_meter_points"]) > 0: for point in account_info["gas_meter_points"]: # We only care about points that have active agreements - gas_tariff_code = get_active_tariff_code(now, point["agreements"]) - if gas_tariff_code is not None: + gas_tariff = get_active_tariff(now, point["agreements"]) + if gas_tariff is not None: for meter in point["meters"]: _LOGGER.info(f'Adding gas meter; mprn: {point["mprn"]}; serial number: {meter["serial_number"]}') if meter["is_smart_meter"] == True: - entities.append(OctopusEnergyPreviousAccumulativeGasCostTariffOverride(hass, account_id, client, gas_tariff_code, meter, point)) + entities.append(OctopusEnergyPreviousAccumulativeGasCostTariffOverride(hass, account_id, client, gas_tariff.code, meter, point)) else: for meter in point["meters"]: _LOGGER.info(f'Skipping gas meter due to no active agreement; mprn: {point["mprn"]}; serial number: {meter["serial_number"]}') diff --git a/custom_components/octopus_energy/translations/en.json b/custom_components/octopus_energy/translations/en.json index f85d3a31..05a0e7d7 100644 --- a/custom_components/octopus_energy/translations/en.json +++ b/custom_components/octopus_energy/translations/en.json @@ -181,9 +181,9 @@ "title": "Invalid format - {type} - {tariff_code}", "description": "The tariff \"{tariff_code}\" associated with your {type} meter is not in an expected format. Click on \"Learn More\" with instructions on what to do next." }, - "unknown_tariff": { - "title": "Unknown tariff - {type} - {tariff_code}", - "description": "The tariff \"{tariff_code}\" associated with your {type} meter has not been found. Click on \"Learn More\" with instructions on what to do next." + "unknown_product": { + "title": "Unknown product - {type} - {product_code}", + "description": "The product \"{product_code}\" associated with your {type} meter has not been found. Click on \"Learn More\" with instructions on what to do next." }, "invalid_target_rate": { "title": "Invalid target rate \"{name}\"", diff --git a/custom_components/octopus_energy/utils/__init__.py b/custom_components/octopus_energy/utils/__init__.py index 0bd8ae4f..dcf4dfa3 100644 --- a/custom_components/octopus_energy/utils/__init__.py +++ b/custom_components/octopus_energy/utils/__init__.py @@ -23,7 +23,7 @@ def __init__(self, energy: str, rate: str, product_code: str, region: str): self.product_code = product_code self.region = region -def get_tariff_parts(tariff_code) -> TariffParts: +def get_tariff_parts(tariff_code: str) -> TariffParts: matches = re.search(REGEX_TARIFF_PARTS, tariff_code) if matches is None: return None @@ -37,7 +37,20 @@ def get_tariff_parts(tariff_code) -> TariffParts: return TariffParts(energy, rate, product_code, region) -def get_active_tariff_code(utcnow: datetime, agreements): +class Tariff: + product: str + code: str + + def __init__(self, product: str, code: str): + self.product = product + self.code = code + +def is_day_night_tariff(tariff_code: str) -> bool: + tariff_parts = get_tariff_parts(tariff_code) + print(tariff_parts) + return tariff_parts is not None and tariff_parts.rate.startswith("2") + +def get_active_tariff(utcnow: datetime, agreements): latest_agreement = None latest_valid_from = None @@ -59,7 +72,7 @@ def get_active_tariff_code(utcnow: datetime, agreements): latest_valid_from = valid_from if latest_agreement is not None: - return latest_agreement["tariff_code"] + return Tariff(latest_agreement["product_code"], latest_agreement["tariff_code"]) return None diff --git a/custom_components/octopus_energy/utils/tariff_overrides.py b/custom_components/octopus_energy/utils/tariff_overrides.py index 08fcb238..345077e5 100644 --- a/custom_components/octopus_energy/utils/tariff_overrides.py +++ b/custom_components/octopus_energy/utils/tariff_overrides.py @@ -3,6 +3,7 @@ from homeassistant.helpers import storage from ..const import STORAGE_ELECTRICITY_TARIFF_OVERRIDE_NAME +from ..utils import Tariff _LOGGER = logging.getLogger(__name__) @@ -12,9 +13,9 @@ async def async_get_tariff_override(hass, mpan_mprn: str, serial_number: str): try: data = await store.async_load() - if data is not None and "tariff" in data: - tariff = data["tariff"] - _LOGGER.info(f"Overriding tariff for {mpan_mprn}/{serial_number} with {tariff}") + if data is not None and "tariff_code" in data and "product_code" in data: + tariff = Tariff(data["product_code"], data["tariff_code"]) + _LOGGER.info(f"Overriding tariff for {mpan_mprn}/{serial_number} with {tariff.code}") return tariff except: diff --git a/home_pro_server/oeha_server.py b/home_pro_server/oeha_server.py new file mode 100644 index 00000000..af28e860 --- /dev/null +++ b/home_pro_server/oeha_server.py @@ -0,0 +1,71 @@ +import json +import os +from urllib.parse import urlparse +from http.server import BaseHTTPRequestHandler, HTTPServer +import requests + +han_host = os.getenv("HAN_API_HOST") + +class RequestHandler(BaseHTTPRequestHandler): + # Handle GET requests + def do_GET(self): + query = urlparse(self.path).query + params = dict(qc.split("=") for qc in query.split("&")) + + if self.path.startswith("/get_meter_consumption"): + # Set response status code + self.send_response(200) + # Set headers + self.send_header("Content-type", "application/json") + self.end_headers() + response = request_get_response("get_meter_consumption", params) + if response.ok: + self.wfile.write(to_response(response, "meter_consump")) + return + + elif self.path.startswith("/get_meter_status"): + # Set response status code + self.send_response(200) + # Set headers + self.send_header("Content-type", "application/json") + self.end_headers() + response = request_get_response("get_meter_status", params) + if response.ok: + self.wfile.write(to_response(response, "meter_status")) + return + + elif self.path.startswith("/get_meter_info"): + # Set response status code + self.send_response(200) + # Set headers + self.send_header("Content-type", "application/json") + self.end_headers() + response = request_get_response("get_meter_info", params) + if response.ok: + self.wfile.write(to_response(response, "meter_info")) + return + else: + self.send_response(404) + self.send_header("Content-type", "text/plain") + self.end_headers() + +def request_get_response(api, params): + print(f"Calling API: {api}") + url = f"{han_host}/" + f"{api}" + response = requests.get(url, json=params) + print(f"Response: {response.text}") + return response + +def to_response(response: requests.Response, result_name: str): + result = response.json() + output = json.dumps({ + "Status": result["Status"], + result_name: json.loads(result[result_name]), + }) + return output.encode("utf8") + +if __name__ == "__main__": + server_address = ("", 8000) + httpd = HTTPServer(server_address, RequestHandler) + print("Secure server started on port 8000...") + httpd.serve_forever() \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index b2e1d71c..9f207a4e 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -22,8 +22,7 @@ nav: - ./repairs/account_not_found.md - ./repairs/invalid_target_rate.md - ./repairs/octopus_mini_not_valid.md - - ./repairs/unknown_tariff_format.md - - ./repairs/unknown_tariff.md + - ./repairs/unknown_product.md - Community: community.md - blueprints.md - faq.md diff --git a/tests/integration/api_client/test_get_electricity_rates.py b/tests/integration/api_client/test_get_electricity_rates.py index 1054d6fb..3b125247 100644 --- a/tests/integration/api_client/test_get_electricity_rates.py +++ b/tests/integration/api_client/test_get_electricity_rates.py @@ -9,14 +9,14 @@ default_period_from = datetime.strptime("2022-12-01T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z") default_period_to = datetime.strptime("2022-12-02T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z") -async def async_assert_electricity_data(tariff, is_smart_meter, price_cap, period_from = default_period_from, period_to = default_period_to, expected_rates = None): +async def async_assert_electricity_data(product_code, tariff_code, is_smart_meter, price_cap, period_from = default_period_from, period_to = default_period_to, expected_rates = None): # Arrange context = get_test_context() client = OctopusEnergyApiClient(context.api_key, price_cap) # Act - data = await client.async_get_electricity_rates(tariff, is_smart_meter, period_from, period_to) + data = await client.async_get_electricity_rates(product_code, tariff_code, is_smart_meter, period_from, period_to) diff = period_to - period_from @@ -51,22 +51,24 @@ async def async_assert_electricity_data(tariff, is_smart_meter, price_cap, perio return data @pytest.mark.asyncio -@pytest.mark.parametrize("tariff,price_cap,period_from,period_to",[ - ("E-1R-SUPER-GREEN-24M-21-07-30-A", None, datetime.strptime("2022-12-01T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2022-12-04T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z")), - ("E-1R-GO-18-06-12-A", None, datetime.strptime("2022-12-01T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2022-12-04T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z")), - ("E-1R-VAR-21-09-29-A", None, datetime.strptime("2022-12-01T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2022-12-04T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z")), - ("E-1R-AGILE-18-02-21-A", None, datetime.strptime("2022-12-01T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2022-12-04T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z")), - ("E-1R-AGILE-FLEX-22-11-25-D", None, datetime.strptime("2022-12-01T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2022-12-04T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z")), - ("E-1R-SILVER-FLEX-22-11-25-C", None, datetime.strptime("2023-07-01T00:00:00+01:00", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2023-07-02T00:00:00+01:00", "%Y-%m-%dT%H:%M:%S%z")), - ("E-1R-SUPER-GREEN-24M-21-07-30-A", 10, datetime.strptime("2022-12-01T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2022-12-04T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z")), - ("E-1R-GO-18-06-12-A", 10, datetime.strptime("2022-12-01T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2022-12-04T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z")), - ("E-1R-VAR-21-09-29-A", 10, datetime.strptime("2022-12-01T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2022-12-04T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z")), - ("E-1R-AGILE-18-02-21-A", 10, datetime.strptime("2022-12-01T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2022-12-04T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z")), - ("E-1R-AGILE-FLEX-22-11-25-D", 10, datetime.strptime("2022-12-01T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2022-12-04T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z")), - ("E-1R-SILVER-FLEX-22-11-25-C", 10, datetime.strptime("2023-07-01T00:00:00+01:00", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2023-07-04T00:00:00+01:00", "%Y-%m-%dT%H:%M:%S%z")), +@pytest.mark.parametrize("product_code,tariff_code,price_cap,period_from,period_to",[ + ("SUPER-GREEN-24M-21-07-30", "E-1R-SUPER-GREEN-24M-21-07-30-A", None, datetime.strptime("2022-12-01T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2022-12-04T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z")), + ("GO-18-06-12", "E-1R-GO-18-06-12-A", None, datetime.strptime("2022-12-01T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2022-12-04T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z")), + ("VAR-21-09-29", "E-1R-VAR-21-09-29-A", None, datetime.strptime("2022-12-01T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2022-12-04T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z")), + ("AGILE-18-02-21", "E-1R-AGILE-18-02-21-A", None, datetime.strptime("2022-12-01T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2022-12-04T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z")), + ("AGILE-FLEX-22-11-25", "E-1R-AGILE-FLEX-22-11-25-D", None, datetime.strptime("2022-12-01T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2022-12-04T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z")), + ("SILVER-FLEX-22-11-25", "E-1R-SILVER-FLEX-22-11-25-C", None, datetime.strptime("2023-07-01T00:00:00+01:00", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2023-07-02T00:00:00+01:00", "%Y-%m-%dT%H:%M:%S%z")), + ("BUS-PANELP-12M-FIXED-SEPTEMBER2022", "BUS-PANELP-12M-FIXED-SEPTEMBER2029", None, datetime.strptime("2023-07-01T00:00:00+01:00", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2023-07-02T00:00:00+01:00", "%Y-%m-%dT%H:%M:%S%z")), + ("SUPER-GREEN-24M-21-07-30", "E-1R-SUPER-GREEN-24M-21-07-30-A", 10, datetime.strptime("2022-12-01T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2022-12-04T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z")), + ("GO-18-06-12", "E-1R-GO-18-06-12-A", 10, datetime.strptime("2022-12-01T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2022-12-04T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z")), + ("VAR-21-09-29", "E-1R-VAR-21-09-29-A", 10, datetime.strptime("2022-12-01T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2022-12-04T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z")), + ("AGILE-18-02-21", "E-1R-AGILE-18-02-21-A", 10, datetime.strptime("2022-12-01T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2022-12-04T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z")), + ("AGILE-FLEX-22-11-25", "E-1R-AGILE-FLEX-22-11-25-D", 10, datetime.strptime("2022-12-01T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2022-12-04T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z")), + ("SILVER-FLEX-22-11-25", "E-1R-SILVER-FLEX-22-11-25-C", 10, datetime.strptime("2023-07-01T00:00:00+01:00", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2023-07-04T00:00:00+01:00", "%Y-%m-%dT%H:%M:%S%z")), + ("BUS-PANELP-12M-FIXED-SEPTEMBER2022", "BUS-PANELP-12M-FIXED-SEPTEMBER2029", 10, datetime.strptime("2023-07-01T00:00:00+01:00", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2023-07-04T00:00:00+01:00", "%Y-%m-%dT%H:%M:%S%z")), ]) -async def test_when_get_electricity_rates_is_called_with_tariff_then_data_is_returned_in_thirty_minute_increments(tariff, price_cap, period_from,period_to): - await async_assert_electricity_data(tariff, False, price_cap, period_from, period_to) +async def test_when_get_electricity_rates_is_called_with_tariff_then_data_is_returned_in_thirty_minute_increments(product_code, tariff_code, price_cap, period_from,period_to): + await async_assert_electricity_data(product_code, tariff_code, False, price_cap, period_from, period_to) @pytest.mark.asyncio @pytest.mark.parametrize("price_cap",[ @@ -106,6 +108,7 @@ async def test_when_get_electricity_rates_is_called_with_flux_tariff_then_data_i }] await async_assert_electricity_data( + "FLUX-IMPORT-23-02-14", "E-1R-FLUX-IMPORT-23-02-14-E", False, price_cap, @@ -117,8 +120,9 @@ async def test_when_get_electricity_rates_is_called_with_flux_tariff_then_data_i @pytest.mark.asyncio @pytest.mark.parametrize("price_cap",[(None), (15)]) async def test_when_get_electricity_rates_is_called_with_duel_rate_tariff_dumb_meter_then_data_is_returned_in_thirty_minute_increments(price_cap): - tariff = "E-2R-SUPER-GREEN-24M-21-07-30-A" - data = await async_assert_electricity_data(tariff, False, price_cap) + product_code = "SUPER-GREEN-24M-21-07-30" + tariff_code = "E-2R-SUPER-GREEN-24M-21-07-30-A" + data = await async_assert_electricity_data(product_code, tariff_code, False, price_cap) cheapest_rate_from = datetime.strptime("2022-12-01T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z") cheapest_rate_to = datetime.strptime("2022-12-01T07:00:00Z", "%Y-%m-%dT%H:%M:%S%z") @@ -141,8 +145,9 @@ async def test_when_get_electricity_rates_is_called_with_duel_rate_tariff_dumb_m @pytest.mark.asyncio @pytest.mark.parametrize("price_cap",[(None), (15)]) async def test_when_get_electricity_rates_is_called_with_duel_rate_tariff_smart_meter_then_data_is_returned_in_thirty_minute_increments(price_cap): - tariff = "E-2R-SUPER-GREEN-24M-21-07-30-A" - data = await async_assert_electricity_data(tariff, True, price_cap) + product_code = "SUPER-GREEN-24M-21-07-30" + tariff_code = "E-2R-SUPER-GREEN-24M-21-07-30-A" + data = await async_assert_electricity_data(product_code, tariff_code, True, price_cap) cheapest_rate_from = datetime.strptime("2022-12-01T00:30:00Z", "%Y-%m-%dT%H:%M:%S%z") cheapest_rate_to = datetime.strptime("2022-12-01T07:30:00Z", "%Y-%m-%dT%H:%M:%S%z") @@ -163,15 +168,20 @@ async def test_when_get_electricity_rates_is_called_with_duel_rate_tariff_smart_ assert item["value_inc_vat"] != cheapest_rate @pytest.mark.asyncio -@pytest.mark.parametrize("tariff",[("E-2R-NOT-A-TARIFF-A"), ("E-1R-NOT-A-TARIFF-A"), ("NOT-A-TARIFF")]) -async def test_when_get_electricity_rates_is_called_for_non_existent_tariff_then_none_is_returned(tariff): +@pytest.mark.parametrize("product_code,tariff_code",[ + ("SUPER-GREEN-24M-21-07-30", "E-2R-NOT-A-TARIFF-A"), + ("SUPER-GREEN-24M-21-07-30", "E-1R-NOT-A-TARIFF-A"), + ("SUPER-GREEN-24M-21-07-30", "NOT-A-TARIFF"), + ("NOT-A-PRODUCT", "E-1R-SUPER-GREEN-24M-21-07-30-A") +]) +async def test_when_get_electricity_rates_is_called_for_non_existent_tariff_then_none_is_returned(product_code, tariff_code): # Arrange context = get_test_context() client = OctopusEnergyApiClient(context.api_key) # Act - data = await client.async_get_electricity_rates(tariff, True, default_period_from, default_period_to) + data = await client.async_get_electricity_rates(product_code, tariff_code, True, default_period_from, default_period_to) # Assert assert data is None @@ -179,12 +189,13 @@ async def test_when_get_electricity_rates_is_called_for_non_existent_tariff_then @pytest.mark.asyncio async def test_when_get_electricity_rates_is_called_with_cosy_tariff_then_data_is_returned_in_thirty_minute_increments(): # Arrange - tariff = "E-1R-COSY-22-12-08-H" + product_code = "COSY-22-12-08" + tariff_code = "E-1R-COSY-22-12-08-H" period_from = datetime.strptime("2023-10-15T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z") period_to = datetime.strptime("2023-10-17T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z") # Act - data = await async_assert_electricity_data(tariff, False, None, period_from, period_to) + data = await async_assert_electricity_data(product_code, tariff_code, False, None, period_from, period_to) # Assert cheapest_rate = None diff --git a/tests/integration/api_client/test_get_electricity_standing_charge.py b/tests/integration/api_client/test_get_electricity_standing_charge.py index 5203372d..51efb00b 100644 --- a/tests/integration/api_client/test_get_electricity_standing_charge.py +++ b/tests/integration/api_client/test_get_electricity_standing_charge.py @@ -10,21 +10,21 @@ period_to = datetime.strptime("2022-12-02T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z") @pytest.mark.asyncio -@pytest.mark.parametrize("tariff,expected_value_inc_vat",[ - ("E-1R-SUPER-GREEN-24M-21-07-30-A", 24.0135), - ("E-1R-GO-18-06-12-A", 25.0005), - ("E-1R-VAR-21-09-29-A", 37.29243), - ("E-1R-AGILE-18-02-21-A", 21.0), - ("E-1R-AGILE-FLEX-22-11-25-D", 46.956) +@pytest.mark.parametrize("product_code,tariff_code,expected_value_inc_vat",[ + ("SUPER-GREEN-24M-21-07-30", "E-1R-SUPER-GREEN-24M-21-07-30-A", 24.0135), + ("GO-18-06-12", "E-1R-GO-18-06-12-A", 25.0005), + ("VAR-21-09-29", "E-1R-VAR-21-09-29-A", 37.29243), + ("AGILE-18-02-21", "E-1R-AGILE-18-02-21-A", 21.0), + ("AGILE-FLEX-22-11-25", "E-1R-AGILE-FLEX-22-11-25-D", 46.956) ]) -async def test_when_get_electricity_standing_charge_is_called_for_existent_tariff_then_rates_are_returned(tariff, expected_value_inc_vat): +async def test_when_get_electricity_standing_charge_is_called_for_existent_tariff_then_rates_are_returned(product_code, tariff_code, expected_value_inc_vat): # Arrange context = get_test_context() client = OctopusEnergyApiClient(context.api_key) # Act - result = await client.async_get_electricity_standing_charge(tariff, period_from, period_to) + result = await client.async_get_electricity_standing_charge(product_code, tariff_code, period_from, period_to) # Assert assert result is not None @@ -32,14 +32,14 @@ async def test_when_get_electricity_standing_charge_is_called_for_existent_tarif assert result["value_inc_vat"] == expected_value_inc_vat @pytest.mark.asyncio -@pytest.mark.parametrize("tariff",[("E-1R-SILVER-FLEX-22-11-25-C")]) -async def test_when_get_electricity_standing_charge_is_called_with_tracker_tariff_then_rates_are_returned(tariff): +@pytest.mark.parametrize("product_code,tariff_code",[("SILVER-FLEX-22-11-25", "E-1R-SILVER-FLEX-22-11-25-C")]) +async def test_when_get_electricity_standing_charge_is_called_with_tracker_tariff_then_rates_are_returned(product_code, tariff_code): # Arrange context = get_test_context() client = OctopusEnergyApiClient(context.api_key) # Act - result = await client.async_get_electricity_standing_charge(tariff, period_from, period_to) + result = await client.async_get_electricity_standing_charge(product_code, tariff_code, period_from, period_to) # Assert assert result is not None @@ -47,15 +47,19 @@ async def test_when_get_electricity_standing_charge_is_called_with_tracker_tarif assert result["value_inc_vat"] is not None @pytest.mark.asyncio -@pytest.mark.parametrize("tariff",[("E-1R-NOT-A-TARIFF-A"), ("NOT-A-TARIFF")]) -async def test_when_get_electricity_standing_charge_is_called_for_non_existent_tariff_then_none_is_returned(tariff): +@pytest.mark.parametrize("product_code,tariff_code",[ + ("NOT-A-PRODUCT", "E-1R-NOT-A-TARIFF-A"), + ("AGILE-FLEX-22-11-25", "NOT-A-TARIFF"), + ("AGILE-FLEX-22-11-25", "E-1R-NOT-A-PRODUCT-D") +]) +async def test_when_get_electricity_standing_charge_is_called_for_non_existent_tariff_then_none_is_returned(product_code, tariff_code): # Arrange context = get_test_context() client = OctopusEnergyApiClient(context.api_key) # Act - result = await client.async_get_electricity_standing_charge(tariff, period_from, period_to) + result = await client.async_get_electricity_standing_charge(product_code, tariff_code, period_from, period_to) # Assert assert result is None \ No newline at end of file diff --git a/tests/integration/api_client/test_get_gas_rates.py b/tests/integration/api_client/test_get_gas_rates.py index 85896b0b..a3d6d5d6 100644 --- a/tests/integration/api_client/test_get_gas_rates.py +++ b/tests/integration/api_client/test_get_gas_rates.py @@ -7,20 +7,20 @@ from custom_components.octopus_energy.api_client import OctopusEnergyApiClient @pytest.mark.asyncio -@pytest.mark.parametrize("tariff,price_cap,period_from,period_to",[ - ("G-1R-SUPER-GREEN-24M-21-07-30-A", None, datetime.strptime("2021-12-01T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2021-12-02T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z")), - ("G-1R-SUPER-GREEN-24M-21-07-30-A", 2, datetime.strptime("2021-12-01T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2021-12-02T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z")), - ("G-1R-SILVER-FLEX-22-11-25-C", None, datetime.strptime("2023-06-01T00:00:00+01:00", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2023-06-02T00:00:00+01:00", "%Y-%m-%dT%H:%M:%S%z")), - ("G-1R-SILVER-FLEX-22-11-25-C", 2, datetime.strptime("2023-06-01T00:00:00+01:00", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2023-06-02T00:00:00+01:00", "%Y-%m-%dT%H:%M:%S%z")), +@pytest.mark.parametrize("product_code,tariff_code,price_cap,period_from,period_to",[ + ("SUPER-GREEN-24M-21-07-30", "G-1R-SUPER-GREEN-24M-21-07-30-A", None, datetime.strptime("2021-12-01T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2021-12-02T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z")), + ("SUPER-GREEN-24M-21-07-30", "G-1R-SUPER-GREEN-24M-21-07-30-A", 2, datetime.strptime("2021-12-01T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2021-12-02T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z")), + ("SILVER-FLEX-22-11-25", "G-1R-SILVER-FLEX-22-11-25-C", None, datetime.strptime("2023-06-01T00:00:00+01:00", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2023-06-02T00:00:00+01:00", "%Y-%m-%dT%H:%M:%S%z")), + ("SILVER-FLEX-22-11-25", "G-1R-SILVER-FLEX-22-11-25-C", 2, datetime.strptime("2023-06-01T00:00:00+01:00", "%Y-%m-%dT%H:%M:%S%z"), datetime.strptime("2023-06-02T00:00:00+01:00", "%Y-%m-%dT%H:%M:%S%z")), ]) -async def test_when_get_gas_rates_is_called_for_existent_tariff_then_rates_are_returned(tariff, price_cap, period_from, period_to): +async def test_when_get_gas_rates_is_called_for_existent_tariff_then_rates_are_returned(product_code, tariff_code, price_cap, period_from, period_to): # Arrange context = get_test_context() client = OctopusEnergyApiClient(context.api_key, None, price_cap) # Act - data = await client.async_get_gas_rates(tariff, period_from, period_to) + data = await client.async_get_gas_rates(product_code, tariff_code, period_from, period_to) # Assert assert data is not None @@ -43,8 +43,12 @@ async def test_when_get_gas_rates_is_called_for_existent_tariff_then_rates_are_r expected_valid_from = expected_valid_to @pytest.mark.asyncio -@pytest.mark.parametrize("tariff",[("G-1R-NOT-A-TARIFF-A"), ("NOT-A-TARIFF")]) -async def test_when_get_gas_rates_is_called_for_non_existent_tariff_then_none_is_returned(tariff): +@pytest.mark.parametrize("product_code,tariff_code",[ + ("NOT-A-PRODUCT", "G-1R-NOT-A-PRODUCT-A"), + ("SUPER-GREEN-24M-21-07-30", "NOT-A-TARIFF"), + ("NOT-A-PRODUCT", "G-1R-SUPER-GREEN-24M-21-07-30-A") +]) +async def test_when_get_gas_rates_is_called_for_non_existent_tariff_then_none_is_returned(product_code, tariff_code): # Arrange context = get_test_context() period_from = now().replace(hour=0, minute=0, second=0, microsecond=0) @@ -53,7 +57,7 @@ async def test_when_get_gas_rates_is_called_for_non_existent_tariff_then_none_is client = OctopusEnergyApiClient(context.api_key) # Act - data = await client.async_get_gas_rates(tariff, period_from, period_to) + data = await client.async_get_gas_rates(product_code, tariff_code, period_from, period_to) # Assert assert data is None \ No newline at end of file diff --git a/tests/integration/api_client/test_get_gas_standing_charge.py b/tests/integration/api_client/test_get_gas_standing_charge.py index 23103ab0..65d3fe03 100644 --- a/tests/integration/api_client/test_get_gas_standing_charge.py +++ b/tests/integration/api_client/test_get_gas_standing_charge.py @@ -10,15 +10,15 @@ period_to = datetime.strptime("2021-12-02T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z") @pytest.mark.asyncio -@pytest.mark.parametrize("tariff",[("G-1R-SUPER-GREEN-24M-21-07-30-A")]) -async def test_when_get_gas_standing_charge_is_called_for_existent_tariff_then_rates_are_returned(tariff): +@pytest.mark.parametrize("product_code,tariff_code",[("SUPER-GREEN-24M-21-07-30", "G-1R-SUPER-GREEN-24M-21-07-30-A")]) +async def test_when_get_gas_standing_charge_is_called_for_existent_tariff_then_rates_are_returned(product_code, tariff_code): # Arrange context = get_test_context() client = OctopusEnergyApiClient(context.api_key) # Act - result = await client.async_get_gas_standing_charge(tariff, period_from, period_to) + result = await client.async_get_gas_standing_charge(product_code, tariff_code, period_from, period_to) # Assert assert result is not None @@ -26,8 +26,8 @@ async def test_when_get_gas_standing_charge_is_called_for_existent_tariff_then_r assert result["value_inc_vat"] == 26.586 @pytest.mark.asyncio -@pytest.mark.parametrize("tariff",[("G-1R-SILVER-FLEX-22-11-25-C")]) -async def test_when_get_gas_standing_charge_is_called_with_tracker_tariff_then_rates_are_returned(tariff): +@pytest.mark.parametrize("product_code,tariff_code",[("SILVER-FLEX-22-11-25", "G-1R-SILVER-FLEX-22-11-25-C")]) +async def test_when_get_gas_standing_charge_is_called_with_tracker_tariff_then_rates_are_returned(product_code, tariff_code): # Arrange context = get_test_context() client = OctopusEnergyApiClient(context.api_key) @@ -36,7 +36,7 @@ async def test_when_get_gas_standing_charge_is_called_with_tracker_tariff_then_r period_to = datetime.strptime("2022-12-02T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z") # Act - result = await client.async_get_gas_standing_charge(tariff, period_from, period_to) + result = await client.async_get_gas_standing_charge(product_code, tariff_code, period_from, period_to) # Assert assert result is not None @@ -44,15 +44,19 @@ async def test_when_get_gas_standing_charge_is_called_with_tracker_tariff_then_r assert result["value_inc_vat"] is not None @pytest.mark.asyncio -@pytest.mark.parametrize("tariff",[("G-1R-NOT-A-TARIFF-A"), ("NOT-A-TARIFF")]) -async def test_when_get_gas_standing_charge_is_called_for_non_existent_tariff_then_none_is_returned(tariff): +@pytest.mark.parametrize("product_code,tariff_code",[ + ("SUPER-GREEN-24M-21-07-30", "G-1R-NOT-A-TARIFF-A"), + ("SUPER-GREEN-24M-21-07-30", "NOT-A-TARIFF"), + ("NOT-A-PRODUCT", "G-1R-SILVER-FLEX-22-11-25-C") +]) +async def test_when_get_gas_standing_charge_is_called_for_non_existent_tariff_then_none_is_returned(product_code, tariff_code): # Arrange context = get_test_context() client = OctopusEnergyApiClient(context.api_key) # Act - result = await client.async_get_gas_standing_charge(tariff, period_from, period_to) + result = await client.async_get_gas_standing_charge(product_code, tariff_code, period_from, period_to) # Assert assert result is None \ No newline at end of file diff --git a/tests/integration/electricity/test_calculate_electricity_consumption_and_cost.py b/tests/integration/electricity/test_calculate_electricity_consumption_and_cost.py index d99d0b1d..fd494f55 100644 --- a/tests/integration/electricity/test_calculate_electricity_consumption_and_cost.py +++ b/tests/integration/electricity/test_calculate_electricity_consumption_and_cost.py @@ -17,6 +17,7 @@ async def test_when_calculate_electricity_cost_uses_real_data_then_calculation_r period_from = datetime.strptime("2022-02-28T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z") period_to = datetime.strptime("2022-03-01T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z") + expected_product_code = "SUPER-GREEN-24M-21-07-30" expected_tariff_code = "E-1R-SUPER-GREEN-24M-21-07-30-L" latest_date = None is_smart_meter = True @@ -49,11 +50,11 @@ def fire_event(name, metadata): assert consumption_and_rates_result is not None # Make sure we have rates and standing charges available - rates = await client.async_get_electricity_rates(expected_tariff_code, False, period_from, period_to) + rates = await client.async_get_electricity_rates(expected_product_code, expected_tariff_code, False, period_from, period_to) assert rates is not None assert len(rates) > 0 - standard_charge_result = await client.async_get_electricity_standing_charge(expected_tariff_code, period_from, period_to) + standard_charge_result = await client.async_get_electricity_standing_charge(expected_product_code, expected_tariff_code, period_from, period_to) assert standard_charge_result is not None # Act diff --git a/tests/integration/gas/test_calculate_gas_consumption_and_cost.py b/tests/integration/gas/test_calculate_gas_consumption_and_cost.py index 37b8a218..4f7f7db1 100644 --- a/tests/integration/gas/test_calculate_gas_consumption_and_cost.py +++ b/tests/integration/gas/test_calculate_gas_consumption_and_cost.py @@ -21,6 +21,7 @@ async def test_when_calculate_gas_cost_using_real_data_then_calculation_returned period_from = datetime.strptime("2022-02-28T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z") period_to = datetime.strptime("2022-03-01T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z") + expected_product_code = "SUPER-GREEN-24M-21-07-30" expected_tariff_code = "G-1R-SUPER-GREEN-24M-21-07-30-L" latest_date = None @@ -53,7 +54,7 @@ def fire_event(name, metadata): # Make sure we have standing charges available - standard_charge_result = await client.async_get_gas_standing_charge(expected_tariff_code, period_from, period_to) + standard_charge_result = await client.async_get_gas_standing_charge(expected_product_code, expected_tariff_code, period_from, period_to) assert standard_charge_result is not None # Act diff --git a/tests/unit/config/test_validate_main_config.py b/tests/unit/config/test_validate_main_config.py index e0f4d9a7..c4c20891 100644 --- a/tests/unit/config/test_validate_main_config.py +++ b/tests/unit/config/test_validate_main_config.py @@ -31,7 +31,7 @@ def get_account_info(tariff_code: str = "E-1R-SUPER-GREEN-24M-21-07-30-C"): "start": "2023-08-01T00:00:00+01:00", "end": "2023-09-01T00:00:00+01:00", "tariff_code": tariff_code, - "product": "SUPER-GREEN-24M-21-07-30" + "product_code": "SUPER-GREEN-24M-21-07-30" } ] } diff --git a/tests/unit/config/test_validate_target_rate_config.py b/tests/unit/config/test_validate_target_rate_config.py index fca38f3f..ad9e9820 100644 --- a/tests/unit/config/test_validate_target_rate_config.py +++ b/tests/unit/config/test_validate_target_rate_config.py @@ -20,7 +20,7 @@ def get_account_info(tariff_code: str = "E-1R-SUPER-GREEN-24M-21-07-30-C", is_ac "start": "2023-08-01T00:00:00+01:00" if is_active_agreement else "2023-01-01T00:00:00+01:00", "end": "2023-09-01T00:00:00+01:00" if is_active_agreement else "2023-02-01T00:00:00+01:00", "tariff_code": tariff_code, - "product": "SUPER-GREEN-24M-21-07-30" + "product_code": "SUPER-GREEN-24M-21-07-30" } ] } diff --git a/tests/unit/coordinators/test_async_refresh_electricity_rates_data.py b/tests/unit/coordinators/test_async_refresh_electricity_rates_data.py index aacfee7b..85d82b5b 100644 --- a/tests/unit/coordinators/test_async_refresh_electricity_rates_data.py +++ b/tests/unit/coordinators/test_async_refresh_electricity_rates_data.py @@ -18,7 +18,7 @@ mpan = "1234567890" serial_number = "abcdefgh" -def get_account_info(is_active_agreement = True, tariff_code = "E-1R-SUPER-GREEN-24M-21-07-30-A"): +def get_account_info(is_active_agreement = True, tariff_code = "E-1R-SUPER-GREEN-24M-21-07-30-A", product_code = "SUPER-GREEN-24M-21-07-30"): return { "electricity_meter_points": [ { @@ -39,7 +39,7 @@ def get_account_info(is_active_agreement = True, tariff_code = "E-1R-SUPER-GREEN "start": "2023-07-01T00:00:00+01:00" if is_active_agreement else "2023-08-01T00:00:00+01:00", "end": "2023-08-01T00:00:00+01:00" if is_active_agreement else "2023-09-01T00:00:00+01:00", "tariff_code": tariff_code, - "product": "SUPER-GREEN-24M-21-07-30" + "product_code": product_code } ] } @@ -224,7 +224,7 @@ async def test_when_existing_rates_is_none_then_rates_retrieved(existing_rates): async def async_mocked_get_electricity_rates(*args, **kwargs): nonlocal requested_period_from, requested_period_to, mock_api_called, expected_rates - requested_client, requested_tariff_code, is_smart_meter, requested_period_from, requested_period_to = args + requested_client, requested_product_code, requested_tariff_code, is_smart_meter, requested_period_from, requested_period_to = args mock_api_called = True return expected_rates @@ -293,7 +293,7 @@ async def test_when_dispatches_is_not_defined_and_existing_rates_is_none_then_ra async def async_mocked_get_electricity_rates(*args, **kwargs): nonlocal requested_period_from, requested_period_to, mock_api_called, expected_rates - requested_client, requested_tariff_code, is_smart_meter, requested_period_from, requested_period_to = args + requested_client, requested_product_code, requested_tariff_code, is_smart_meter, requested_period_from, requested_period_to = args mock_api_called = True return expected_rates @@ -813,7 +813,7 @@ def fire_event(name, metadata): actual_fired_events[name] = metadata return None - account_info = get_account_info(tariff_code="E-1R-INTELLI-VAR-22-10-14-C") + account_info = get_account_info(product_code="INTELLI-VAR-22-10-14") existing_rates = ElectricityRatesCoordinatorResult(period_to - timedelta(days=60), 1, create_rate_data(period_from - timedelta(days=60), period_to - timedelta(days=60), [2, 4])) dispatches_result = None diff --git a/tests/unit/coordinators/test_async_refresh_electricity_standing_charge_data.py b/tests/unit/coordinators/test_async_refresh_electricity_standing_charge_data.py index 89cc8443..8dbc5eed 100644 --- a/tests/unit/coordinators/test_async_refresh_electricity_standing_charge_data.py +++ b/tests/unit/coordinators/test_async_refresh_electricity_standing_charge_data.py @@ -37,7 +37,7 @@ def get_account_info(is_active_agreement = True): "start": "2023-07-01T00:00:00+01:00" if is_active_agreement else "2023-08-01T00:00:00+01:00", "end": "2023-08-01T00:00:00+01:00" if is_active_agreement else "2023-09-01T00:00:00+01:00", "tariff_code": tariff_code, - "product": "SUPER-GREEN-24M-21-07-30" + "product_code": "SUPER-GREEN-24M-21-07-30" } ] } @@ -160,7 +160,7 @@ async def test_when_existing_standing_charge_is_none_then_standing_charge_retrie async def async_mocked_get_electricity_standing_charge(*args, **kwargs): nonlocal requested_period_from, requested_period_to, mock_api_called, expected_standing_charge - requested_client, requested_tariff_code, requested_period_from, requested_period_to = args + requested_client, requested_product_code, requested_tariff_code, requested_period_from, requested_period_to = args mock_api_called = True return expected_standing_charge diff --git a/tests/unit/coordinators/test_async_refresh_gas_rates_data.py b/tests/unit/coordinators/test_async_refresh_gas_rates_data.py index 0ba6a1b9..1e12049e 100644 --- a/tests/unit/coordinators/test_async_refresh_gas_rates_data.py +++ b/tests/unit/coordinators/test_async_refresh_gas_rates_data.py @@ -37,7 +37,7 @@ def get_account_info(is_active_agreement = True): "start": "2023-07-01T00:00:00+01:00" if is_active_agreement else "2023-08-01T00:00:00+01:00", "end": "2023-08-01T00:00:00+01:00" if is_active_agreement else "2023-09-01T00:00:00+01:00", "tariff_code": tariff_code, - "product": "SUPER-GREEN-24M-21-07-30" + "product_code": "SUPER-GREEN-24M-21-07-30" } ] } @@ -199,7 +199,7 @@ async def test_when_existing_rates_is_none_then_rates_retrieved(existing_rates): async def async_mocked_get_gas_rates(*args, **kwargs): nonlocal requested_period_from, requested_period_to, mock_api_called - requested_client, requested_tariff_code, requested_period_from, requested_period_to = args + requested_client, requested_product_code, requested_tariff_code, requested_period_from, requested_period_to = args mock_api_called = True return expected_rates diff --git a/tests/unit/coordinators/test_async_refresh_gas_standing_charge_data.py b/tests/unit/coordinators/test_async_refresh_gas_standing_charge_data.py index f52307ef..adff3a3c 100644 --- a/tests/unit/coordinators/test_async_refresh_gas_standing_charge_data.py +++ b/tests/unit/coordinators/test_async_refresh_gas_standing_charge_data.py @@ -37,7 +37,7 @@ def get_account_info(is_active_agreement = True): "start": "2023-07-01T00:00:00+01:00" if is_active_agreement else "2023-08-01T00:00:00+01:00", "end": "2023-08-01T00:00:00+01:00" if is_active_agreement else "2023-09-01T00:00:00+01:00", "tariff_code": tariff_code, - "product": "SUPER-GREEN-24M-21-07-30" + "product_code": "SUPER-GREEN-24M-21-07-30" } ] } @@ -159,7 +159,7 @@ async def test_when_existing_standing_charge_is_none_then_standing_charge_retrie async def async_mocked_get_gas_standing_charge(*args, **kwargs): nonlocal requested_period_from, requested_period_to, mock_api_called, expected_standing_charge - requested_client, requested_tariff_code, requested_period_from, requested_period_to = args + requested_client, requested_rate_product_code, requested_tariff_code, requested_period_from, requested_period_to = args mock_api_called = True return expected_standing_charge diff --git a/tests/unit/coordinators/test_async_refresh_intelligent_dispatches.py b/tests/unit/coordinators/test_async_refresh_intelligent_dispatches.py index c4197bbf..85d45bd2 100644 --- a/tests/unit/coordinators/test_async_refresh_intelligent_dispatches.py +++ b/tests/unit/coordinators/test_async_refresh_intelligent_dispatches.py @@ -12,13 +12,14 @@ current = datetime.strptime("2023-07-14T10:30:01+01:00", "%Y-%m-%dT%H:%M:%S%z") last_retrieved = datetime.strptime("2023-07-14T00:00:00+01:00", "%Y-%m-%dT%H:%M:%S%z") +product_code = "INTELLI-VAR-22-10-14" tariff_code = "E-1R-INTELLI-VAR-22-10-14-C" mpan = "1234567890" serial_number = "abcdefgh" intelligent_device = IntelligentDevice("1", "2", "3", "4", 1, "5", "6", 2) -def get_account_info(is_active_agreement = True, active_tariff_code = tariff_code): +def get_account_info(is_active_agreement = True, active_product_code = product_code, active_tariff_code = tariff_code): return { "id": "A-XXXXXX", "electricity_meter_points": [ @@ -40,7 +41,7 @@ def get_account_info(is_active_agreement = True, active_tariff_code = tariff_cod "start": "2023-07-01T00:00:00+01:00" if is_active_agreement else "2023-08-01T00:00:00+01:00", "end": "2023-08-01T00:00:00+01:00" if is_active_agreement else "2023-09-01T00:00:00+01:00", "tariff_code": active_tariff_code, - "product": "SUPER-GREEN-24M-21-07-30" + "product_code": active_product_code } ] } @@ -91,7 +92,7 @@ async def async_merge_dispatch_data(*args, **kwargs): account_id, completed_dispatches = args return completed_dispatches - account_info = get_account_info(True, "E-1R-GO-18-06-12-A") + account_info = get_account_info(True, active_product_code="GO-18-06-12") existing_settings = None with mock.patch.multiple(OctopusEnergyApiClient, async_get_intelligent_dispatches=async_mock_get_intelligent_dispatches): @@ -123,7 +124,7 @@ async def async_merge_dispatch_data(*args, **kwargs): account_id, completed_dispatches = args return completed_dispatches - account_info = get_account_info(True, "E-1R-GO-18-06-12-A") + account_info = get_account_info(True, active_product_code="GO-18-06-12") existing_settings = None with mock.patch.multiple(OctopusEnergyApiClient, async_get_intelligent_dispatches=async_mock_get_intelligent_dispatches): diff --git a/tests/unit/coordinators/test_async_refresh_intelligent_settings.py b/tests/unit/coordinators/test_async_refresh_intelligent_settings.py index 9c440abe..6ec1c32e 100644 --- a/tests/unit/coordinators/test_async_refresh_intelligent_settings.py +++ b/tests/unit/coordinators/test_async_refresh_intelligent_settings.py @@ -11,11 +11,12 @@ current = datetime.strptime("2023-07-14T10:30:01+01:00", "%Y-%m-%dT%H:%M:%S%z") last_retrieved = datetime.strptime("2023-07-14T00:00:00+01:00", "%Y-%m-%dT%H:%M:%S%z") +product_code = "INTELLI-VAR-22-10-14" tariff_code = "E-1R-INTELLI-VAR-22-10-14-C" mpan = "1234567890" serial_number = "abcdefgh" -def get_account_info(is_active_agreement = True, active_tariff_code = tariff_code): +def get_account_info(is_active_agreement = True, active_product_code = product_code, active_tariff_code = tariff_code): return { "id": "A-XXXXXX", "electricity_meter_points": [ @@ -37,7 +38,7 @@ def get_account_info(is_active_agreement = True, active_tariff_code = tariff_cod "start": "2023-07-01T00:00:00+01:00" if is_active_agreement else "2023-08-01T00:00:00+01:00", "end": "2023-08-01T00:00:00+01:00" if is_active_agreement else "2023-09-01T00:00:00+01:00", "tariff_code": active_tariff_code, - "product": "SUPER-GREEN-24M-21-07-30" + "product_code": active_product_code } ] } @@ -90,7 +91,7 @@ async def async_mock_get_intelligent_settings(*args, **kwargs): mock_api_called = True return expected_settings - account_info = get_account_info(True, "E-1R-GO-18-06-12-A") + account_info = get_account_info(True, active_product_code="GO-18-06-12") existing_settings = None with mock.patch.multiple(OctopusEnergyApiClient, async_get_intelligent_settings=async_mock_get_intelligent_settings): diff --git a/tests/unit/coordinators/test_previous_consumption_and_rates.py b/tests/unit/coordinators/test_previous_consumption_and_rates.py index b0c6d394..859e256f 100644 --- a/tests/unit/coordinators/test_previous_consumption_and_rates.py +++ b/tests/unit/coordinators/test_previous_consumption_and_rates.py @@ -15,8 +15,14 @@ default_electricity_tariff_code = "E-1R-SUPER-GREEN-24M-21-07-30-A" default_gas_tariff_code = "G-1R-SUPER-GREEN-24M-21-07-30-A" - -def get_account_info(current: datetime, electricity_tariff_code = default_electricity_tariff_code, gas_tariff_code = default_gas_tariff_code): +default_electricity_product_code = "SUPER-GREEN-24M-21-07-30" +default_gas_product_code = "SUPER-GREEN-24M-21-07-30" + +def get_account_info(current: datetime, + electricity_product_code = default_electricity_product_code, + electricity_tariff_code = default_electricity_tariff_code, + gas_product_code = default_gas_product_code, + gas_tariff_code = default_gas_tariff_code): return { "electricity_meter_points": [ { @@ -30,17 +36,20 @@ def get_account_info(current: datetime, electricity_tariff_code = default_electr { "start": (current + timedelta(days=7)).isoformat(), "end": (current + timedelta(days=14)).isoformat(), - "tariff_code": "E-1R-FUTURE-TARIFF-A" + "tariff_code": "E-1R-FUTURE-TARIFF-A", + "product_code": "FUTURE-TARIFF" }, { "start": (current - timedelta(days=7)).isoformat(), "end": (current + timedelta(days=7)).isoformat(), - "tariff_code": electricity_tariff_code + "tariff_code": electricity_tariff_code, + "product_code": electricity_product_code }, { "start": (current - timedelta(days=14)).isoformat(), "end": (current - timedelta(days=7)).isoformat(), - "tariff_code": "E-1R-AGILE-TARIFF-A" + "tariff_code": "E-1R-AGILE-TARIFF-A", + "product_code": "AGILE-TARIFF" } ] } @@ -57,17 +66,20 @@ def get_account_info(current: datetime, electricity_tariff_code = default_electr { "start": (current + timedelta(days=7)).isoformat(), "end": (current + timedelta(days=14)).isoformat(), - "tariff_code": "G-1R-FUTURE-TARIFF-A" + "tariff_code": "G-1R-FUTURE-TARIFF-A", + "product_code": "FUTURE-TARIFF" }, { "start": (current - timedelta(days=7)).isoformat(), "end": (current + timedelta(days=7)).isoformat(), - "tariff_code": gas_tariff_code + "tariff_code": gas_tariff_code, + "product_code": gas_product_code }, { "start": (current - timedelta(days=14)).isoformat(), "end": (current - timedelta(days=7)).isoformat(), - "tariff_code": "G-1R-AGILE-TARIFF-A" + "tariff_code": "G-1R-AGILE-TARIFF-A", + "product_code": "AGILE-TARIFF" } ] } @@ -229,7 +241,7 @@ async def async_mocked_get_gas_consumption(*args, **kwargs): async def async_mocked_get_gas_rates(*args, **kwargs): nonlocal requested_rate_tariff_code - requested_client, requested_rate_tariff_code, period_from, period_to = args + requested_client, requested_rate_product_code, requested_rate_tariff_code, period_from, period_to = args return expected_rates expected_standing_charge = 100.2 @@ -237,7 +249,7 @@ async def async_mocked_get_gas_rates(*args, **kwargs): async def async_mocked_get_gas_standing_charge(*args, **kwargs): nonlocal requested_standing_charge_tariff_code - requested_client, requested_standing_charge_tariff_code, period_from, period_to = args + requested_client, requested_standing_charge_product_code, requested_standing_charge_tariff_code, period_from, period_to = args return { "value_inc_vat": expected_standing_charge } @@ -343,7 +355,7 @@ async def async_mocked_get_electricity_consumption(*args, **kwargs): async def async_mocked_get_electricity_rates(*args, **kwargs): nonlocal requested_rate_tariff_code - requested_client, requested_rate_tariff_code, is_smart_meter, period_from, period_to = args + requested_client, requested_product_code, requested_rate_tariff_code, is_smart_meter, period_from, period_to = args return expected_rates expected_standing_charge = 100.2 @@ -351,7 +363,7 @@ async def async_mocked_get_electricity_rates(*args, **kwargs): async def async_mocked_get_electricity_standing_charge(*args, **kwargs): nonlocal requested_standing_charge_tariff_code - requested_client, requested_standing_charge_tariff_code, period_from, period_to = args + requested_client, requested_standing_charge_product_code, requested_standing_charge_tariff_code, period_from, period_to = args return { "value_inc_vat": expected_standing_charge } @@ -870,7 +882,7 @@ def fire_event(name, metadata): current_utc_timestamp = datetime.strptime(f'2022-02-12T00:00:00Z', "%Y-%m-%dT%H:%M:%S%z") - account_info = get_account_info(period_from, "E-1R-INTELLI-BB-VAR-23-03-01-C") + account_info = get_account_info(period_from, electricity_product_code="INTELLI-BB-VAR-23-03-01", electricity_tariff_code="E-1R-INTELLI-BB-VAR-23-03-01-C") previous_data = PreviousConsumptionCoordinatorResult( current_utc_timestamp - timedelta(days=1), @@ -994,7 +1006,7 @@ def fire_event(name, metadata): current_utc_timestamp = datetime.strptime(f'2022-02-12T00:00:00Z', "%Y-%m-%dT%H:%M:%S%z") - account_info = get_account_info(period_from, "E-1R-INTELLI-BB-VAR-23-03-01-C") + account_info = get_account_info(period_from, electricity_product_code="INTELLI-BB-VAR-23-03-01", electricity_tariff_code="E-1R-INTELLI-BB-VAR-23-03-01-C") previous_data = PreviousConsumptionCoordinatorResult( current_utc_timestamp - timedelta(days=1), diff --git a/tests/unit/intelligent/test_has_intelligent_tariff.py b/tests/unit/intelligent/test_has_intelligent_tariff.py index a69571f3..8ffaedd9 100644 --- a/tests/unit/intelligent/test_has_intelligent_tariff.py +++ b/tests/unit/intelligent/test_has_intelligent_tariff.py @@ -5,7 +5,7 @@ current = datetime.strptime("2023-07-14T10:30:01+01:00", "%Y-%m-%dT%H:%M:%S%z") -def get_account_info(tariff_code: str, is_active_agreement = True): +def get_account_info(product_code: str, is_active_agreement = True): return { "electricity_meter_points": [ { @@ -25,8 +25,8 @@ def get_account_info(tariff_code: str, is_active_agreement = True): { "start": "2023-07-01T00:00:00+01:00" if is_active_agreement else "2023-08-01T00:00:00+01:00", "end": "2023-08-01T00:00:00+01:00" if is_active_agreement else "2023-09-01T00:00:00+01:00", - "tariff_code": tariff_code, - "product": "SUPER-GREEN-24M-21-07-30" + "tariff_code": f"E-1R-{product_code}-C", + "product_code": product_code } ] } @@ -50,23 +50,23 @@ async def test_when_account_info_has_no_electricity_meters_then_false_returned() assert has_intelligent_tariff(current, account_info) == False @pytest.mark.asyncio -@pytest.mark.parametrize("tariff_code",[ - ("E-1R-INTELLI-VAR-22-10-14-C".upper()), - ("E-1R-INTELLI-VAR-22-10-14-C".lower()), +@pytest.mark.parametrize("product_code",[ + ("INTELLI-VAR-22-10-14".upper()), + ("INTELLI-VAR-22-10-14".lower()), ]) -async def test_when_tariff_code_is_and_not_active_then_true_returned(tariff_code: str): - account_info = get_account_info(tariff_code, False) +async def test_when_product_code_is_and_not_active_then_true_returned(product_code: str): + account_info = get_account_info(product_code, False) # Act assert has_intelligent_tariff(current, account_info) == False @pytest.mark.asyncio -@pytest.mark.parametrize("tariff_code",[ - ("E-1R-INTELLI-VAR-22-10-14-C".upper()), - ("E-1R-INTELLI-VAR-22-10-14-C".lower()), +@pytest.mark.parametrize("product_code",[ + ("INTELLI-VAR-22-10-14".upper()), + ("INTELLI-VAR-22-10-14".lower()), ]) -async def test_when_tariff_code_is_valid_and_active_then_true_returned(tariff_code: str): - account_info = get_account_info(tariff_code, True) +async def test_when_product_code_is_valid_and_active_then_true_returned(product_code: str): + account_info = get_account_info(product_code, True) # Act assert has_intelligent_tariff(current, account_info) == True diff --git a/tests/unit/intelligent/test_is_intelligent_product.py b/tests/unit/intelligent/test_is_intelligent_product.py new file mode 100644 index 00000000..62faff75 --- /dev/null +++ b/tests/unit/intelligent/test_is_intelligent_product.py @@ -0,0 +1,27 @@ +import pytest + +from custom_components.octopus_energy.intelligent import is_intelligent_product + +@pytest.mark.asyncio +@pytest.mark.parametrize("product_code",[ + ("INTELLI-BB-VAR-23-03-01"), + ("INTELLI-VAR-22-10-14"), + ("INTELLI-22-03-29"), +]) +async def test_when_product_code_is_valid_then_true_returned(product_code: str): + # Act + assert is_intelligent_product(product_code.upper()) == True + assert is_intelligent_product(product_code.lower()) == True + +@pytest.mark.asyncio +@pytest.mark.parametrize("product_code",[ + ("invalid-product-code"), + ("INTELLI-FLUX-EXPORT-23-07-14"), + ("INTELLI-FLUX-EXPORT-BB-23-07-14"), + ("INTELLI-FLUX-IMPORT-23-07-14"), + ("INTELLI-FLUX-IMPORT-BB-23-07-14"), +]) +async def test_when_invalid_then_none_returned(product_code): + # Act + assert is_intelligent_product(product_code.upper()) == False + assert is_intelligent_product(product_code.lower()) == False \ No newline at end of file diff --git a/tests/unit/intelligent/test_is_intelligent_tariff.py b/tests/unit/intelligent/test_is_intelligent_tariff.py deleted file mode 100644 index cd8afc08..00000000 --- a/tests/unit/intelligent/test_is_intelligent_tariff.py +++ /dev/null @@ -1,27 +0,0 @@ -import pytest - -from custom_components.octopus_energy.intelligent import is_intelligent_tariff - -@pytest.mark.asyncio -@pytest.mark.parametrize("tariff_code",[ - ("E-1R-INTELLI-BB-VAR-23-03-01-C"), - ("E-1R-INTELLI-VAR-22-10-14-C"), - ("E-1R-INTELLI-22-03-29-B"), -]) -async def test_when_tariff_code_is_valid_then_true_returned(tariff_code: str): - # Act - assert is_intelligent_tariff(tariff_code.upper()) == True - assert is_intelligent_tariff(tariff_code.lower()) == True - -@pytest.mark.asyncio -@pytest.mark.parametrize("tariff_code",[ - ("invalid-tariff-code"), - ("E-1R-INTELLI-FLUX-EXPORT-23-07-14-C"), - ("E-1R-INTELLI-FLUX-EXPORT-BB-23-07-14-C"), - ("E-1R-INTELLI-FLUX-IMPORT-23-07-14-C"), - ("E-1R-INTELLI-FLUX-IMPORT-BB-23-07-14-C"), -]) -async def test_when_invalid_then_none_returned(tariff_code): - # Act - assert is_intelligent_tariff(tariff_code.upper()) == False - assert is_intelligent_tariff(tariff_code.lower()) == False \ No newline at end of file diff --git a/tests/unit/statistics/test_get_statistic_ids_to_remove.py b/tests/unit/statistics/test_get_statistic_ids_to_remove.py index b6e021eb..9ccccb25 100644 --- a/tests/unit/statistics/test_get_statistic_ids_to_remove.py +++ b/tests/unit/statistics/test_get_statistic_ids_to_remove.py @@ -13,7 +13,7 @@ def get_account_info(): "start": "2023-08-01T00:00:00+01:00", "end": "2023-08-14T00:00:00+01:00", "tariff_code": "E-1R-SUPER-GREEN-24M-21-07-30-C", - "product": "SUPER-GREEN-24M-21-07-30" + "product_code": "SUPER-GREEN-24M-21-07-30" } ], "meters": [ @@ -32,7 +32,7 @@ def get_account_info(): "start": "2023-08-13T00:00:00+01:00", "end": "2023-09-01T00:00:00+01:00", "tariff_code": "G-1R-SUPER-GREEN-24M-21-07-30-C", - "product": "SUPER-GREEN-24M-21-07-30" + "product_code": "SUPER-GREEN-24M-21-07-30" } ], "meters": [ diff --git a/tests/unit/utils/test_get_active_tariff_code.py b/tests/unit/utils/test_get_active_tariff.py similarity index 76% rename from tests/unit/utils/test_get_active_tariff_code.py rename to tests/unit/utils/test_get_active_tariff.py index 0f4bbd90..1a530efe 100644 --- a/tests/unit/utils/test_get_active_tariff_code.py +++ b/tests/unit/utils/test_get_active_tariff.py @@ -1,7 +1,7 @@ import pytest from datetime import datetime -from custom_components.octopus_energy.utils import get_active_tariff_code +from custom_components.octopus_energy.utils import get_active_tariff @pytest.mark.asyncio async def test_when_active_tariff_available_then_get_active_tariff_code_returns_expected_code(): @@ -10,26 +10,31 @@ async def test_when_active_tariff_available_then_get_active_tariff_code_returns_ agreements = [ { + 'product_code': 'FIX-12M-18-02-14', 'tariff_code': 'G-1R-FIX-12M-18-02-14-G', 'start': '2018-04-02T00:00:00+01:00', 'end': '2019-04-02T00:00:00+01:00' }, { + 'product_code': 'FIX-12M-18-12-21', 'tariff_code': 'G-1R-FIX-12M-18-12-21-G', 'start': '2019-04-02T00:00:00+01:00', 'end': '2020-04-02T00:00:00+01:00' }, { + 'product_code': 'SUPER-GREEN-12M-20-02-12', 'tariff_code': 'G-1R-SUPER-GREEN-12M-20-02-12-G', 'start': '2020-04-02T00:00:00+01:00', 'end': '2021-04-02T00:00:00+01:00' }, { + 'product_code': 'VAR-20-10-01', 'tariff_code': 'G-1R-VAR-20-10-01-G', 'start': '2021-04-02T00:00:00+01:00', 'end': '2021-04-02T00:00:00+01:00' }, { + 'product_code': 'FIX-12M-21-02-16', 'tariff_code': 'G-1R-FIX-12M-21-02-16-G', 'start': '2021-04-02T00:00:00+01:00', 'end': '2022-04-02T00:00:00+01:00' @@ -37,11 +42,12 @@ async def test_when_active_tariff_available_then_get_active_tariff_code_returns_ ] # Act - result = get_active_tariff_code(now, agreements) + result = get_active_tariff(now, agreements) # Assert assert result is not None - assert result == 'G-1R-FIX-12M-21-02-16-G' + assert result.product == 'FIX-12M-21-02-16' + assert result.code == 'G-1R-FIX-12M-21-02-16-G' @pytest.mark.asyncio async def test_when_agreements_ended_then_get_active_tariff_code_returns_none(): @@ -50,26 +56,31 @@ async def test_when_agreements_ended_then_get_active_tariff_code_returns_none(): agreements = [ { + 'product_code': 'FIX-12M-18-02-14', 'tariff_code': 'G-1R-FIX-12M-18-02-14-G', 'start': '2018-04-02T00:00:00+01:00', 'end': '2019-04-02T00:00:00+01:00' }, { + 'product_code': 'FIX-12M-18-12-21', 'tariff_code': 'G-1R-FIX-12M-18-12-21-G', 'start': '2019-04-02T00:00:00+01:00', 'end': '2020-04-02T00:00:00+01:00' }, { + 'product_code': 'SUPER-GREEN-12M-20-02-12', 'tariff_code': 'G-1R-SUPER-GREEN-12M-20-02-12-G', 'start': '2020-04-02T00:00:00+01:00', 'end': '2021-04-02T00:00:00+01:00' }, { + 'product_code': 'VAR-20-10-01', 'tariff_code': 'G-1R-VAR-20-10-01-G', 'start': '2021-04-02T00:00:00+01:00', 'end': '2021-04-02T00:00:00+01:00' }, { + 'product_code': 'FIX-12M-21-02-16', 'tariff_code': 'G-1R-FIX-12M-21-02-16-G', 'start': '2021-04-02T00:00:00+01:00', 'end': '2022-04-02T00:00:00+01:00' @@ -77,7 +88,7 @@ async def test_when_agreements_ended_then_get_active_tariff_code_returns_none(): ] # Act - result = get_active_tariff_code(now, agreements) + result = get_active_tariff(now, agreements) # Assert assert result is None @@ -89,26 +100,31 @@ async def test_when_agreements_not_started_then_get_active_tariff_code_returns_n agreements = [ { + 'product_code': 'FIX-12M-18-02-14', 'tariff_code': 'G-1R-FIX-12M-18-02-14-G', 'start': '2018-04-02T00:00:00+01:00', 'end': '2019-04-02T00:00:00+01:00' }, { + 'product_code': 'FIX-12M-18-12-21', 'tariff_code': 'G-1R-FIX-12M-18-12-21-G', 'start': '2019-04-02T00:00:00+01:00', 'end': '2020-04-02T00:00:00+01:00' }, { + 'product_code': 'SUPER-GREEN-12M-20-02-12', 'tariff_code': 'G-1R-SUPER-GREEN-12M-20-02-12-G', 'start': '2020-04-02T00:00:00+01:00', 'end': '2021-04-02T00:00:00+01:00' }, { + 'product_code': 'VAR-20-10-01', 'tariff_code': 'G-1R-VAR-20-10-01-G', 'start': '2021-04-02T00:00:00+01:00', 'end': '2021-04-02T00:00:00+01:00' }, { + 'product_code': 'FIX-12M-21-02-16', 'tariff_code': 'G-1R-FIX-12M-21-02-16-G', 'start': '2021-04-02T00:00:00+01:00', 'end': '2022-04-02T00:00:00+01:00' @@ -116,7 +132,7 @@ async def test_when_agreements_not_started_then_get_active_tariff_code_returns_n ] # Act - result = get_active_tariff_code(now, agreements) + result = get_active_tariff(now, agreements) # Assert assert result is None @@ -128,34 +144,40 @@ async def test_when_agreement_has_no_end_date_then_get_active_tariff_code_return agreements = [ { + 'product_code': 'FIX-12M-18-02-14', 'tariff_code': 'G-1R-FIX-12M-18-02-14-G', 'start': '2018-04-02T00:00:00+01:00', 'end': '2019-04-02T00:00:00+01:00' }, { + 'product_code': 'FIX-12M-18-12-21', 'tariff_code': 'G-1R-FIX-12M-18-12-21-G', 'start': '2019-04-02T00:00:00+01:00', 'end': '2020-04-02T00:00:00+01:00' }, { + 'product_code': 'SUPER-GREEN-12M-20-02-12', 'tariff_code': 'G-1R-SUPER-GREEN-12M-20-02-12-G', 'start': '2020-04-02T00:00:00+01:00', 'end': '2021-04-02T00:00:00+01:00' }, { + 'product_code': 'VAR-20-10-01', 'tariff_code': 'G-1R-VAR-20-10-01-G', 'start': '2021-04-02T00:00:00+01:00', 'end': '2021-04-02T00:00:00+01:00' }, { + 'product_code': 'FIX-12M-21-02-16', 'tariff_code': 'G-1R-FIX-12M-21-02-16-G', 'start': '2021-04-02T00:00:00+01:00' } ] # Act - result = get_active_tariff_code(now, agreements) + result = get_active_tariff(now, agreements) # Assert assert result is not None - assert result == 'G-1R-FIX-12M-21-02-16-G' \ No newline at end of file + assert result.product == 'FIX-12M-21-02-16' + assert result.code == 'G-1R-FIX-12M-21-02-16-G' \ No newline at end of file diff --git a/tests/unit/utils/test_is_agile_tariff.py b/tests/unit/utils/test_is_agile_tariff.py index bd63bd5f..a86d6c20 100644 --- a/tests/unit/utils/test_is_agile_tariff.py +++ b/tests/unit/utils/test_is_agile_tariff.py @@ -13,6 +13,6 @@ async def test_when_tariff_code_is_valid_then_true_returned(tariff_code: str, ex assert is_agile_tariff(tariff_code.lower()) == expected_result @pytest.mark.asyncio -async def test_when_invalid_then_none_returned(): +async def test_when_invalid_then_false_returned(): # Act assert is_agile_tariff("invalid-tariff-code") == False \ No newline at end of file diff --git a/tests/unit/utils/test_is_day_night_tariff.py b/tests/unit/utils/test_is_day_night_tariff.py new file mode 100644 index 00000000..e596d668 --- /dev/null +++ b/tests/unit/utils/test_is_day_night_tariff.py @@ -0,0 +1,13 @@ +import pytest + +from custom_components.octopus_energy.utils import is_day_night_tariff + +@pytest.mark.asyncio +@pytest.mark.parametrize("tariff_code,expected_result",[ + ("E-1R-AGILE-FLEX-22-11-25-B", False), + ("BUS-PANELP-12M-FIXED-SEPTEMBER2029", False), + ("E-2R-VAR-22-11-01-A", True), +]) +async def test_when_tariff_code_provided_then_expected_result_returned(tariff_code: str, expected_result: bool): + # Act + assert is_day_night_tariff(tariff_code) == expected_result \ No newline at end of file