mirror of
https://github.com/home-assistant/core.git
synced 2026-09-28 02:18:10 -04:00
Add price type and interval options to EnergyZero energy price action (#181683)
This commit is contained in:
@@ -27,6 +27,10 @@ ATTR_CONFIG_ENTRY: Final = "config_entry"
|
|||||||
ATTR_START: Final = "start"
|
ATTR_START: Final = "start"
|
||||||
ATTR_END: Final = "end"
|
ATTR_END: Final = "end"
|
||||||
ATTR_INCL_VAT: Final = "incl_vat"
|
ATTR_INCL_VAT: Final = "incl_vat"
|
||||||
|
ATTR_PRICE_TYPE: Final = "price_type"
|
||||||
|
ATTR_INTERVAL: Final = "interval"
|
||||||
|
|
||||||
|
ENERGY_INTERVALS = {"hour": Interval.HOUR, "quarter": Interval.QUARTER}
|
||||||
|
|
||||||
GAS_SERVICE_NAME: Final = "get_gas_prices"
|
GAS_SERVICE_NAME: Final = "get_gas_prices"
|
||||||
ENERGY_SERVICE_NAME: Final = "get_energy_prices"
|
ENERGY_SERVICE_NAME: Final = "get_energy_prices"
|
||||||
@@ -43,6 +47,13 @@ SERVICE_SCHEMA: Final = vol.Schema(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ENERGY_SERVICE_SCHEMA: Final = SERVICE_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
vol.Optional(ATTR_PRICE_TYPE, default="market"): vol.In(("market", "all_in")),
|
||||||
|
vol.Optional(ATTR_INTERVAL, default="hour"): vol.In(ENERGY_INTERVALS),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ServicePriceType(Enum):
|
class ServicePriceType(Enum):
|
||||||
"""Type of service."""
|
"""Type of service."""
|
||||||
@@ -142,6 +153,11 @@ async def __get_prices(
|
|||||||
PriceType.MARKET_WITH_VAT if call.data[ATTR_INCL_VAT] else PriceType.MARKET
|
PriceType.MARKET_WITH_VAT if call.data[ATTR_INCL_VAT] else PriceType.MARKET
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if price_type is ServicePriceType.ENERGY and call.data[ATTR_PRICE_TYPE] == "all_in":
|
||||||
|
selected_price_type = (
|
||||||
|
PriceType.ALL_IN if call.data[ATTR_INCL_VAT] else PriceType.ALL_IN_EXCL_VAT
|
||||||
|
)
|
||||||
|
|
||||||
price_data: list[EnergyPrices] = []
|
price_data: list[EnergyPrices] = []
|
||||||
for day_offset in range((end_date - start_date).days + 1):
|
for day_offset in range((end_date - start_date).days + 1):
|
||||||
request_date = start_date + timedelta(days=day_offset)
|
request_date = start_date + timedelta(days=day_offset)
|
||||||
@@ -156,7 +172,7 @@ async def __get_prices(
|
|||||||
prices = coordinator.energyzero.get_electricity_prices(
|
prices = coordinator.energyzero.get_electricity_prices(
|
||||||
start_date=request_date,
|
start_date=request_date,
|
||||||
end_date=request_date,
|
end_date=request_date,
|
||||||
interval=Interval.HOUR,
|
interval=ENERGY_INTERVALS[call.data[ATTR_INTERVAL]],
|
||||||
price_type=selected_price_type,
|
price_type=selected_price_type,
|
||||||
local_tz=local_tz,
|
local_tz=local_tz,
|
||||||
)
|
)
|
||||||
@@ -190,6 +206,6 @@ def async_setup_services(hass: HomeAssistant) -> None:
|
|||||||
DOMAIN,
|
DOMAIN,
|
||||||
ENERGY_SERVICE_NAME,
|
ENERGY_SERVICE_NAME,
|
||||||
partial(__get_prices, price_type=ServicePriceType.ENERGY),
|
partial(__get_prices, price_type=ServicePriceType.ENERGY),
|
||||||
schema=SERVICE_SCHEMA,
|
schema=ENERGY_SERVICE_SCHEMA,
|
||||||
supports_response=SupportsResponse.ONLY,
|
supports_response=SupportsResponse.ONLY,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -32,6 +32,22 @@ get_energy_prices:
|
|||||||
default: true
|
default: true
|
||||||
selector:
|
selector:
|
||||||
boolean:
|
boolean:
|
||||||
|
price_type:
|
||||||
|
default: market
|
||||||
|
selector:
|
||||||
|
select:
|
||||||
|
translation_key: price_type
|
||||||
|
options:
|
||||||
|
- market
|
||||||
|
- all_in
|
||||||
|
interval:
|
||||||
|
default: hour
|
||||||
|
selector:
|
||||||
|
select:
|
||||||
|
translation_key: interval
|
||||||
|
options:
|
||||||
|
- hour
|
||||||
|
- quarter
|
||||||
start:
|
start:
|
||||||
required: false
|
required: false
|
||||||
example: "2023-01-01 00:00:00"
|
example: "2023-01-01 00:00:00"
|
||||||
|
|||||||
@@ -87,6 +87,18 @@
|
|||||||
"hourly": "Hourly",
|
"hourly": "Hourly",
|
||||||
"quarter_hourly": "Quarter-hourly"
|
"quarter_hourly": "Quarter-hourly"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"interval": {
|
||||||
|
"options": {
|
||||||
|
"hour": "[%key:component::energyzero::selector::electricity_price_interval::options::hourly%]",
|
||||||
|
"quarter": "[%key:component::energyzero::selector::electricity_price_interval::options::quarter_hourly%]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"price_type": {
|
||||||
|
"options": {
|
||||||
|
"all_in": "All-in",
|
||||||
|
"market": "Market"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"services": {
|
"services": {
|
||||||
@@ -105,6 +117,14 @@
|
|||||||
"description": "[%key:component::energyzero::services::get_gas_prices::fields::incl_vat::description%]",
|
"description": "[%key:component::energyzero::services::get_gas_prices::fields::incl_vat::description%]",
|
||||||
"name": "[%key:component::energyzero::services::get_gas_prices::fields::incl_vat::name%]"
|
"name": "[%key:component::energyzero::services::get_gas_prices::fields::incl_vat::name%]"
|
||||||
},
|
},
|
||||||
|
"interval": {
|
||||||
|
"description": "The interval of electricity prices to retrieve. Defaults to hourly, independently of the electricity price interval configured for entities.",
|
||||||
|
"name": "Interval"
|
||||||
|
},
|
||||||
|
"price_type": {
|
||||||
|
"description": "The type of electricity prices to retrieve. Defaults to market prices.",
|
||||||
|
"name": "Price type"
|
||||||
|
},
|
||||||
"start": {
|
"start": {
|
||||||
"description": "[%key:component::energyzero::services::get_gas_prices::fields::start::description%]",
|
"description": "[%key:component::energyzero::services::get_gas_prices::fields::start::description%]",
|
||||||
"name": "[%key:component::energyzero::services::get_gas_prices::fields::start::name%]"
|
"name": "[%key:component::energyzero::services::get_gas_prices::fields::start::name%]"
|
||||||
|
|||||||
@@ -1,16 +1,25 @@
|
|||||||
"""Tests for the services provided by the EnergyZero integration."""
|
"""Tests for the services provided by the EnergyZero integration."""
|
||||||
|
|
||||||
from datetime import UTC, date, datetime
|
from datetime import UTC, date, datetime, timedelta
|
||||||
import re
|
import re
|
||||||
from unittest.mock import AsyncMock
|
from unittest.mock import AsyncMock, call
|
||||||
from zoneinfo import ZoneInfo
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
from energyzero import EnergyPrices, EnergyZeroNoDataError, PriceType, TimeRange
|
from energyzero import (
|
||||||
|
EnergyPrices,
|
||||||
|
EnergyZeroNoDataError,
|
||||||
|
Interval,
|
||||||
|
PriceType,
|
||||||
|
TimeRange,
|
||||||
|
)
|
||||||
import pytest
|
import pytest
|
||||||
from syrupy.assertion import SnapshotAssertion
|
from syrupy.assertion import SnapshotAssertion
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components.energyzero.const import DOMAIN
|
from homeassistant.components.energyzero.const import (
|
||||||
|
CONF_ELECTRICITY_PRICE_INTERVAL,
|
||||||
|
DOMAIN,
|
||||||
|
)
|
||||||
from homeassistant.components.energyzero.services import (
|
from homeassistant.components.energyzero.services import (
|
||||||
ATTR_CONFIG_ENTRY,
|
ATTR_CONFIG_ENTRY,
|
||||||
ENERGY_SERVICE_NAME,
|
ENERGY_SERVICE_NAME,
|
||||||
@@ -514,12 +523,20 @@ async def test_service_called_with_unloaded_entry(
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures("init_integration")
|
@pytest.mark.usefixtures("init_integration")
|
||||||
@pytest.mark.parametrize("service", [GAS_SERVICE_NAME, ENERGY_SERVICE_NAME])
|
@pytest.mark.parametrize(
|
||||||
|
("service", "service_data"),
|
||||||
|
[
|
||||||
|
(GAS_SERVICE_NAME, {}),
|
||||||
|
(ENERGY_SERVICE_NAME, {}),
|
||||||
|
(ENERGY_SERVICE_NAME, {"price_type": "all_in", "interval": "quarter"}),
|
||||||
|
],
|
||||||
|
)
|
||||||
async def test_service_no_data_returns_validation_error(
|
async def test_service_no_data_returns_validation_error(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
mock_energyzero: AsyncMock,
|
mock_energyzero: AsyncMock,
|
||||||
mock_config_entry: MockConfigEntry,
|
mock_config_entry: MockConfigEntry,
|
||||||
service: str,
|
service: str,
|
||||||
|
service_data: dict[str, str],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test backend no-data errors are surfaced as service validation errors."""
|
"""Test backend no-data errors are surfaced as service validation errors."""
|
||||||
method = (
|
method = (
|
||||||
@@ -541,7 +558,288 @@ async def test_service_no_data_returns_validation_error(
|
|||||||
{
|
{
|
||||||
ATTR_CONFIG_ENTRY: mock_config_entry.entry_id,
|
ATTR_CONFIG_ENTRY: mock_config_entry.entry_id,
|
||||||
"incl_vat": True,
|
"incl_vat": True,
|
||||||
|
**service_data,
|
||||||
},
|
},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
return_response=True,
|
return_response=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("entity_interval", ["hourly", "quarter_hourly"])
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("interval_data", "expected_interval"),
|
||||||
|
[
|
||||||
|
pytest.param({}, Interval.HOUR, id="default-hour"),
|
||||||
|
pytest.param({"interval": "hour"}, Interval.HOUR, id="hour"),
|
||||||
|
pytest.param({"interval": "quarter"}, Interval.QUARTER, id="quarter"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("price_data", "incl_vat", "expected_price_type"),
|
||||||
|
[
|
||||||
|
pytest.param({}, True, PriceType.MARKET_WITH_VAT, id="default-vat"),
|
||||||
|
pytest.param({}, False, PriceType.MARKET, id="default-no-vat"),
|
||||||
|
pytest.param(
|
||||||
|
{"price_type": "market"}, True, PriceType.MARKET_WITH_VAT, id="market-vat"
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
{"price_type": "market"}, False, PriceType.MARKET, id="market-no-vat"
|
||||||
|
),
|
||||||
|
pytest.param({"price_type": "all_in"}, True, PriceType.ALL_IN, id="all-in-vat"),
|
||||||
|
pytest.param(
|
||||||
|
{"price_type": "all_in"},
|
||||||
|
False,
|
||||||
|
PriceType.ALL_IN_EXCL_VAT,
|
||||||
|
id="all-in-no-vat",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_energy_service_options(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_energyzero: AsyncMock,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
entity_interval: str,
|
||||||
|
interval_data: dict[str, str],
|
||||||
|
expected_interval: Interval,
|
||||||
|
price_data: dict[str, str],
|
||||||
|
incl_vat: bool,
|
||||||
|
expected_price_type: PriceType,
|
||||||
|
) -> None:
|
||||||
|
"""Action options and defaults are independent of entity configuration."""
|
||||||
|
mock_config_entry.add_to_hass(hass)
|
||||||
|
hass.config_entries.async_update_entry(
|
||||||
|
mock_config_entry, options={CONF_ELECTRICITY_PRICE_INTERVAL: entity_interval}
|
||||||
|
)
|
||||||
|
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
coordinator = mock_config_entry.runtime_data
|
||||||
|
coordinator_data = coordinator.data
|
||||||
|
entity_states = hass.states.async_all()
|
||||||
|
mock_energyzero.reset_mock()
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
ENERGY_SERVICE_NAME,
|
||||||
|
{
|
||||||
|
ATTR_CONFIG_ENTRY: mock_config_entry.entry_id,
|
||||||
|
"incl_vat": incl_vat,
|
||||||
|
**price_data,
|
||||||
|
**interval_data,
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
return_response=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
mock_energyzero.get_electricity_prices.assert_awaited_once_with(
|
||||||
|
start_date=date(2026, 4, 10),
|
||||||
|
end_date=date(2026, 4, 10),
|
||||||
|
interval=expected_interval,
|
||||||
|
price_type=expected_price_type,
|
||||||
|
local_tz=ZoneInfo(hass.config.time_zone),
|
||||||
|
)
|
||||||
|
mock_energyzero.get_gas_prices.assert_not_awaited()
|
||||||
|
assert coordinator.data is coordinator_data
|
||||||
|
assert hass.states.async_all() == entity_states
|
||||||
|
assert mock_config_entry.options == {
|
||||||
|
CONF_ELECTRICITY_PRICE_INTERVAL: entity_interval
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("init_integration")
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("start", "end", "first_timestamp", "period_count"),
|
||||||
|
[
|
||||||
|
pytest.param(
|
||||||
|
"2026-04-10", "2026-04-10", "2026-04-09T22:00:00+00:00", 96, id="date-only"
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
"2026-04-10 00:07:00",
|
||||||
|
"2026-04-10 00:38:00",
|
||||||
|
"2026-04-09T22:00:00+00:00",
|
||||||
|
3,
|
||||||
|
id="partial-periods",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
"2026-04-10 00:15:00",
|
||||||
|
"2026-04-10 00:15:00",
|
||||||
|
"2026-04-09T22:00:00+00:00",
|
||||||
|
96,
|
||||||
|
id="equal-times-full-day",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
"2026-04-10 00:15:00",
|
||||||
|
"2026-04-10 00:30:00",
|
||||||
|
"2026-04-09T22:15:00+00:00",
|
||||||
|
1,
|
||||||
|
id="exact-boundaries",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
"2026-04-10 23:53:00+02:00",
|
||||||
|
"2026-04-11 00:07:00+02:00",
|
||||||
|
"2026-04-10T21:45:00+00:00",
|
||||||
|
2,
|
||||||
|
id="multiple-days",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
"2026-03-29", "2026-03-29", "2026-03-28T23:00:00+00:00", 92, id="spring-dst"
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
"2026-10-25",
|
||||||
|
"2026-10-25",
|
||||||
|
"2026-10-24T22:00:00+00:00",
|
||||||
|
100,
|
||||||
|
id="autumn-dst",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
"2026-03-29 01:53:00+01:00",
|
||||||
|
"2026-03-29 03:07:00+02:00",
|
||||||
|
"2026-03-29T00:45:00+00:00",
|
||||||
|
2,
|
||||||
|
id="spring-overlap",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
"2026-10-25 02:53:00+02:00",
|
||||||
|
"2026-10-25 02:07:00+01:00",
|
||||||
|
"2026-10-25T00:45:00+00:00",
|
||||||
|
2,
|
||||||
|
id="autumn-overlap",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_energy_service_quarter_ranges(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_energyzero: AsyncMock,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
start: str,
|
||||||
|
end: str,
|
||||||
|
first_timestamp: str,
|
||||||
|
period_count: int,
|
||||||
|
) -> None:
|
||||||
|
"""Filter actual quarter-hour ranges, including partial periods and DST."""
|
||||||
|
await hass.config.async_set_time_zone("Europe/Amsterdam")
|
||||||
|
local_tz = ZoneInfo(hass.config.time_zone)
|
||||||
|
first_day = date.fromisoformat(start[:10])
|
||||||
|
last_day = date.fromisoformat(end[:10])
|
||||||
|
days = [
|
||||||
|
first_day + timedelta(days=index)
|
||||||
|
for index in range((last_day - first_day).days + 1)
|
||||||
|
]
|
||||||
|
step = timedelta(minutes=15)
|
||||||
|
datasets = []
|
||||||
|
for day in days:
|
||||||
|
day_start = datetime.combine(day, datetime.min.time(), local_tz).astimezone(UTC)
|
||||||
|
day_end = datetime.combine(
|
||||||
|
day + timedelta(days=1), datetime.min.time(), local_tz
|
||||||
|
).astimezone(UTC)
|
||||||
|
datasets.append(
|
||||||
|
EnergyPrices(
|
||||||
|
prices={
|
||||||
|
TimeRange(
|
||||||
|
day_start + index * step, day_start + (index + 1) * step
|
||||||
|
): 0.25
|
||||||
|
for index in range((day_end - day_start) // step)
|
||||||
|
},
|
||||||
|
average_price=0.25,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
mock_energyzero.reset_mock()
|
||||||
|
mock_energyzero.get_electricity_prices.side_effect = datasets
|
||||||
|
|
||||||
|
response = await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
ENERGY_SERVICE_NAME,
|
||||||
|
{
|
||||||
|
ATTR_CONFIG_ENTRY: mock_config_entry.entry_id,
|
||||||
|
"incl_vat": True,
|
||||||
|
"price_type": "all_in",
|
||||||
|
"interval": "quarter",
|
||||||
|
"start": start,
|
||||||
|
"end": end,
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
return_response=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
first = datetime.fromisoformat(first_timestamp)
|
||||||
|
assert response == {
|
||||||
|
"prices": [
|
||||||
|
{
|
||||||
|
"price": 0.25,
|
||||||
|
"timestamp": str(first + index * step),
|
||||||
|
"start": str(first + index * step),
|
||||||
|
"end": str(first + (index + 1) * step),
|
||||||
|
}
|
||||||
|
for index in range(period_count)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
assert mock_energyzero.get_electricity_prices.await_args_list == [
|
||||||
|
call(
|
||||||
|
start_date=day,
|
||||||
|
end_date=day,
|
||||||
|
interval=Interval.QUARTER,
|
||||||
|
price_type=PriceType.ALL_IN,
|
||||||
|
local_tz=local_tz,
|
||||||
|
)
|
||||||
|
for day in days
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("init_integration")
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("service", "service_data"),
|
||||||
|
[
|
||||||
|
(ENERGY_SERVICE_NAME, {"price_type": "market_with_vat"}),
|
||||||
|
(ENERGY_SERVICE_NAME, {"interval": "day"}),
|
||||||
|
(GAS_SERVICE_NAME, {"price_type": "all_in"}),
|
||||||
|
(GAS_SERVICE_NAME, {"interval": "quarter"}),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_service_rejects_unsupported_options(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_energyzero: AsyncMock,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
service: str,
|
||||||
|
service_data: dict[str, str],
|
||||||
|
) -> None:
|
||||||
|
"""Only the electricity action accepts the supported new field values."""
|
||||||
|
mock_energyzero.reset_mock()
|
||||||
|
with pytest.raises(vol.Invalid):
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
service,
|
||||||
|
{
|
||||||
|
ATTR_CONFIG_ENTRY: mock_config_entry.entry_id,
|
||||||
|
"incl_vat": True,
|
||||||
|
**service_data,
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
return_response=True,
|
||||||
|
)
|
||||||
|
mock_energyzero.get_electricity_prices.assert_not_awaited()
|
||||||
|
mock_energyzero.get_gas_prices.assert_not_awaited()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("init_integration")
|
||||||
|
async def test_energy_service_quarter_invalid_range(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_energyzero: AsyncMock,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
) -> None:
|
||||||
|
"""Reject reversed quarter-hour ranges before calling the API."""
|
||||||
|
mock_energyzero.reset_mock()
|
||||||
|
with pytest.raises(ServiceValidationError, match="Invalid date range provided"):
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
ENERGY_SERVICE_NAME,
|
||||||
|
{
|
||||||
|
ATTR_CONFIG_ENTRY: mock_config_entry.entry_id,
|
||||||
|
"incl_vat": True,
|
||||||
|
"price_type": "all_in",
|
||||||
|
"interval": "quarter",
|
||||||
|
"start": "2026-04-10 00:15:00",
|
||||||
|
"end": "2026-04-10 00:10:00",
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
return_response=True,
|
||||||
|
)
|
||||||
|
mock_energyzero.get_electricity_prices.assert_not_awaited()
|
||||||
|
|||||||
Reference in New Issue
Block a user