Skip to content

Commit

Permalink
feat: Added new service for refreshing intelligent dispatches. This h…
Browse files Browse the repository at this point in the history
…as some caveats, so please review the docs (4 hours 45 minutes dev time)
  • Loading branch information
BottlecapDave authored Jan 31, 2025
1 parent 3c61692 commit 11cc47c
Show file tree
Hide file tree
Showing 22 changed files with 449 additions and 171 deletions.
4 changes: 4 additions & 0 deletions _docs/entities/heat_pump.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,7 @@ This represents the current outdoor temperature as observed by the heat pump.

!!! note
As the integration uses cloud polling this will inherently have a delay.

## Services

There are some services available relating to these entities that you might find useful. They can be found in the [services docs](../services.md#heat-pump).
4 changes: 2 additions & 2 deletions _docs/entities/octoplus.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Each available event item will include the following attributes
| Attribute | Type | Description |
|-----------|------|-------------|
| `id` | `integer` | The id of the event |
| `code` | `string` | The event code of the event. This will be required to join via the [join service](../services.md) |
| `code` | `string` | The event code of the event. This will be required to join via the [join service](../services.md#octopus_energyjoin_octoplus_saving_session_event) |
| `start` | `datetime` | The date/time the event starts |
| `end` | `datetime` | The date/time the event starts |
| `duration_in_minutes` | `integer` | The duration of the event in minutes |
Expand Down Expand Up @@ -208,5 +208,5 @@ Each item within `baselines` consists of the following attributes

## Services

There are some services available relating to these entities that you might find useful. They can be found in the [services docs](../services.md).
There are some services available relating to these entities that you might find useful. They can be found in the [services docs](../services.md#octoplus).

2 changes: 1 addition & 1 deletion _docs/entities/wheel_of_fortune.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ The number of spins remaining for gas supply

## Services

There are some services available relating to these entities that you might find useful. They can be found in the [services docs](../services.md).
There are some services available relating to these entities that you might find useful. They can be found in the [services docs](../services.md#wheel-of-fortune).
2 changes: 1 addition & 1 deletion _docs/events.md
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ Each available event item will include the following attributes
| Attribute | Type | Description |
|-----------|------|-------------|
| `id` | `integer` | The id of the event |
| `code` | `string` | The event code of the event. This will be required to join via the [join service](./services.md) |
| `code` | `string` | The event code of the event. This will be required to join via the [join service](./services.md#octopus_energyjoin_octoplus_saving_session_event) |
| `start` | `datetime` | The date/time the event starts |
| `end` | `datetime` | The date/time the event starts |
| `duration_in_minutes` | `integer` | The duration of the event in minutes |
Expand Down
176 changes: 104 additions & 72 deletions _docs/services.md

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions _docs/setup/account.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ There are some tariffs where direct debit and non direct debit rates are availab

It might take a couple of minutes for these changes to reflect once changed.

## Manually refresh intelligent dispatches

By default, intelligent dispatches are retrieved [periodically](../faq.md#how-often-is-data-refreshed). This is fine for most scenarios, but this can be a little slow depending on what else you're doing off the back of the dispatches. If you have other ways of knowing when new dispatches should be available (e.g. your charger changes to a charging state or a manual button in your HA dashboard), then you can turn on `Manually refresh intelligent dispatches`. This will disable the periodic refreshing and expose a [service](../services.md#octopus_energyrefresh_intelligent_dispatches) which can be called to refresh the dispatches.

## Home Pro

If you are lucky enough to own an [Octopus Home Pro](https://forum.octopus.energy/t/for-the-pro-user/8453/2352/), you can now receive this data locally from within Home Assistant.
Expand Down
2 changes: 1 addition & 1 deletion _docs/setup/cost_tracker.md
Original file line number Diff line number Diff line change
Expand Up @@ -292,4 +292,4 @@ This is the total cost of the tracked entity for the current month during peak h

## Services

There are services available associated with cost tracker sensors. Please review them in the [services doc](../services.md#octopus_energyupdate_cost_tracker).
There are services available associated with cost tracker sensors. Please review them in the [services doc](../services.md#cost-trackers).
2 changes: 1 addition & 1 deletion _docs/setup/rolling_target_rate.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,4 +175,4 @@ The following attributes are available on each sensor

## Services

There are services available associated with target rate sensors. Please review them in the [services doc](../services.md).
There are services available associated with target rate sensors. Please review them in the [services doc](../services.md#rolling-target-rates).
2 changes: 1 addition & 1 deletion _docs/setup/target_rate.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ The following attributes are available on each sensor

## Services

There are services available associated with target rate sensors. Please review them in the [services doc](../services.md).
There are services available associated with target rate sensors. Please review them in the [services doc](../services.md#target-rates).

## Examples

Expand Down
34 changes: 30 additions & 4 deletions custom_components/octopus_energy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
from .storage.heat_pump import async_load_cached_heat_pump, async_save_cached_heat_pump

from .const import (
CONFIG_FAVOUR_DIRECT_DEBIT_RATES,
CONFIG_MAIN_FAVOUR_DIRECT_DEBIT_RATES,
CONFIG_KIND,
CONFIG_KIND_ACCOUNT,
CONFIG_KIND_ROLLING_TARGET_RATE,
Expand All @@ -48,6 +48,7 @@
CONFIG_KIND_TARGET_RATE,
CONFIG_MAIN_HOME_PRO_ADDRESS,
CONFIG_MAIN_HOME_PRO_API_KEY,
CONFIG_MAIN_INTELLIGENT_MANUAL_DISPATCHES,
CONFIG_MAIN_OLD_API_KEY,
CONFIG_VERSION,
DATA_HEAT_PUMP_CONFIGURATION_AND_STATUS_KEY,
Expand All @@ -67,6 +68,7 @@
DATA_CLIENT,
DATA_ELECTRICITY_RATES_COORDINATOR_KEY,
DATA_ACCOUNT,
REFRESH_RATE_IN_MINUTES_INTELLIGENT,
REPAIR_ACCOUNT_NOT_FOUND,
REPAIR_INVALID_API_KEY,
REPAIR_UNIQUE_RATES_CHANGED_KEY,
Expand Down Expand Up @@ -279,8 +281,8 @@ async def async_setup_dependencies(hass, config):
gas_price_cap = config[CONFIG_MAIN_GAS_PRICE_CAP]

favour_direct_debit_rates = True
if CONFIG_FAVOUR_DIRECT_DEBIT_RATES in config:
favour_direct_debit_rates = config[CONFIG_FAVOUR_DIRECT_DEBIT_RATES]
if CONFIG_MAIN_FAVOUR_DIRECT_DEBIT_RATES in config:
favour_direct_debit_rates = config[CONFIG_MAIN_FAVOUR_DIRECT_DEBIT_RATES]

_LOGGER.info(f'electricity_price_cap: {electricity_price_cap}')
_LOGGER.info(f'gas_price_cap: {gas_price_cap}')
Expand Down Expand Up @@ -389,6 +391,7 @@ async def async_setup_dependencies(hass, config):
intelligent_serial_number = meter["serial_number"]
break

intelligent_manual_service = False
intelligent_device = None
if has_intelligent_tariff or should_mock_intelligent_data:
client: OctopusEnergyApiClient = hass.data[DOMAIN][account_id][DATA_CLIENT]
Expand All @@ -415,6 +418,9 @@ async def async_setup_dependencies(hass, config):
hass.data[DOMAIN][account_id][DATA_INTELLIGENT_MPAN] = intelligent_mpan
hass.data[DOMAIN][account_id][DATA_INTELLIGENT_SERIAL_NUMBER] = intelligent_serial_number

if CONFIG_MAIN_INTELLIGENT_MANUAL_DISPATCHES not in config or config[CONFIG_MAIN_INTELLIGENT_MANUAL_DISPATCHES] == False:
intelligent_manual_service = True

await async_save_cached_intelligent_device(hass, account_id, intelligent_device)

intelligent_features = get_intelligent_features(intelligent_device.provider) if intelligent_device is not None else None
Expand All @@ -430,6 +436,21 @@ async def async_setup_dependencies(hass, config):
translation_placeholders={ "account_id": account_id, "provider": intelligent_device.provider },
)

intelligent_repair_key = f"intelligent_manual_service_{account_id}"
if intelligent_manual_service and intelligent_features is not None and intelligent_features.planned_dispatches_supported:
ir.async_create_issue(
hass,
DOMAIN,
intelligent_repair_key,
is_fixable=False,
severity=ir.IssueSeverity.WARNING,
learn_more_url="https://bottlecapdave.github.io/HomeAssistant-OctopusEnergy/services/#octopus_energyrefresh_intelligent_dispatches",
translation_key="intelligent_manual_service",
translation_placeholders={ "account_id": account_id, "polling_time": REFRESH_RATE_IN_MINUTES_INTELLIGENT },
)
else:
ir.async_delete_issue(hass, DOMAIN, intelligent_repair_key)

for point in account_info["electricity_meter_points"]:
# We only care about points that have active agreements
electricity_tariff = get_active_tariff(now, point["agreements"])
Expand Down Expand Up @@ -468,7 +489,12 @@ async def async_setup_dependencies(hass, config):

await async_setup_account_info_coordinator(hass, account_id)

await async_setup_intelligent_dispatches_coordinator(hass, account_id, account_debug_override.mock_intelligent_controls if account_debug_override is not None else False)
await async_setup_intelligent_dispatches_coordinator(
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
)

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)

Expand Down
2 changes: 2 additions & 0 deletions custom_components/octopus_energy/api_client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1873,6 +1873,8 @@ async def __async_read_response__(self, response, url, ignore_errors = False):

_LOGGER.info(f"Response received - {url} ({request_context}) - Unexpected response received: {response.status}; {text}")
return None

_LOGGER.debug(f'Response received - {url} ({request_context}) - Successful response')

data_as_json = None
try:
Expand Down
15 changes: 15 additions & 0 deletions custom_components/octopus_energy/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
CONFIG_KIND_ROLLING_TARGET_RATE,
CONFIG_KIND_TARGET_RATE,
CONFIG_ACCOUNT_ID,
CONFIG_MAIN_INTELLIGENT_MANUAL_DISPATCHES,
DATA_FREE_ELECTRICITY_SESSIONS_COORDINATOR,
DATA_GREENNESS_FORECAST_COORDINATOR,
DATA_INTELLIGENT_DEVICE,
Expand Down Expand Up @@ -139,6 +140,20 @@ async def async_setup_main_sensors(hass, entry, async_add_entities):
intelligent_mpan = hass.data[DOMAIN][account_id][DATA_INTELLIGENT_MPAN] if DATA_INTELLIGENT_MPAN in hass.data[DOMAIN][account_id] else None
intelligent_serial_number = hass.data[DOMAIN][account_id][DATA_INTELLIGENT_SERIAL_NUMBER] if DATA_INTELLIGENT_SERIAL_NUMBER in hass.data[DOMAIN][account_id] else None
if intelligent_device is not None and intelligent_mpan is not None and intelligent_serial_number is not None:

if CONFIG_MAIN_INTELLIGENT_MANUAL_DISPATCHES in config and config[CONFIG_MAIN_INTELLIGENT_MANUAL_DISPATCHES] == True:
platform = entity_platform.async_get_current_platform()
platform.async_register_entity_service(
"refresh_intelligent_dispatches",
vol.All(
cv.make_entity_service_schema(
{},
extra=vol.ALLOW_EXTRA,
),
),
"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)]
Expand Down
9 changes: 6 additions & 3 deletions custom_components/octopus_energy/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@
from .config.main import async_validate_main_config, merge_main_config
from .const import (
CONFIG_COST_TRACKER_MANUAL_RESET,
CONFIG_FAVOUR_DIRECT_DEBIT_RATES,
CONFIG_MAIN_FAVOUR_DIRECT_DEBIT_RATES,
CONFIG_KIND_ROLLING_TARGET_RATE,
CONFIG_MAIN_HOME_PRO_ADDRESS,
CONFIG_MAIN_HOME_PRO_API_KEY,
CONFIG_MAIN_INTELLIGENT_MANUAL_DISPATCHES,
CONFIG_ROLLING_TARGET_HOURS_LOOK_AHEAD,
CONFIG_TARGET_TARGET_TIMES_EVALUATION_MODE,
CONFIG_TARGET_TARGET_TIMES_EVALUATION_MODE_ALL_IN_FUTURE_OR_PAST,
Expand Down Expand Up @@ -798,7 +799,8 @@ async def __async_setup_main_schema__(self, config, errors):
vol.Required(CONFIG_MAIN_LIVE_GAS_CONSUMPTION_REFRESH_IN_MINUTES): cv.positive_int,
vol.Optional(CONFIG_MAIN_ELECTRICITY_PRICE_CAP): cv.positive_float,
vol.Optional(CONFIG_MAIN_GAS_PRICE_CAP): cv.positive_float,
vol.Required(CONFIG_FAVOUR_DIRECT_DEBIT_RATES): bool,
vol.Required(CONFIG_MAIN_FAVOUR_DIRECT_DEBIT_RATES): bool,
vol.Required(CONFIG_MAIN_INTELLIGENT_MANUAL_DISPATCHES): bool,
}),
{
CONFIG_MAIN_API_KEY: config[CONFIG_MAIN_API_KEY],
Expand All @@ -810,7 +812,8 @@ async def __async_setup_main_schema__(self, config, errors):
CONFIG_MAIN_LIVE_GAS_CONSUMPTION_REFRESH_IN_MINUTES: live_gas_consumption_refresh_in_minutes,
CONFIG_MAIN_ELECTRICITY_PRICE_CAP: config[CONFIG_MAIN_ELECTRICITY_PRICE_CAP] if CONFIG_MAIN_ELECTRICITY_PRICE_CAP in config else None,
CONFIG_MAIN_GAS_PRICE_CAP: config[CONFIG_MAIN_GAS_PRICE_CAP] if CONFIG_MAIN_GAS_PRICE_CAP in config else None,
CONFIG_FAVOUR_DIRECT_DEBIT_RATES: config[CONFIG_FAVOUR_DIRECT_DEBIT_RATES] if CONFIG_FAVOUR_DIRECT_DEBIT_RATES in config else True
CONFIG_MAIN_FAVOUR_DIRECT_DEBIT_RATES: config[CONFIG_MAIN_FAVOUR_DIRECT_DEBIT_RATES] if CONFIG_MAIN_FAVOUR_DIRECT_DEBIT_RATES in config else True,
CONFIG_MAIN_INTELLIGENT_MANUAL_DISPATCHES: config[CONFIG_MAIN_INTELLIGENT_MANUAL_DISPATCHES] if CONFIG_MAIN_INTELLIGENT_MANUAL_DISPATCHES in config else False,
}
),
errors=errors
Expand Down
6 changes: 4 additions & 2 deletions custom_components/octopus_energy/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@
CONFIG_MAIN_GAS_PRICE_CAP = "gas_price_cap"
CONFIG_MAIN_HOME_PRO_ADDRESS = "home_pro_address"
CONFIG_MAIN_HOME_PRO_API_KEY = "home_pro_api_key"
CONFIG_FAVOUR_DIRECT_DEBIT_RATES = "favour_direct_debit_rates"
CONFIG_MAIN_FAVOUR_DIRECT_DEBIT_RATES = "favour_direct_debit_rates"
CONFIG_MAIN_INTELLIGENT_MANUAL_DISPATCHES = "intelligent_manual_dispatches"

CONFIG_DEFAULT_LIVE_ELECTRICITY_CONSUMPTION_REFRESH_IN_MINUTES = 1
CONFIG_DEFAULT_LIVE_GAS_CONSUMPTION_REFRESH_IN_MINUTES = 2
Expand Down Expand Up @@ -188,7 +189,8 @@
vol.Required(CONFIG_MAIN_LIVE_GAS_CONSUMPTION_REFRESH_IN_MINUTES, default=CONFIG_DEFAULT_LIVE_ELECTRICITY_CONSUMPTION_REFRESH_IN_MINUTES): cv.positive_int,
vol.Optional(CONFIG_MAIN_ELECTRICITY_PRICE_CAP): cv.positive_float,
vol.Optional(CONFIG_MAIN_GAS_PRICE_CAP): cv.positive_float,
vol.Required(CONFIG_FAVOUR_DIRECT_DEBIT_RATES): bool
vol.Required(CONFIG_MAIN_FAVOUR_DIRECT_DEBIT_RATES): bool,
vol.Required(CONFIG_MAIN_INTELLIGENT_MANUAL_DISPATCHES): bool,
})

EVENT_ELECTRICITY_PREVIOUS_DAY_RATES = "octopus_energy_electricity_previous_day_rates"
Expand Down
Loading

0 comments on commit 11cc47c

Please sign in to comment.