diff --git a/_docs/assets/target_timeframes_data_source.png b/_docs/assets/target_timeframes_data_source.png new file mode 100644 index 00000000..a50f27db Binary files /dev/null and b/_docs/assets/target_timeframes_data_source.png differ diff --git a/_docs/assets/target_timeframes_sub_menu.png b/_docs/assets/target_timeframes_sub_menu.png new file mode 100644 index 00000000..99d673b5 Binary files /dev/null and b/_docs/assets/target_timeframes_sub_menu.png differ diff --git a/_docs/blueprints/octopus_energy_manual_intelligent_refresh.yaml b/_docs/blueprints/octopus_energy_manual_intelligent_refresh.yaml index 24c98d6f..b5498524 100644 --- a/_docs/blueprints/octopus_energy_manual_intelligent_refresh.yaml +++ b/_docs/blueprints/octopus_energy_manual_intelligent_refresh.yaml @@ -48,27 +48,41 @@ blueprint: action: {} variables: + intelligent_dispatches_data_last_retrieved_sensor: !input intelligent_dispatches_data_last_retrieved_sensor intelligent_dispatches_sensor: !input intelligent_dispatches_sensor car_plugged_in_sensor: !input car_plugged_in_sensor + millisecond_jitter: > + {{ range(1, 1000) | random }} mode: queued max: 4 -trigger_variables: - intelligent_dispatches_data_last_retrieved_sensor: !input intelligent_dispatches_data_last_retrieved_sensor triggers: - trigger: state + id: car_plugged_in entity_id: !input car_plugged_in_sensor to: !input car_plugged_in_sensor_state - - trigger: template - value_template: > - {{ state_attr(intelligent_dispatches_data_last_retrieved_sensor, 'next_refresh') | as_datetime | as_local < now() }} + - trigger: time_pattern + minutes: "/1" conditions: - condition: state entity_id: !input car_plugged_in_sensor state: !input car_plugged_in_sensor_state + # Make sure that our dispatches are either due to be updated or our automation was triggered due to the vehicle being plugged in + - condition: or + conditions: + - condition: template + value_template: > + {{ trigger.id == "car_plugged_in" }} + - condition: template + value_template: > + {{ state_attr(intelligent_dispatches_data_last_retrieved_sensor, 'next_refresh') | as_datetime | as_local < now() }} actions: # Wait 30 seconds to give OE a chance to update the dispatches - delay: 00:00:30 + # Add a bit of jitter so the API isn't hit at once + - delay: + milliseconds: > + {{ millisecond_jitter }} - action: octopus_energy.refresh_intelligent_dispatches target: entity_id: !input intelligent_dispatches_sensor diff --git a/_docs/entities/electricity.md b/_docs/entities/electricity.md index 3850656c..46727964 100644 --- a/_docs/entities/electricity.md +++ b/_docs/entities/electricity.md @@ -227,6 +227,10 @@ The total consumption reported by the meter for the previous available full day This is [disabled by default](../faq.md#there-are-entities-that-are-disabled-why-are-they-disabled-and-how-do-i-enable-them). +!!! warning + + If you are on intelligent and are using a provider where [planned_dispatches](./intelligent.md#is-dispatching) are not supported, then charges outside of your normal off peak periods will be counted at peak. This is because Octopus Energy doesn't provide enough information to determine if a completed dispatch was a bump charge or a planned charge. + ##### Standard `sensor.octopus_energy_electricity_{{METER_SERIAL_NUMBER}}_{{MPAN_NUMBER}}_previous_accumulative_consumption_standard` @@ -320,6 +324,10 @@ The total cost reported by the meter for the previous available full day during This is [disabled by default](../faq.md#there-are-entities-that-are-disabled-why-are-they-disabled-and-how-do-i-enable-them). +!!! warning + + If you are on intelligent and are using a provider where [planned_dispatches](./intelligent.md#is-dispatching) are not supported, then charges outside of your normal off peak periods will be counted at peak. This is because Octopus Energy doesn't provide enough information to determine if a completed dispatch was a bump charge or a planned charge. + ##### Standard `sensor.octopus_energy_electricity_{{METER_SERIAL_NUMBER}}_{{MPAN_NUMBER}}_previous_accumulative_cost_standard` @@ -522,6 +530,10 @@ The total cost reported by the meter for the current day during off peak hours ( !!! warning This will only be available if you have specified you have a [Octopus Home Mini](../setup/account.md#home-mini) or have configured an [Octopus Home Pro](../setup//account.md#home-pro). Do not set unless you have one. +!!! warning + + If you are on intelligent and are using a provider where [planned_dispatches](./intelligent.md#is-dispatching) are not supported, then charges outside of your normal off peak periods will be counted at peak. This is because Octopus Energy doesn't provide enough information to determine if a completed dispatch was a bump charge or a planned charge. + !!! info An export equivalent of this sensor does not exist because the data is not available diff --git a/_docs/entities/heat_pump.md b/_docs/entities/heat_pump.md index 4765cb32..66879f73 100644 --- a/_docs/entities/heat_pump.md +++ b/_docs/entities/heat_pump.md @@ -65,6 +65,10 @@ This represents the instantaneous efficiency of the heat pump. !!! note As this integration uses cloud polling this will inherently have a delay. +!!! info + + This sensor will report zero when the heat pump is not reporting input power, otherwise the reported COP can be inaccurate. + ## Live Power Input `sensor.octopus_energy_heat_pump_{{HEAT_PUMP_ID}}_live_power_input` diff --git a/_docs/entities/intelligent.md b/_docs/entities/intelligent.md index d703ca34..04b105c1 100644 --- a/_docs/entities/intelligent.md +++ b/_docs/entities/intelligent.md @@ -24,7 +24,7 @@ This sensor is used to determine if you're currently in a planned dispatch perio * OHME - If you are supplied by one of the above providers, `planned_dispatches` will always return an empty collection and this entity will only turn on when within the standard off peak period. + If you are supplied by one of the above providers, `planned_dispatches` will always return an empty collection and this entity will only turn on when within the standard off peak period. | Attribute | Type | Description | |-----------|------|-------------| diff --git a/_docs/migrations/target_timeframes.md b/_docs/migrations/target_timeframes.md new file mode 100644 index 00000000..bd5850db --- /dev/null +++ b/_docs/migrations/target_timeframes.md @@ -0,0 +1,51 @@ +# Migrating Target Rate Sensors To Target Timeframes + +It has been [proposed](https://github.com/BottlecapDave/HomeAssistant-OctopusEnergy/discussions/1305) that the target rate feature of the integration be deprecated and removed in favour of a new external integration, [Target Timeframes](https://bottlecapdave.github.io/HomeAssistant-TargetTimeframes/). The full reasoning can be found in the proposal. + +This guide explains how to migrate your target rate sensors to the new integration. + +## Installing the integration + +The first thing you need to do is install the new integration. Full instructions can be found on [the website](https://bottlecapdave.github.io/HomeAssistant-TargetTimeframes/#how-to-install). + +## Setting up data sources + +Once installed, you'll need to setup a data source that represents data coming from this integration. This can be done by [following the link](https://my.home-assistant.io/redirect/config_flow_start/?domain=target_timeframes) or searching for the integration in your integrations view. You'll need a data source for each of your meters (e.g. one for import and one for export) + +The recommended name is `Octopus Energy Import` and the recommended source id is `octopus_energy_import`, but you can pick whatever you want as long as it's unique within the integration. + +![Data Source window](../assets/target_timeframes_data_source.png) + +## Configuring Octopus Energy data + +Next, we'll need to get data from the Octopus Energy integration into the Target Timeframes integration. The recommended approach is an automation based on the [available blueprint](https://bottlecapdave.github.io/HomeAssistant-TargetTimeframes/blueprints/#octopus-energy). This will track when the rate entities within the Octopus Energy integration update. Upon updating, it will then transform the rate data into the shape required by Target Timeframes and use the available service to add the rate data with the data source we just created. Each `value` in Target Timeframes will represent our rate in pounds/pence. + +## Setting up Target Rate sensors + +Now we have our data source representing Octopus Energy and data coming from this integration into Target Timeframes, it's time to now port across our target rate and rolling target rate sensors. Each type of sensor are added as a sub entry to our data source. You can see below what the menu looks like. + +![Integration sub menu](../assets/target_timeframes_sub_menu.png) + +For porting a [target rate sensor](../setup/target_rate.md), you would select [target timeframe](https://bottlecapdave.github.io/HomeAssistant-TargetTimeframes/setup/target_timeframe/) and for porting a [rolling target rate sensor](../setup/rolling_target_rate.md), you would select [rolling target timeframe](https://bottlecapdave.github.io/HomeAssistant-TargetTimeframes/setup/rolling_target_timeframe/). + +All options within the sensors should feel familiar, as they represent what's available within this integration. Below are some noticeable differences + +* `Invert targeted rates` in the Octopus Energy integration is represented by `Find highest values`. If `Invert targeted rates` is checked, for sensors using data sources targeting import meters, `Find highest values` should be checked. If `Invert targeted rates` is checked, for sensors using data sources targeting export meters, `Find highest values` should be checked. + +!!! info + + If you are wanting to minimise updates of automations, once the target timeframe sensor has been created and you delete the old sensor from the Octopus Energy integration, you can rename the entity id to have the name of the old sensor. For example, if you have a target sensor with the entity id of `sensor.target_timeframe_octopus_energy_import_dishwasher`, your could rename it to `sensor.octopus_energy_target_dishwasher`. + +!!! warning + + There is currently a bug in HA where you'll need to reload the data source when a target rate sensor is added/updated in order to see the target rate sensor. + +## Available services + +The following list of related services and their counterparts. + +| OE Service | Target Timeframes Service | +|-|-| +| [octopus_energy.update_target_config](../services.md#octopus_energyupdate_target_config) | [target_timeframes.update_target_timeframe_config](https://bottlecapdave.github.io/HomeAssistant-TargetTimeframes/services/#target_timeframesupdate_target_timeframe_config) | +| [octopus_energy.update_rolling_target_config](../services.md#octopus_energyupdate_rolling_target_config) | [target_timeframes.update_rolling_target_timeframe_config](https://bottlecapdave.github.io/HomeAssistant-TargetTimeframes/services/#target_timeframesupdate_rolling_target_timeframe_config) | +| [octopus_energy.register_rate_weightings](../services.md#octopus_energyregister_rate_weightings) | Data is now loaded as part of [target_timeframes.update_target_timeframe_data_source](https://bottlecapdave.github.io/HomeAssistant-TargetTimeframes/services/#target_timeframesupdate_target_timeframe_data_source). Therefore data can be manipulated before this service is called. A [blueprint](https://bottlecapdave.github.io/HomeAssistant-TargetTimeframes/blueprints/#octopus-energy-and-carbon-intensity) is available as an example. | \ No newline at end of file diff --git a/_docs/services.md b/_docs/services.md index e61b404b..184f57c9 100644 --- a/_docs/services.md +++ b/_docs/services.md @@ -313,7 +313,7 @@ This service is only available for the following sensors Due to limitations with Home Assistant entities, this service will only refresh data for the associated statistic ids used for the recommended approach in the [energy dashboard](./setup/energy_dashboard.md#previous-day-consumption). This will not update the history of the entities themselves. -!!! warn +!!! warning If you are on intelligent, the cost data will not be correct for charges outside of the normal off peak times. This is because this data isn't available. diff --git a/_docs/setup/cost_tracker.md b/_docs/setup/cost_tracker.md index b3fe20bd..735403ad 100644 --- a/_docs/setup/cost_tracker.md +++ b/_docs/setup/cost_tracker.md @@ -108,6 +108,10 @@ This is the total cost of the tracked entity for the current day during off peak This is [disabled by default](../faq.md#there-are-entities-that-are-disabled-why-are-they-disabled-and-how-do-i-enable-them). +!!! warning + + If you are on intelligent and are using a provider where [planned_dispatches](../entities/intelligent.md#is-dispatching) are not supported, then charges outside of your normal off peak periods will be counted at peak. This is because Octopus Energy doesn't provide enough information to determine if a completed dispatch was a bump charge or a planned charge. + ##### Standard `sensor.octopus_energy_cost_tracker_{{COST_TRACKER_NAME}}_standard` @@ -184,6 +188,10 @@ This is the total cost of the tracked entity for the current week during off pea This is [disabled by default](../faq.md#there-are-entities-that-are-disabled-why-are-they-disabled-and-how-do-i-enable-them). +!!! warning + + If you are on intelligent and are using a provider where [planned_dispatches](../entities/intelligent.md#is-dispatching) are not supported, then charges outside of your normal off peak periods will be counted at peak. This is because Octopus Energy doesn't provide enough information to determine if a completed dispatch was a bump charge or a planned charge. + ##### Standard `sensor.octopus_energy_cost_tracker_{{COST_TRACKER_NAME}}_week_standard` @@ -260,6 +268,10 @@ This is the total cost of the tracked entity for the current month during off pe This is [disabled by default](../faq.md#there-are-entities-that-are-disabled-why-are-they-disabled-and-how-do-i-enable-them). +!!! warning + + If you are on intelligent and are using a provider where [planned_dispatches](../entities/intelligent.md#is-dispatching) are not supported, then charges outside of your normal off peak periods will be counted at peak. This is because Octopus Energy doesn't provide enough information to determine if a completed dispatch was a bump charge or a planned charge. + ##### Standard `sensor.octopus_energy_cost_tracker_{{COST_TRACKER_NAME}}_month_standard` diff --git a/_docs/setup/rolling_target_rate.md b/_docs/setup/rolling_target_rate.md index 7066bc7c..c9fbaee1 100644 --- a/_docs/setup/rolling_target_rate.md +++ b/_docs/setup/rolling_target_rate.md @@ -1,5 +1,11 @@ # Rolling Target Rate Sensor(s) +!!! warning + + It has been [proposed](https://github.com/BottlecapDave/HomeAssistant-OctopusEnergy/discussions/1305) that the rolling target rate feature of the integration be deprecated and removed in favour of a new external integration, [Target Timeframes](https://bottlecapdave.github.io/HomeAssistant-TargetTimeframes/). The full reasoning can be found in the proposal. + + A [migration guide](../migrations/target_timeframes.md) is available for migrating rolling target rate sensors to the new integration. + After you've configured your [account](./account.md), you'll be able to configure rolling target rate sensors. These are configured by adding subsequent instances of the integration going through the [normal flow](https://my.home-assistant.io/redirect/config_flow_start/?domain=octopus_energy), and selecting `Rolling Target Rate` in the provided menu. These sensors calculate the lowest continuous or intermittent rates within the next available `x` hours, where `x` is configurable via the sensor, and turn on when these periods are active. If you are targeting an export meter, then the sensors will calculate the highest continuous or intermittent rates within the next available `x` hours and turn on when these periods are active. If you are wanting to evaluate on a fixed basis (e.g. every 24 hours), you might be interested in the [standard target rate sensors](./target_rate.md) diff --git a/_docs/setup/target_rate.md b/_docs/setup/target_rate.md index 5ab380fe..f7881a9f 100644 --- a/_docs/setup/target_rate.md +++ b/_docs/setup/target_rate.md @@ -1,5 +1,11 @@ # Target Rate Sensor(s) +!!! warning + + It has been [proposed](https://github.com/BottlecapDave/HomeAssistant-OctopusEnergy/discussions/1305) that the target rate feature of the integration be deprecated and removed in favour of a new external integration, [Target Timeframes](https://bottlecapdave.github.io/HomeAssistant-TargetTimeframes/). The full reasoning can be found in the proposal. + + A [migration guide](../migrations/target_timeframes.md) is available for migrating target rate sensors to the new integration. + After you've configured your [account](./account.md), you'll be able to configure target rate sensors. These are configured by adding subsequent instances of the integration going through the [normal flow](https://my.home-assistant.io/redirect/config_flow_start/?domain=octopus_energy), and selecting `Target Rate` in the provided menu. These sensors calculate the lowest continuous or intermittent rates **within a 24 hour period** and turn on when these periods are active. If you are targeting an export meter, then the sensors will calculate the highest continuous or intermittent rates **within a 24 hour period** and turn on when these periods are active. If you are wanting to evaluate on a rolling basis, you might be interested in the [rolling target rate sensors](./rolling_target_rate.md) diff --git a/custom_components/octopus_energy/__init__.py b/custom_components/octopus_energy/__init__.py index 8742feba..7a18f427 100644 --- a/custom_components/octopus_energy/__init__.py +++ b/custom_components/octopus_energy/__init__.py @@ -496,14 +496,12 @@ async def async_setup_dependencies(hass, config): is_smart_meter = meter["is_smart_meter"] override = await async_get_meter_debug_override(hass, mpan, serial_number) tariff_override = override.tariff if override is not None else None - planned_dispatches_supported = intelligent_features.planned_dispatches_supported if intelligent_features is not None else True await async_setup_electricity_rates_coordinator(hass, account_id, mpan, serial_number, is_smart_meter, is_export_meter, - planned_dispatches_supported, config[CONFIG_MAIN_INTELLIGENT_RATE_MODE] if CONFIG_MAIN_INTELLIGENT_RATE_MODE in config else CONFIG_MAIN_INTELLIGENT_RATE_MODE_PENDING_AND_STARTED_DISPATCHES, tariff_override) @@ -535,7 +533,8 @@ async def async_setup_dependencies(hass, config): hass, account_id, account_debug_override.mock_intelligent_controls if account_debug_override is not None else False, - config[CONFIG_MAIN_INTELLIGENT_MANUAL_DISPATCHES] == True if CONFIG_MAIN_INTELLIGENT_MANUAL_DISPATCHES in config else False + config[CONFIG_MAIN_INTELLIGENT_MANUAL_DISPATCHES] == True if CONFIG_MAIN_INTELLIGENT_MANUAL_DISPATCHES in config else False, + intelligent_features.planned_dispatches_supported if intelligent_features is not None else True ) await async_setup_intelligent_settings_coordinator(hass, account_id, intelligent_device.id if intelligent_device is not None else None, account_debug_override.mock_intelligent_controls if account_debug_override is not None else False) diff --git a/custom_components/octopus_energy/binary_sensor.py b/custom_components/octopus_energy/binary_sensor.py index 13fdf1f8..a187debe 100644 --- a/custom_components/octopus_energy/binary_sensor.py +++ b/custom_components/octopus_energy/binary_sensor.py @@ -165,10 +165,9 @@ async def async_setup_main_sensors(hass, entry, async_add_entities): "async_refresh_dispatches" ) - intelligent_features = get_intelligent_features(intelligent_device.provider) coordinator = hass.data[DOMAIN][account_id][DATA_INTELLIGENT_DISPATCHES_COORDINATOR] electricity_rate_coordinator = hass.data[DOMAIN][account_id][DATA_ELECTRICITY_RATES_COORDINATOR_KEY.format(intelligent_mpan, intelligent_serial_number)] - entities.append(OctopusEnergyIntelligentDispatching(hass, coordinator, electricity_rate_coordinator, intelligent_mpan, intelligent_device, account_id, intelligent_features.planned_dispatches_supported)) + entities.append(OctopusEnergyIntelligentDispatching(hass, coordinator, electricity_rate_coordinator, intelligent_mpan, intelligent_device, account_id)) if len(entities) > 0: async_add_entities(entities) diff --git a/custom_components/octopus_energy/config_flow.py b/custom_components/octopus_energy/config_flow.py index 1dc3b3f6..a786dcee 100644 --- a/custom_components/octopus_energy/config_flow.py +++ b/custom_components/octopus_energy/config_flow.py @@ -841,7 +841,7 @@ async def __async_setup_main_schema__(self, config, errors): selector.SelectSelectorConfig( options=[ selector.SelectOptionDict(value=CONFIG_MAIN_INTELLIGENT_RATE_MODE_PENDING_AND_STARTED_DISPATCHES, label="Planned and started dispatches will turn into off peak rates"), - selector.SelectOptionDict(value=CONFIG_MAIN_INTELLIGENT_RATE_MODE_STARTED_DISPATCHES_ONLY, label="Only stared dispatches will turn into off peak rates"), + selector.SelectOptionDict(value=CONFIG_MAIN_INTELLIGENT_RATE_MODE_STARTED_DISPATCHES_ONLY, label="Only started dispatches will turn into off peak rates"), ], mode=selector.SelectSelectorMode.DROPDOWN, ) diff --git a/custom_components/octopus_energy/coordinators/electricity_rates.py b/custom_components/octopus_energy/coordinators/electricity_rates.py index 748751c0..601253ff 100644 --- a/custom_components/octopus_energy/coordinators/electricity_rates.py +++ b/custom_components/octopus_energy/coordinators/electricity_rates.py @@ -61,7 +61,6 @@ async def async_refresh_electricity_rates_data( existing_rates_result: ElectricityRatesCoordinatorResult | None, intelligent_device: IntelligentDevice | None, dispatches_result: IntelligentDispatchesCoordinatorResult | None, - planned_dispatches_supported: bool, fire_event: Callable[[str, "dict[str, Any]"], None], tariff_override = None, unique_rates_changed: Callable[[Tariff, int], Awaitable[None]] = None, @@ -121,7 +120,7 @@ async def async_refresh_electricity_rates_data( if dispatches_result is not None and dispatches_result.dispatches is not None and is_export_meter == False: new_rates = adjust_intelligent_rates(new_rates, - dispatches_result.dispatches.planned if planned_dispatches_supported else [], + dispatches_result.dispatches.planned, dispatches_result.dispatches.started, intelligent_rate_mode) @@ -182,7 +181,6 @@ async def async_refresh_electricity_rates_data( # While we might have updated completed dispatches when planned dispatches isn't supported, # these can wait as they only power previous consumption costs which can be recalculated with a delay elif (is_export_meter == False and - planned_dispatches_supported == True and existing_rates_result is not None and dispatches_result is not None and dispatches_result.dispatches is not None and @@ -253,7 +251,6 @@ async def async_setup_electricity_rates_coordinator(hass, target_serial_number: str, is_smart_meter: bool, is_export_meter: bool, - planned_dispatches_supported: bool, intelligent_rate_mode: str, tariff_override = None): key = DATA_ELECTRICITY_RATES_KEY.format(target_mpan, target_serial_number) @@ -286,7 +283,6 @@ async def async_update_electricity_rates_data(): rates, intelligent_device, dispatches, - planned_dispatches_supported, hass.bus.async_fire, tariff_override, lambda tariff, total_unique_rates: async_update_unique_rates(hass, account_id, tariff, total_unique_rates), diff --git a/custom_components/octopus_energy/coordinators/intelligent_dispatches.py b/custom_components/octopus_energy/coordinators/intelligent_dispatches.py index 722448b8..d8400506 100644 --- a/custom_components/octopus_energy/coordinators/intelligent_dispatches.py +++ b/custom_components/octopus_energy/coordinators/intelligent_dispatches.py @@ -145,6 +145,7 @@ async def async_refresh_intelligent_dispatches( existing_intelligent_dispatches_result: IntelligentDispatchesCoordinatorResult, is_data_mocked: bool, is_manual_refresh: bool, + planned_dispatches_supported: bool, async_save_dispatches: Callable[[str, IntelligentDispatches], Awaitable[list]], ): requests_current_hour = existing_intelligent_dispatches_result.requests_current_hour if existing_intelligent_dispatches_result is not None else 0 @@ -201,6 +202,11 @@ async def async_refresh_intelligent_dispatches( dispatches = mock_intelligent_dispatches() _LOGGER.debug(f'Intelligent dispatches mocked for account {account_id}') + if planned_dispatches_supported == False: + # If planned dispatches are not supported, then we should clear down the planned dispatches as they are not useful + _LOGGER.debug("Clearing planned dispatches due to not being supported for provider") + dispatches.planned.clear() + if dispatches is not None: dispatches.completed = clean_previous_dispatches(utcnow(), (existing_intelligent_dispatches_result.dispatches.completed if existing_intelligent_dispatches_result is not None and existing_intelligent_dispatches_result.dispatches is not None and existing_intelligent_dispatches_result.dispatches.completed is not None else []) + dispatches.completed) dispatches.started = merge_started_dispatches(current, @@ -239,7 +245,7 @@ async def async_refresh_intelligent_dispatches( return existing_intelligent_dispatches_result -async def async_setup_intelligent_dispatches_coordinator(hass, account_id: str, mock_intelligent_data: bool, manual_dispatch_refreshes: bool): +async def async_setup_intelligent_dispatches_coordinator(hass, account_id: str, mock_intelligent_data: bool, manual_dispatch_refreshes: bool, planned_dispatches_supported: bool): async def async_update_intelligent_dispatches_data(is_manual_refresh = False): """Fetch data from API endpoint.""" # Request our account data to be refreshed @@ -260,6 +266,7 @@ async def async_update_intelligent_dispatches_data(is_manual_refresh = False): hass.data[DOMAIN][account_id][DATA_INTELLIGENT_DISPATCHES] if DATA_INTELLIGENT_DISPATCHES in hass.data[DOMAIN][account_id] else None, mock_intelligent_data, is_manual_refresh, + planned_dispatches_supported, lambda account_id, dispatches: async_save_cached_intelligent_dispatches(hass, account_id, dispatches) ) diff --git a/custom_components/octopus_energy/diagnostics.py b/custom_components/octopus_energy/diagnostics.py index 6a740194..34877d7b 100644 --- a/custom_components/octopus_energy/diagnostics.py +++ b/custom_components/octopus_energy/diagnostics.py @@ -176,6 +176,7 @@ def get_entity_info(redacted_mappings): unique_id = unique_id.lower().replace(key.lower(), f"{redacted_mappings[key]}") entity_info[unique_id] = { + "state": state.state if state is not None else None, "last_updated": state.last_updated if state is not None else None, "last_changed": state.last_changed if state is not None else None } diff --git a/custom_components/octopus_energy/heat_pump/sensor_live_cop.py b/custom_components/octopus_energy/heat_pump/sensor_live_cop.py index a24d8933..47f8121a 100644 --- a/custom_components/octopus_energy/heat_pump/sensor_live_cop.py +++ b/custom_components/octopus_energy/heat_pump/sensor_live_cop.py @@ -76,7 +76,7 @@ def _handle_coordinator_update(self) -> None: self._state = 0 # Only update the CoP if heat pump is actively running if float(result.data.octoHeatPumpLivePerformance.powerInput.value) != 0: - self._state = float(result.data.octoHeatPumpLivePerformance.coefficientOfPerformance) if result.data.octoHeatPumpLivePerformance.coefficientOfPerformanc is not None else None + self._state = float(result.data.octoHeatPumpLivePerformance.coefficientOfPerformance) if result.data.octoHeatPumpLivePerformance.coefficientOfPerformance is not None else None self._attributes["read_at"] = datetime.fromisoformat(result.data.octoHeatPumpLivePerformance.readAt) self._last_updated = current diff --git a/custom_components/octopus_energy/intelligent/dispatching.py b/custom_components/octopus_energy/intelligent/dispatching.py index f0af80ae..434144ac 100644 --- a/custom_components/octopus_energy/intelligent/dispatching.py +++ b/custom_components/octopus_energy/intelligent/dispatching.py @@ -30,7 +30,7 @@ class OctopusEnergyIntelligentDispatching(MultiCoordinatorEntity, BinarySensorEntity, OctopusEnergyIntelligentSensor, RestoreEntity): """Sensor for determining if an intelligent is dispatching.""" - def __init__(self, hass: HomeAssistant, coordinator: IntelligentDispatchDataUpdateCoordinator, rates_coordinator, mpan: str, device: IntelligentDevice, account_id: str, planned_dispatches_supported: bool): + def __init__(self, hass: HomeAssistant, coordinator: IntelligentDispatchDataUpdateCoordinator, rates_coordinator, mpan: str, device: IntelligentDevice, account_id: str): """Init sensor.""" MultiCoordinatorEntity.__init__(self, coordinator, [rates_coordinator]) @@ -40,7 +40,6 @@ def __init__(self, hass: HomeAssistant, coordinator: IntelligentDispatchDataUpda self._mpan = mpan self._account_id = account_id self._state = None - self._planned_dispatches_supported = planned_dispatches_supported self.__init_attributes__([], [], []) self.entity_id = generate_entity_id("binary_sensor.{}", self.unique_id, hass=hass) @@ -90,10 +89,9 @@ def _handle_coordinator_update(self) -> None: rates = self._rates_coordinator.data.rates if self._rates_coordinator is not None and self._rates_coordinator.data is not None else None current_date = utcnow() - planned_dispatches = result.dispatches.planned if result is not None and result.dispatches is not None and self._planned_dispatches_supported else [] self.__init_attributes__( - dispatches_to_dictionary_list(planned_dispatches) if result is not None else [], + dispatches_to_dictionary_list(result.dispatches.planned) if result is not None else [], dispatches_to_dictionary_list(result.dispatches.completed if result is not None and result.dispatches is not None else []) if result is not None else [], dispatches_to_dictionary_list(result.dispatches.started if result is not None and result.dispatches is not None else []) if result is not None else [], ) diff --git a/mkdocs.yml b/mkdocs.yml index f691ba24..34b9f28a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -21,6 +21,8 @@ nav: - Home Pro: ./entities/home_pro.md - Heat Pump: ./entities/heat_pump.md - Diagnostics: ./entities/diagnostics.md + - Migrations: + - ./migrations/target_timeframes.md - services.md - events.md - Repairs: diff --git a/tests/integration/coordinators/test_async_refresh_electricity_rates_data.py b/tests/integration/coordinators/test_async_refresh_electricity_rates_data.py index 8cbbbc88..aa119f08 100644 --- a/tests/integration/coordinators/test_async_refresh_electricity_rates_data.py +++ b/tests/integration/coordinators/test_async_refresh_electricity_rates_data.py @@ -30,7 +30,6 @@ async def test_when_next_refresh_is_in_the_past_and_then_requested_data_returned is_export_meter = False intelligent_device = None dispatches_result = None - planned_dispatches_supported = False tariff_override = None current_utc_timestamp = datetime.strptime(f'2024-11-20T10:12:00Z', "%Y-%m-%dT%H:%M:%S%z") @@ -78,7 +77,6 @@ def unique_rates_changed(tariff: Tariff, unique_rates: int): existing_rates_result, intelligent_device, dispatches_result, - planned_dispatches_supported, fire_event, tariff_override, unique_rates_changed diff --git a/tests/unit/api_client/test_heat_pump.py b/tests/unit/api_client/test_heat_pump.py index eabd6d52..30fc0dd6 100644 --- a/tests/unit/api_client/test_heat_pump.py +++ b/tests/unit/api_client/test_heat_pump.py @@ -8,97 +8,85 @@ def test_when_valid_dictionary_returned_then_it_can_be_parsed_into_heat_pump_obj { "code": "ADC1", "connectivity": { - "online": True, - "retrievedAt": "2024-12-01T10:04:54.952000+00:00" + "online": "true", + "retrievedAt": "2025-05-09T17:28:51.553000+00:00" }, "telemetry": { - "temperatureInCelsius": 57.4, + "temperatureInCelsius": 52.5, "humidityPercentage": None, - "retrievedAt": "2024-12-01T10:04:51.588000+00:00" + "retrievedAt": "2025-05-09T17:28:44.152000+00:00" } }, { "code": "ADC2", "connectivity": { - "online": True, - "retrievedAt": "2024-12-01T10:04:54.952000+00:00" + "online": "true", + "retrievedAt": "2025-05-09T17:28:51.554000+00:00" }, "telemetry": { - "temperatureInCelsius": -273.1, + "temperatureInCelsius": -90.3, "humidityPercentage": None, - "retrievedAt": "2024-12-01T10:04:51.588000+00:00" + "retrievedAt": "2025-05-09T17:28:44.152000+00:00" } }, { "code": "ADC3", "connectivity": { - "online": True, - "retrievedAt": "2024-12-01T10:04:54.953000+00:00" + "online": "true", + "retrievedAt": "2025-05-09T17:28:51.555000+00:00" }, "telemetry": { - "temperatureInCelsius": -273.1, + "temperatureInCelsius": -90.3, "humidityPercentage": None, - "retrievedAt": "2024-12-01T10:04:51.588000+00:00" + "retrievedAt": "2025-05-09T17:28:44.152000+00:00" } }, { "code": "ADC4", "connectivity": { - "online": True, - "retrievedAt": "2024-12-01T10:04:54.953000+00:00" + "online": "true", + "retrievedAt": "2025-05-09T17:28:51.556000+00:00" }, "telemetry": { - "temperatureInCelsius": -273.1, + "temperatureInCelsius": -90.3, "humidityPercentage": None, - "retrievedAt": "2024-12-01T10:04:51.588000+00:00" + "retrievedAt": "2025-05-09T17:28:44.152000+00:00" } }, { "code": "SENSOR01", "connectivity": { - "online": True, - "retrievedAt": "2024-12-01T10:04:54.953000+00:00" + "online": "true", + "retrievedAt": "2025-05-09T17:28:51.556000+00:00" }, "telemetry": { - "temperatureInCelsius": 19.4, - "humidityPercentage": 57, - "retrievedAt": "2024-12-01T10:03:15.615000+00:00" + "temperatureInCelsius": 21.0, + "humidityPercentage": 36.0, + "retrievedAt": "2025-05-09T17:27:51.160000+00:00" } }, { "code": "SENSOR02", "connectivity": { - "online": True, - "retrievedAt": "2024-12-01T10:04:54.955000+00:00" + "online": "true", + "retrievedAt": "2025-05-09T17:28:51.557000+00:00" }, "telemetry": { - "temperatureInCelsius": 22.4, - "humidityPercentage": 54, - "retrievedAt": "2024-12-01T10:03:54.876000+00:00" + "temperatureInCelsius": 20.8, + "humidityPercentage": 37.0, + "retrievedAt": "2025-05-09T17:28:39.347000+00:00" } }, { "code": "SENSOR03", "connectivity": { - "online": True, - "retrievedAt": "2024-12-01T10:04:54.956000+00:00" + "online": "true", + "retrievedAt": "2025-05-09T17:28:51.570000+00:00" }, "telemetry": { - "temperatureInCelsius": 22.3, - "humidityPercentage": 60, - "retrievedAt": "2024-12-01T10:04:27.571000+00:00" - } - }, - { - "code": "SENSOR04", - "connectivity": { - "online": True, - "retrievedAt": "2024-12-01T10:04:54.957000+00:00" - }, - "telemetry": { - "temperatureInCelsius": 22.7, - "humidityPercentage": 46, - "retrievedAt": "2024-12-01T10:03:12.376000+00:00" + "temperatureInCelsius": 20.9, + "humidityPercentage": 38.0, + "retrievedAt": "2025-05-09T17:28:46.611000+00:00" } } ], @@ -106,41 +94,41 @@ def test_when_valid_dictionary_returned_then_it_can_be_parsed_into_heat_pump_obj { "zone": "WATER", "telemetry": { - "setpointInCelsius": -300, + "setpointInCelsius": -300.0, "mode": "AUTO", "relaySwitchedOn": False, "heatDemand": False, - "retrievedAt": "2024-12-01T10:04:59.116000+00:00" + "retrievedAt": "2025-05-09T17:28:56.609000+00:00" } }, { "zone": "ZONE_1", "telemetry": { - "setpointInCelsius": 22, + "setpointInCelsius": 18.0, "mode": "AUTO", "relaySwitchedOn": False, "heatDemand": False, - "retrievedAt": "2024-12-01T10:04:59.117000+00:00" + "retrievedAt": "2025-05-09T17:28:56.610000+00:00" } }, { "zone": "ZONE_2", "telemetry": { - "setpointInCelsius": 7, + "setpointInCelsius": 7.0, "mode": "OFF", "relaySwitchedOn": False, "heatDemand": False, - "retrievedAt": "2024-12-01T10:04:59.118000+00:00" + "retrievedAt": "2025-05-09T17:28:56.611000+00:00" } }, { "zone": "AUXILIARY", "telemetry": { - "setpointInCelsius": 7, + "setpointInCelsius": 7.0, "mode": "OFF", "relaySwitchedOn": False, "heatDemand": False, - "retrievedAt": "2024-12-01T10:04:59.118000+00:00" + "retrievedAt": "2025-05-09T17:28:56.612000+00:00" } } ] @@ -151,11 +139,11 @@ def test_when_valid_dictionary_returned_then_it_can_be_parsed_into_heat_pump_obj "NORMAL_MODE" ], "heatPumpTimezone": "GMT0BST,M3.5.0/1,M10.5.0", - "connected": True + "connected": "true" }, "heatPump": { - "serialNumber": None, - "model": "Cosy 6", + "serialNumber": "00000000000002510198", + "model": "Cosy 9", "hardwareVersion": "v5.1.0", "maxWaterSetpoint": 60, "minWaterSetpoint": 40, @@ -176,7 +164,7 @@ def test_when_valid_dictionary_returned_then_it_can_be_parsed_into_heat_pump_obj } }, "weatherCompensation": { - "enabled": True, + "enabled": "true", "allowableRange": { "minimum": { "value": "30", @@ -189,11 +177,11 @@ def test_when_valid_dictionary_returned_then_it_can_be_parsed_into_heat_pump_obj }, "currentRange": { "minimum": { - "value": "45", + "value": "37", "unit": "DEGREES_CELSIUS" }, "maximum": { - "value": "55", + "value": "57", "unit": "DEGREES_CELSIUS" } } @@ -204,7 +192,7 @@ def test_when_valid_dictionary_returned_then_it_can_be_parsed_into_heat_pump_obj "configuration": { "code": "WATER", "zoneType": "WATER", - "enabled": True, + "enabled": "true", "displayName": "WATER", "primarySensor": "ADC1", "currentOperation": { @@ -221,25 +209,33 @@ def test_when_valid_dictionary_returned_then_it_can_be_parsed_into_heat_pump_obj "code": "ADC1", "displayName": "ADC1", "type": "NTC", - "enabled": True + "enabled": "true", + "firmwareVersion": None, + "boostEnabled": None }, { "code": "ADC2", "displayName": "ADC2", "type": "NTC", - "enabled": True + "enabled": "true", + "firmwareVersion": None, + "boostEnabled": None }, { "code": "ADC3", "displayName": "ADC3", "type": "NTC", - "enabled": True + "enabled": "true", + "firmwareVersion": None, + "boostEnabled": None }, { "code": "ADC4", "displayName": "ADC4", "type": "NTC", - "enabled": True + "enabled": "true", + "firmwareVersion": None, + "boostEnabled": None } ] } @@ -248,12 +244,12 @@ def test_when_valid_dictionary_returned_then_it_can_be_parsed_into_heat_pump_obj "configuration": { "code": "ZONE_1", "zoneType": "HEAT", - "enabled": True, + "enabled": "true", "displayName": "ZONE1", - "primarySensor": "SENSOR03", + "primarySensor": "SENSOR01", "currentOperation": { "mode": "AUTO", - "setpointInCelsius": 22, + "setpointInCelsius": 18.0, "action": None, "end": "1970-01-01T00:00:00+00:00" }, @@ -263,35 +259,27 @@ def test_when_valid_dictionary_returned_then_it_can_be_parsed_into_heat_pump_obj "sensors": [ { "code": "SENSOR01", - "displayName": "Hallway", + "displayName": "Primary", "type": "ZIGBEE", - "id": None, + "enabled": None, "firmwareVersion": "0D", - "boostEnabled": True + "boostEnabled": "true" }, { "code": "SENSOR02", - "displayName": "bedoom", + "displayName": "Upstairs", "type": "ZIGBEE", - "id": None, + "enabled": None, "firmwareVersion": "0D", - "boostEnabled": True + "boostEnabled": "true" }, { "code": "SENSOR03", - "displayName": "Mom and Dad", - "type": "ZIGBEE", - "id": None, - "firmwareVersion": "0D", - "boostEnabled": True - }, - { - "code": "SENSOR04", - "displayName": "Lounge ", + "displayName": "Nursery", "type": "ZIGBEE", - "id": None, + "enabled": None, "firmwareVersion": "0D", - "boostEnabled": True + "boostEnabled": "true" } ] } @@ -305,64 +293,64 @@ def test_when_valid_dictionary_returned_then_it_can_be_parsed_into_heat_pump_obj "primarySensor": None, "currentOperation": { "mode": "OFF", - "setpointInCelsius": 7, + "setpointInCelsius": 7.0, "action": None, "end": "1970-01-01T00:00:00+00:00" }, "callForHeat": False, "heatDemand": False, - "emergency": True, + "emergency": "true", "sensors": [] } }, { "configuration": { "code": "AUXILIARY", - "zoneType": "AUX", + "zoneType": "HEAT", "enabled": False, "displayName": "AUX", "primarySensor": None, "currentOperation": { "mode": "OFF", - "setpointInCelsius": 7, + "setpointInCelsius": 7.0, "action": None, "end": "1970-01-01T00:00:00+00:00" }, "callForHeat": False, "heatDemand": False, - "emergency": False, + "emergency": "true", "sensors": [] } } ] }, - "octoHeatPumpLifetimePerformance": { - "seasonalCoefficientOfPerformance": "3.5", + "octoHeatPumpLivePerformance": { + "coefficientOfPerformance": "32.510", "heatOutput": { - "unit": "KILOWATT_HOUR", - "value": "100.4" + "value": "0.000", + "unit": "KILOWATT" }, - "energyInput": { - "unit": "KILOWATT_HOUR", - "value": "100.2" + "powerInput": { + "value": "0.002", + "unit": "KILOWATT" }, - "readAt": "2024-12-31T09:10:00+00:00" - }, - "octoHeatPumpLivePerformance": { - "coefficientOfPerformance": "3.4", "outdoorTemperature": { - "unit": "DEGREES_CELSIUS", - "value": "30.1" + "value": "18.400", + "unit": "DEGREES_CELSIUS" }, + "readAt": "2025-05-09T18:28:51.630000+01:00" + }, + "octoHeatPumpLifetimePerformance": { + "seasonalCoefficientOfPerformance": "2.985", "heatOutput": { - "value": "10.5", - "unit": "KILOWATT" + "value": "765.599", + "unit": "KILOWATT_HOUR" }, - "powerInput": { - "unit": "KILOWATT", - "value": "5.4" + "energyInput": { + "value": "256.439", + "unit": "KILOWATT_HOUR" }, - "readAt": "2024-12-31T09:10:00+00:00" + "readAt": "2025-05-09T18:28:51.628000+01:00" } } @@ -370,4 +358,13 @@ def test_when_valid_dictionary_returned_then_it_can_be_parsed_into_heat_pump_obj result = HeatPumpResponse.parse_obj(data) # Assert - assert result is not None \ No newline at end of file + assert result is not None + + assert float(result.octoHeatPumpLivePerformance.coefficientOfPerformance) == 32.510 + assert float(result.octoHeatPumpLivePerformance.heatOutput.value) == 0.000 + assert float(result.octoHeatPumpLivePerformance.powerInput.value) == 0.002 + assert float(result.octoHeatPumpLivePerformance.outdoorTemperature.value) == 18.400 + + assert float(result.octoHeatPumpLifetimePerformance.seasonalCoefficientOfPerformance) == 2.985 + assert float(result.octoHeatPumpLifetimePerformance.heatOutput.value) == 765.599 + assert float(result.octoHeatPumpLifetimePerformance.energyInput.value) == 256.439 \ No newline at end of file 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 c04f87f4..dfa0abd6 100644 --- a/tests/unit/coordinators/test_async_refresh_electricity_rates_data.py +++ b/tests/unit/coordinators/test_async_refresh_electricity_rates_data.py @@ -124,7 +124,6 @@ async def raise_no_active_tariff(*args, **kwargs): existing_rates, None, dispatches_result, - True, fire_event, raise_no_active_rate=raise_no_active_tariff ) @@ -172,7 +171,6 @@ async def raise_no_active_tariff(*args, **kwargs): existing_rates, None, dispatches_result, - True, fire_event, raise_no_active_rate=raise_no_active_tariff ) @@ -222,7 +220,6 @@ async def raise_no_active_tariff(*args, **kwargs): existing_rates, None, dispatches_result, - True, fire_event, raise_no_active_rate=raise_no_active_tariff ) @@ -289,7 +286,6 @@ async def raise_no_active_tariff(*args, **kwargs): existing_rates, None, dispatches_result, - True, fire_event, raise_no_active_rate=raise_no_active_tariff ) @@ -367,7 +363,6 @@ async def raise_no_active_tariff(*args, **kwargs): existing_rates, None, dispatches_result, - True, fire_event, raise_no_active_rate=raise_no_active_tariff ) @@ -428,7 +423,6 @@ async def raise_no_active_tariff(*args, **kwargs): existing_rates, None, dispatches_result, - True, fire_event, raise_no_active_rate=raise_no_active_tariff ) @@ -487,7 +481,6 @@ async def raise_no_active_tariff(*args, **kwargs): existing_rates, None, dispatches_result, - True, fire_event, raise_no_active_rate=raise_no_active_tariff ) @@ -552,7 +545,6 @@ async def raise_no_active_tariff(*args, **kwargs): existing_rates, None, dispatches_result, - True, fire_event, raise_no_active_rate=raise_no_active_tariff ) @@ -620,7 +612,6 @@ async def raise_no_active_tariff(*args, **kwargs): existing_rates, None, dispatches_result, - True, fire_event, raise_no_active_rate=raise_no_active_tariff ) @@ -708,7 +699,6 @@ async def raise_no_active_tariff(*args, **kwargs): existing_rates, None, dispatches_result, - True, fire_event, raise_no_active_rate=raise_no_active_tariff ) @@ -790,7 +780,6 @@ async def raise_no_active_tariff(*args, **kwargs): existing_rates, None, dispatches_result, - True, fire_event, raise_no_active_rate=raise_no_active_tariff ) @@ -884,7 +873,6 @@ async def raise_no_active_tariff(*args, **kwargs): existing_rates, None, dispatches_result, - True, fire_event, raise_no_active_rate=raise_no_active_tariff ) @@ -921,11 +909,7 @@ async def raise_no_active_tariff(*args, **kwargs): assert_raised_events(actual_fired_events, EVENT_ELECTRICITY_NEXT_DAY_RATES, expected_period_from + timedelta(days=2), expected_period_from + timedelta(days=3)) @pytest.mark.asyncio -@pytest.mark.parametrize("planned_dispatches_supported",[ - (True), - (False), -]) -async def test_when_dispatched_rates_provided_then_rates_are_adjusted_if_planned_dispatches_supported(planned_dispatches_supported: bool): +async def test_when_dispatched_rates_provided_then_rates_are_adjusted(): expected_period_from = (current - timedelta(days=1)).replace(hour=0, minute=0, second=0, microsecond=0) expected_period_to = (current + timedelta(days=2)).replace(hour=0, minute=0, second=0, microsecond=0) expected_rates = create_rate_data(expected_period_from, expected_period_to, [1, 2, 3, 4]) @@ -980,7 +964,6 @@ async def raise_no_active_tariff(*args, **kwargs): existing_rates, None, dispatches_result, - planned_dispatches_supported, fire_event, raise_no_active_rate=raise_no_active_tariff ) @@ -993,12 +976,12 @@ async def raise_no_active_tariff(*args, **kwargs): assert len(retrieved_rates.rates) == len(expected_retrieved_rates.rates) number_of_intelligent_rates = 0 - expected_number_of_intelligent_rates = 3 if planned_dispatches_supported else 0 + expected_number_of_intelligent_rates = 3 for index in range(len(retrieved_rates.rates)): expected_rate = expected_retrieved_rates.rates[index] actual_rate = retrieved_rates.rates[index] - if planned_dispatches_supported == True and actual_rate["start"] >= expected_dispatch_start and actual_rate["end"] <= expected_dispatch_end: + if actual_rate["start"] >= expected_dispatch_start and actual_rate["end"] <= expected_dispatch_end: assert "is_intelligent_adjusted" in actual_rate assert actual_rate["is_intelligent_adjusted"] == True assert actual_rate["value_inc_vat"] == 1 @@ -1053,7 +1036,6 @@ async def raise_no_active_tariff(*args, **kwargs): existing_rates, None, dispatches_result, - True, fire_event, raise_no_active_rate=raise_no_active_tariff ) @@ -1108,7 +1090,6 @@ async def raise_no_active_tariff(*args, **kwargs): existing_rates, None, dispatches_result, - True, fire_event, raise_no_active_rate=raise_no_active_tariff ) @@ -1180,7 +1161,6 @@ async def raise_no_active_tariff(*args, **kwargs): existing_rates, None, dispatches_result, - True, fire_event, raise_no_active_rate=raise_no_active_tariff ) @@ -1271,7 +1251,6 @@ async def raise_no_active_tariff(*args, **kwargs): existing_rates, None, dispatches_result, - True, fire_event, raise_no_active_rate=raise_no_active_tariff ) @@ -1308,12 +1287,7 @@ async def raise_no_active_tariff(*args, **kwargs): assert_raised_events(actual_fired_events, EVENT_ELECTRICITY_NEXT_DAY_RATES, expected_period_from + timedelta(days=2), expected_period_from + timedelta(days=3)) @pytest.mark.asyncio -@pytest.mark.parametrize("is_export_meter,planned_dispatches_supported",[ - (True, False), - (True, True), - (False, False), -]) -async def test_when_rates_next_refresh_is_in_the_future_dispatches_retrieved_before_rates_and_dispatches_not_valid_then_existing_rates_returned(is_export_meter: bool, planned_dispatches_supported: bool): +async def test_when_rates_next_refresh_is_in_the_future_dispatches_retrieved_before_rates_and_dispatches_not_valid_then_existing_rates_returned(): current = datetime.strptime("2023-07-14T10:30:01+01:00", "%Y-%m-%dT%H:%M:%S%z") expected_rates = create_rate_data(period_from, period_to, [1, 2]) mock_api_called = False @@ -1361,11 +1335,10 @@ async def raise_no_active_tariff(*args, **kwargs): mpan, serial_number, True, - is_export_meter, + True, existing_rates, None, dispatches_result, - planned_dispatches_supported, fire_event, raise_no_active_rate=raise_no_active_tariff ) @@ -1428,7 +1401,6 @@ async def raise_no_active_tariff(*args, **kwargs): existing_rates, None, dispatches_result, - True, fire_event, raise_no_active_rate=raise_no_active_tariff ) @@ -1487,7 +1459,6 @@ async def raise_no_active_tariff(*args, **kwargs): existing_rates, intelligent_device, dispatches_result, - True, fire_event, raise_no_active_rate=raise_no_active_tariff ) @@ -1552,7 +1523,6 @@ async def raise_no_active_tariff(*args, **kwargs): existing_rates, intelligent_device, dispatches_result, - True, fire_event, raise_no_active_rate=raise_no_active_tariff ) @@ -1644,7 +1614,6 @@ async def unique_rates_changed(name, metadata): existing_rates, None, None, - True, fire_event, raise_no_active_rate=raise_no_active_tariff, unique_rates_changed=unique_rates_changed @@ -1733,7 +1702,6 @@ async def raise_no_active_tariff(*args, **kwargs): existing_rates, None, dispatches_result, - True, fire_event, raise_no_active_rate=raise_no_active_tariff ) diff --git a/tests/unit/coordinators/test_async_refresh_intelligent_dispatches.py b/tests/unit/coordinators/test_async_refresh_intelligent_dispatches.py index 4420e411..1bd16edf 100644 --- a/tests/unit/coordinators/test_async_refresh_intelligent_dispatches.py +++ b/tests/unit/coordinators/test_async_refresh_intelligent_dispatches.py @@ -80,6 +80,7 @@ async def async_save_dispatches(*args, **kwargs): existing_dispatches, False, False, + True, async_save_dispatches ) @@ -122,6 +123,7 @@ async def async_save_dispatches(*args, **kwargs): existing_dispatches, False, False, + True, async_save_dispatches ) @@ -165,6 +167,7 @@ async def async_save_dispatches(*args, **kwargs): existing_dispatches, False, False, + True, async_save_dispatches ) @@ -207,6 +210,7 @@ async def async_save_dispatches(*args, **kwargs): existing_dispatches, True, False, + True, async_save_dispatches ) @@ -268,6 +272,7 @@ async def async_save_dispatches(*args, **kwargs): existing_dispatches, False, False, + True, async_save_dispatches ) @@ -315,6 +320,7 @@ async def async_save_dispatches(*args, **kwargs): existing_dispatches, False, False, + True, async_save_dispatches ) @@ -360,6 +366,7 @@ async def async_save_dispatches(*args, **kwargs): existing_dispatches, False, False, + True, async_save_dispatches ) @@ -404,6 +411,7 @@ async def async_save_dispatches(*args, **kwargs): existing_dispatches, False, False, + True, async_save_dispatches ) @@ -451,6 +459,7 @@ async def async_save_dispatches(*args, **kwargs): existing_dispatches, False, False, + True, async_save_dispatches ) @@ -500,6 +509,7 @@ async def async_save_dispatches(*args, **kwargs): existing_dispatches, False, False, + True, async_save_dispatches ) @@ -545,6 +555,7 @@ async def async_save_dispatches(*args, **kwargs): existing_dispatches, False, False, + True, async_save_dispatches ) @@ -594,6 +605,7 @@ async def async_save_dispatches(*args, **kwargs): existing_dispatches, False, True, + True, async_save_dispatches ) @@ -644,6 +656,7 @@ async def async_save_dispatches(*args, **kwargs): existing_dispatches, False, True, + True, async_save_dispatches ) @@ -704,6 +717,7 @@ async def async_save_dispatches(*args, **kwargs): existing_dispatches, False, True, + True, async_save_dispatches ) @@ -758,6 +772,7 @@ async def async_save_dispatches(*args, **kwargs): existing_dispatches, False, False, + True, async_save_dispatches ) @@ -809,6 +824,7 @@ async def async_save_dispatches(*args, **kwargs): existing_dispatches, False, False, + True, async_save_dispatches ) @@ -869,6 +885,7 @@ async def async_save_dispatches(*args, **kwargs): existing_dispatches, False, False, + True, async_save_dispatches ) @@ -929,6 +946,7 @@ async def async_save_dispatches(*args, **kwargs): existing_dispatches, False, False, + True, async_save_dispatches ) @@ -992,6 +1010,7 @@ async def async_save_dispatches(*args, **kwargs): existing_dispatches, False, False, + True, async_save_dispatches )