mirror of
https://github.com/home-assistant/core.git
synced 2026-09-14 12:39:58 +01:00
243 lines
8.2 KiB
Python
243 lines
8.2 KiB
Python
"""Tests for the EnergyZero integration."""
|
|
|
|
from datetime import date
|
|
from unittest.mock import MagicMock, call, patch
|
|
from zoneinfo import ZoneInfo
|
|
|
|
from energyzero import EnergyZeroConnectionError, Interval, PriceType
|
|
from freezegun.api import FrozenDateTimeFactory
|
|
import pytest
|
|
|
|
from homeassistant.components.energyzero.const import (
|
|
CONF_ELECTRICITY_PRICE_INTERVAL,
|
|
DOMAIN,
|
|
ELECTRICITY_INTERVALS,
|
|
SCAN_INTERVAL,
|
|
)
|
|
from homeassistant.config_entries import ConfigEntryState
|
|
from homeassistant.core import HomeAssistant
|
|
|
|
from tests.common import (
|
|
MockConfigEntry,
|
|
async_fire_time_changed,
|
|
async_load_json_object_fixture,
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("options", "interval"),
|
|
[
|
|
pytest.param({}, Interval.HOUR, id="existing"),
|
|
pytest.param(
|
|
{CONF_ELECTRICITY_PRICE_INTERVAL: "hourly"}, Interval.HOUR, id="hourly"
|
|
),
|
|
pytest.param(
|
|
{CONF_ELECTRICITY_PRICE_INTERVAL: "quarter_hourly"},
|
|
Interval.QUARTER,
|
|
id="quarter_hourly",
|
|
),
|
|
],
|
|
)
|
|
@pytest.mark.freeze_time("2026-04-10 20:32:59")
|
|
async def test_coordinator_requests_both_prices_with_vat(
|
|
hass: HomeAssistant,
|
|
mock_config_entry: MockConfigEntry,
|
|
mock_energyzero: MagicMock,
|
|
options: dict[str, str],
|
|
interval: Interval,
|
|
) -> None:
|
|
"""Test both VAT-inclusive streams share a request and the configured interval."""
|
|
mock_config_entry.add_to_hass(hass)
|
|
hass.config_entries.async_update_entry(mock_config_entry, options=options)
|
|
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
|
|
local_tz = ZoneInfo(hass.config.time_zone)
|
|
today = date(2026, 4, 10)
|
|
tomorrow = date(2026, 4, 11)
|
|
mock_energyzero.get_electricity_prices.assert_has_awaits(
|
|
[
|
|
call(
|
|
start_date=today,
|
|
end_date=today,
|
|
interval=interval,
|
|
price_type=(PriceType.MARKET_WITH_VAT, PriceType.ALL_IN),
|
|
local_tz=local_tz,
|
|
),
|
|
call(
|
|
start_date=tomorrow,
|
|
end_date=tomorrow,
|
|
interval=interval,
|
|
price_type=(PriceType.MARKET_WITH_VAT, PriceType.ALL_IN),
|
|
local_tz=local_tz,
|
|
),
|
|
]
|
|
)
|
|
assert mock_energyzero.get_electricity_prices.await_count == 2
|
|
mock_energyzero.get_gas_prices.assert_awaited_once_with(
|
|
start_date=today,
|
|
end_date=today,
|
|
price_type=PriceType.MARKET_WITH_VAT,
|
|
local_tz=local_tz,
|
|
)
|
|
|
|
|
|
@pytest.mark.usefixtures("mock_energyzero")
|
|
async def test_load_unload_config_entry(
|
|
hass: HomeAssistant, mock_config_entry: MockConfigEntry
|
|
) -> None:
|
|
"""Test the EnergyZero configuration entry loading/unloading."""
|
|
mock_config_entry.add_to_hass(hass)
|
|
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
|
|
assert mock_config_entry.state is ConfigEntryState.LOADED
|
|
|
|
await hass.config_entries.async_unload(mock_config_entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
|
|
assert mock_config_entry.state is ConfigEntryState.NOT_LOADED
|
|
|
|
|
|
@patch("energyzero.api.rest.RESTClient._request", side_effect=EnergyZeroConnectionError)
|
|
async def test_config_flow_entry_not_ready(
|
|
mock_request: MagicMock,
|
|
hass: HomeAssistant,
|
|
mock_config_entry: MockConfigEntry,
|
|
) -> None:
|
|
"""Test the EnergyZero configuration entry not ready."""
|
|
mock_config_entry.add_to_hass(hass)
|
|
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
|
|
assert mock_request.call_count == 1
|
|
assert mock_config_entry.state is ConfigEntryState.SETUP_RETRY
|
|
|
|
|
|
@pytest.mark.freeze_time("2026-04-10 20:32:59")
|
|
@pytest.mark.parametrize("selected", ["hourly", "quarter_hourly"])
|
|
@pytest.mark.parametrize(
|
|
"missing_streams",
|
|
[
|
|
pytest.param(("base_with_vat",), id="market"),
|
|
pytest.param(("all_in_with_vat",), id="all_in"),
|
|
pytest.param(("base_with_vat", "all_in_with_vat"), id="both"),
|
|
pytest.param(
|
|
("base", "base_with_vat", "all_in", "all_in_with_vat"),
|
|
id="unpublished",
|
|
),
|
|
],
|
|
)
|
|
async def test_missing_tomorrow_prices_do_not_retry(
|
|
hass: HomeAssistant,
|
|
mock_config_entry: MockConfigEntry,
|
|
selected: str,
|
|
missing_streams: tuple[str, ...],
|
|
freezer: FrozenDateTimeFactory,
|
|
) -> None:
|
|
"""Missing tomorrow streams do not cause extra requests or fail today's sensors."""
|
|
await hass.config.async_set_time_zone("Europe/Amsterdam")
|
|
electricity = await async_load_json_object_fixture(
|
|
hass, "today_energy.json", DOMAIN
|
|
)
|
|
gas = await async_load_json_object_fixture(hass, "today_gas.json", DOMAIN)
|
|
tomorrow = {**electricity, **{stream: [] for stream in missing_streams}}
|
|
mock_config_entry.add_to_hass(hass)
|
|
hass.config_entries.async_update_entry(
|
|
mock_config_entry, options={CONF_ELECTRICITY_PRICE_INTERVAL: selected}
|
|
)
|
|
with patch(
|
|
"energyzero.api.rest.RESTClient._request",
|
|
side_effect=[electricity, gas, tomorrow] * 2,
|
|
) as request:
|
|
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
assert request.await_count == 3
|
|
freezer.tick(SCAN_INTERVAL)
|
|
async_fire_time_changed(hass)
|
|
await hass.async_block_till_done(wait_background_tasks=True)
|
|
|
|
assert request.await_count == 6
|
|
assert (
|
|
request.await_args_list[2]
|
|
== request.await_args_list[5]
|
|
== call(
|
|
"public/v1/prices",
|
|
params={
|
|
"energyType": "ENERGY_TYPE_ELECTRICITY",
|
|
"date": "11-04-2026",
|
|
"interval": ELECTRICITY_INTERVALS[selected].value,
|
|
},
|
|
)
|
|
)
|
|
assert mock_config_entry.state is ConfigEntryState.LOADED
|
|
assert (
|
|
state := hass.states.get("sensor.energyzero_today_energy_current_hour_price")
|
|
)
|
|
assert state.state == "0.17191075"
|
|
assert (
|
|
state := hass.states.get("sensor.energyzero_today_energy_all_in_current_price")
|
|
)
|
|
assert state.state == "0.28275885"
|
|
|
|
|
|
@pytest.mark.freeze_time("2026-04-10 20:32:59")
|
|
@pytest.mark.parametrize("selected", ["hourly", "quarter_hourly"])
|
|
async def test_rest_requests_share_price_streams(
|
|
hass: HomeAssistant,
|
|
mock_config_entry: MockConfigEntry,
|
|
selected: str,
|
|
) -> None:
|
|
"""The actual library extracts both streams with one REST request per day."""
|
|
await hass.config.async_set_time_zone("Europe/Amsterdam")
|
|
electricity = await async_load_json_object_fixture(
|
|
hass, "today_energy.json", DOMAIN
|
|
)
|
|
gas = await async_load_json_object_fixture(hass, "today_gas.json", DOMAIN)
|
|
mock_config_entry.add_to_hass(hass)
|
|
hass.config_entries.async_update_entry(
|
|
mock_config_entry, options={CONF_ELECTRICITY_PRICE_INTERVAL: selected}
|
|
)
|
|
with patch(
|
|
"energyzero.api.rest.RESTClient._request",
|
|
side_effect=[electricity, gas, electricity],
|
|
) as request:
|
|
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
|
|
assert mock_config_entry.state is ConfigEntryState.LOADED
|
|
assert request.await_args_list == [
|
|
call(
|
|
"public/v1/prices",
|
|
params={
|
|
"energyType": "ENERGY_TYPE_ELECTRICITY",
|
|
"date": "10-04-2026",
|
|
"interval": ELECTRICITY_INTERVALS[selected].value,
|
|
},
|
|
),
|
|
call(
|
|
"public/v1/prices",
|
|
params={
|
|
"energyType": "ENERGY_TYPE_GAS",
|
|
"date": "10-04-2026",
|
|
"interval": "INTERVAL_DAY",
|
|
},
|
|
),
|
|
call(
|
|
"public/v1/prices",
|
|
params={
|
|
"energyType": "ENERGY_TYPE_ELECTRICITY",
|
|
"date": "11-04-2026",
|
|
"interval": ELECTRICITY_INTERVALS[selected].value,
|
|
},
|
|
),
|
|
]
|
|
assert (
|
|
state := hass.states.get("sensor.energyzero_today_energy_current_hour_price")
|
|
)
|
|
assert state.state == "0.17191075"
|
|
assert (
|
|
state := hass.states.get("sensor.energyzero_today_energy_all_in_current_price")
|
|
)
|
|
assert state.state == "0.28275885"
|