Update easyEnergy integration to v3.0.0 (#169162)

This commit is contained in:
Klaas Schoute
2026-04-26 14:23:59 +02:00
committed by GitHub
parent fa9a336725
commit cd98577eb7
14 changed files with 1525 additions and 1969 deletions
@@ -6,6 +6,7 @@ from datetime import timedelta
from typing import Any
from homeassistant.core import HomeAssistant
from homeassistant.util import dt as dt_util
from .coordinator import EasyEnergyConfigEntry, EasyEnergyData
@@ -23,9 +24,7 @@ def get_gas_price(data: EasyEnergyData, hours: int) -> float | None:
"""
if not data.gas_today:
return None
return data.gas_today.price_at_time(
data.gas_today.utcnow() + timedelta(hours=hours)
)
return data.gas_today.price_at_time(dt_util.utcnow() + timedelta(hours=hours))
async def async_get_config_entry_diagnostics(
@@ -40,21 +39,21 @@ async def async_get_config_entry_diagnostics(
"title": entry.title,
},
"energy_usage": {
"current_hour_price": energy_today.current_usage_price,
"current_hour_price": energy_today.current_price,
"next_hour_price": energy_today.price_at_time(
energy_today.utcnow() + timedelta(hours=1)
dt_util.utcnow() + timedelta(hours=1)
),
"average_price": energy_today.average_usage_price,
"max_price": energy_today.extreme_usage_prices[1],
"min_price": energy_today.extreme_usage_prices[0],
"highest_price_time": energy_today.highest_usage_price_time,
"lowest_price_time": energy_today.lowest_usage_price_time,
"percentage_of_max": energy_today.pct_of_max_usage,
"average_price": energy_today.average_price,
"max_price": energy_today.extreme_prices[1],
"min_price": energy_today.extreme_prices[0],
"highest_price_time": energy_today.highest_price_time,
"lowest_price_time": energy_today.lowest_price_time,
"percentage_of_max": energy_today.pct_of_max,
},
"energy_return": {
"current_hour_price": energy_today.current_return_price,
"next_hour_price": energy_today.price_at_time(
energy_today.utcnow() + timedelta(hours=1), "return"
"next_hour_price": energy_today.return_price_at_time(
dt_util.utcnow() + timedelta(hours=1)
),
"average_price": energy_today.average_return_price,
"max_price": energy_today.extreme_return_prices[1],
@@ -6,6 +6,6 @@
"documentation": "https://www.home-assistant.io/integrations/easyenergy",
"integration_type": "service",
"iot_class": "cloud_polling",
"requirements": ["easyenergy==2.2.0"],
"requirements": ["easyenergy==3.0.0"],
"single_config_entry": true
}
+14 -15
View File
@@ -24,6 +24,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from homeassistant.util import dt as dt_util
from .const import DOMAIN, SERVICE_TYPE_DEVICE_NAMES
from .coordinator import (
@@ -63,7 +64,7 @@ SENSORS: tuple[EasyEnergySensorEntityDescription, ...] = (
service_type="today_energy_usage",
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=f"{CURRENCY_EURO}/{UnitOfEnergy.KILO_WATT_HOUR}",
value_fn=lambda data: data.energy_today.current_usage_price,
value_fn=lambda data: data.energy_today.current_price,
),
EasyEnergySensorEntityDescription(
key="next_hour_price",
@@ -71,7 +72,7 @@ SENSORS: tuple[EasyEnergySensorEntityDescription, ...] = (
service_type="today_energy_usage",
native_unit_of_measurement=f"{CURRENCY_EURO}/{UnitOfEnergy.KILO_WATT_HOUR}",
value_fn=lambda data: data.energy_today.price_at_time(
data.energy_today.utcnow() + timedelta(hours=1)
dt_util.utcnow() + timedelta(hours=1)
),
),
EasyEnergySensorEntityDescription(
@@ -79,42 +80,42 @@ SENSORS: tuple[EasyEnergySensorEntityDescription, ...] = (
translation_key="average_price",
service_type="today_energy_usage",
native_unit_of_measurement=f"{CURRENCY_EURO}/{UnitOfEnergy.KILO_WATT_HOUR}",
value_fn=lambda data: data.energy_today.average_usage_price,
value_fn=lambda data: data.energy_today.average_price,
),
EasyEnergySensorEntityDescription(
key="max_price",
translation_key="max_price",
service_type="today_energy_usage",
native_unit_of_measurement=f"{CURRENCY_EURO}/{UnitOfEnergy.KILO_WATT_HOUR}",
value_fn=lambda data: data.energy_today.extreme_usage_prices[1],
value_fn=lambda data: data.energy_today.extreme_prices[1],
),
EasyEnergySensorEntityDescription(
key="min_price",
translation_key="min_price",
service_type="today_energy_usage",
native_unit_of_measurement=f"{CURRENCY_EURO}/{UnitOfEnergy.KILO_WATT_HOUR}",
value_fn=lambda data: data.energy_today.extreme_usage_prices[0],
value_fn=lambda data: data.energy_today.extreme_prices[0],
),
EasyEnergySensorEntityDescription(
key="highest_price_time",
translation_key="highest_price_time",
service_type="today_energy_usage",
device_class=SensorDeviceClass.TIMESTAMP,
value_fn=lambda data: data.energy_today.highest_usage_price_time,
value_fn=lambda data: data.energy_today.highest_price_time,
),
EasyEnergySensorEntityDescription(
key="lowest_price_time",
translation_key="lowest_price_time",
service_type="today_energy_usage",
device_class=SensorDeviceClass.TIMESTAMP,
value_fn=lambda data: data.energy_today.lowest_usage_price_time,
value_fn=lambda data: data.energy_today.lowest_price_time,
),
EasyEnergySensorEntityDescription(
key="percentage_of_max",
translation_key="percentage_of_max",
service_type="today_energy_usage",
native_unit_of_measurement=PERCENTAGE,
value_fn=lambda data: data.energy_today.pct_of_max_usage,
value_fn=lambda data: data.energy_today.pct_of_max,
),
EasyEnergySensorEntityDescription(
key="current_hour_price",
@@ -129,8 +130,8 @@ SENSORS: tuple[EasyEnergySensorEntityDescription, ...] = (
translation_key="next_hour_price",
service_type="today_energy_return",
native_unit_of_measurement=f"{CURRENCY_EURO}/{UnitOfEnergy.KILO_WATT_HOUR}",
value_fn=lambda data: data.energy_today.price_at_time(
data.energy_today.utcnow() + timedelta(hours=1), "return"
value_fn=lambda data: data.energy_today.return_price_at_time(
dt_util.utcnow() + timedelta(hours=1)
),
),
EasyEnergySensorEntityDescription(
@@ -180,14 +181,14 @@ SENSORS: tuple[EasyEnergySensorEntityDescription, ...] = (
translation_key="hours_priced_equal_or_lower",
service_type="today_energy_usage",
native_unit_of_measurement=UnitOfTime.HOURS,
value_fn=lambda data: data.energy_today.hours_priced_equal_or_lower_usage,
value_fn=lambda data: data.energy_today.periods_priced_equal_or_lower,
),
EasyEnergySensorEntityDescription(
key="hours_priced_equal_or_higher",
translation_key="hours_priced_equal_or_higher",
service_type="today_energy_return",
native_unit_of_measurement=UnitOfTime.HOURS,
value_fn=lambda data: data.energy_today.hours_priced_equal_or_higher_return,
value_fn=lambda data: data.energy_today.return_periods_priced_equal_or_higher,
),
)
@@ -205,9 +206,7 @@ def get_gas_price(data: EasyEnergyData, hours: int) -> float | None:
"""
if data.gas_today is None:
return None
return data.gas_today.price_at_time(
data.gas_today.utcnow() + timedelta(hours=hours)
)
return data.gas_today.price_at_time(dt_util.utcnow() + timedelta(hours=hours))
async def async_setup_entry(
+84 -36
View File
@@ -2,12 +2,13 @@
from __future__ import annotations
from datetime import date, datetime
from datetime import date, datetime, timedelta
from enum import StrEnum
from functools import partial
from typing import Final
from easyenergy import Electricity, Gas, VatOption
from easyenergy import Electricity, Gas, PriceInterval, VatOption
from easyenergy.const import MARKET_TIMEZONE
import voluptuous as vol
from homeassistant.core import (
@@ -32,18 +33,22 @@ ATTR_INCL_VAT: Final = "incl_vat"
GAS_SERVICE_NAME: Final = "get_gas_prices"
ENERGY_USAGE_SERVICE_NAME: Final = "get_energy_usage_prices"
ENERGY_RETURN_SERVICE_NAME: Final = "get_energy_return_prices"
BASE_SERVICE_SCHEMA: Final = {
vol.Required(ATTR_CONFIG_ENTRY): selector.ConfigEntrySelector(
{
"integration": DOMAIN,
}
),
vol.Optional(ATTR_START): str,
vol.Optional(ATTR_END): str,
}
SERVICE_SCHEMA: Final = vol.Schema(
{
vol.Required(ATTR_CONFIG_ENTRY): selector.ConfigEntrySelector(
{
"integration": DOMAIN,
}
),
**BASE_SERVICE_SCHEMA,
vol.Required(ATTR_INCL_VAT): bool,
vol.Optional(ATTR_START): str,
vol.Optional(ATTR_END): str,
}
)
RETURN_SERVICE_SCHEMA: Final = vol.Schema(BASE_SERVICE_SCHEMA)
class PriceType(StrEnum):
@@ -54,22 +59,47 @@ class PriceType(StrEnum):
GAS = "gas"
def __get_date(date_input: str | None) -> date | datetime:
"""Get date."""
def __get_date(
date_input: str | None,
) -> tuple[date, datetime | None]:
"""Get date for the API and optional datetime for response filtering."""
if not date_input:
return dt_util.now().date()
return dt_util.now().date(), None
if value := dt_util.parse_datetime(date_input):
return value
if date_value := dt_util.parse_date(date_input):
return date_value, None
raise ServiceValidationError(
"Invalid datetime provided.",
translation_domain=DOMAIN,
translation_key="invalid_date",
translation_placeholders={
"date": date_input,
},
)
if not (datetime_value := dt_util.parse_datetime(date_input)):
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="invalid_date",
translation_placeholders={
"date": date_input,
},
)
datetime_utc = dt_util.as_utc(datetime_value)
return datetime_utc.astimezone(MARKET_TIMEZONE).date(), datetime_utc
def __filter_prices(
prices: list[dict[str, float | datetime]],
intervals: tuple[PriceInterval, ...],
start: datetime,
end: datetime,
) -> list[dict[str, float | datetime]]:
"""Filter prices to the requested datetime range."""
included_timestamps = {
interval.starts_at
for interval in intervals
if interval.ends_at > start and interval.starts_at < end
}
return [
timestamp_price
for timestamp_price in prices
if timestamp_price["timestamp"] in included_timestamps
]
def __serialize_prices(prices: list[dict[str, float | datetime]]) -> ServiceResponse:
@@ -101,8 +131,8 @@ async def __get_prices(
"""Get prices from easyEnergy."""
coordinator = __get_coordinator(call)
start = __get_date(call.data.get(ATTR_START))
end = __get_date(call.data.get(ATTR_END))
start_date, start_datetime = __get_date(call.data.get(ATTR_START))
end_date, end_datetime = __get_date(call.data.get(ATTR_END))
vat = VatOption.INCLUDE
if call.data.get(ATTR_INCL_VAT) is False:
@@ -112,20 +142,38 @@ async def __get_prices(
if price_type == PriceType.GAS:
data = await coordinator.easyenergy.gas_prices(
start_date=start,
end_date=end,
start_date=start_date,
end_date=end_date,
vat=vat,
)
prices = data.timestamp_prices
else:
data = await coordinator.easyenergy.energy_prices(
start_date=start_date,
end_date=end_date,
vat=vat,
)
return __serialize_prices(data.timestamp_prices)
data = await coordinator.easyenergy.energy_prices(
start_date=start,
end_date=end,
vat=vat,
)
if price_type == PriceType.ENERGY_USAGE:
return __serialize_prices(data.timestamp_usage_prices)
return __serialize_prices(data.timestamp_return_prices)
if price_type == PriceType.ENERGY_USAGE:
prices = data.timestamp_prices
else:
prices = data.timestamp_return_prices
if start_datetime or end_datetime:
filter_start = start_datetime or dt_util.as_utc(
dt_util.start_of_local_day(start_date)
)
filter_end = end_datetime or dt_util.as_utc(
dt_util.start_of_local_day(end_date + timedelta(days=1))
)
prices = __filter_prices(
prices,
data.intervals,
filter_start,
filter_end,
)
return __serialize_prices(prices)
@callback
@@ -150,6 +198,6 @@ def async_setup_services(hass: HomeAssistant) -> None:
DOMAIN,
ENERGY_RETURN_SERVICE_NAME,
partial(__get_prices, price_type=PriceType.ENERGY_RETURN),
schema=SERVICE_SCHEMA,
schema=RETURN_SERVICE_SCHEMA,
supports_response=SupportsResponse.ONLY,
)
+1 -1
View File
@@ -859,7 +859,7 @@ eagle100==0.1.1
earn-e-p1==0.1.0
# homeassistant.components.easyenergy
easyenergy==2.2.0
easyenergy==3.0.0
# homeassistant.components.ebusd
ebusdpy==0.0.17
+1 -1
View File
@@ -768,7 +768,7 @@ eagle100==0.1.1
earn-e-p1==0.1.0
# homeassistant.components.easyenergy
easyenergy==2.2.0
easyenergy==3.0.0
# homeassistant.components.egauge
egauge-async==0.4.0
+11 -4
View File
@@ -9,7 +9,7 @@ import pytest
from homeassistant.components.easyenergy.const import DOMAIN
from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry, async_load_json_array_fixture
from tests.common import MockConfigEntry, async_load_json_object_fixture
@pytest.fixture
@@ -39,11 +39,18 @@ async def mock_easyenergy(hass: HomeAssistant) -> AsyncGenerator[MagicMock]:
"homeassistant.components.easyenergy.coordinator.EasyEnergy", autospec=True
) as easyenergy_mock:
client = easyenergy_mock.return_value
client.energy_prices.return_value = Electricity.from_dict(
await async_load_json_array_fixture(hass, "today_energy.json", DOMAIN)
energy_data = await async_load_json_object_fixture(
hass, "today_energy.json", DOMAIN
)
client.energy_prices.return_value = Electricity.from_dict(
energy_data["prices"],
price_key="priceIncVat",
return_price_key="priceIncVat",
)
gas_data = await async_load_json_object_fixture(hass, "today_gas.json", DOMAIN)
client.gas_prices.return_value = Gas.from_dict(
await async_load_json_array_fixture(hass, "today_gas.json", DOMAIN)
gas_data["prices"],
price_key="priceIncVat",
)
yield client
@@ -1,146 +1,317 @@
[
{
"Timestamp": "2023-01-18T23:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.1349513,
"TariffReturn": 0.11153
},
{
"Timestamp": "2023-01-19T00:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.1294458,
"TariffReturn": 0.10698
},
{
"Timestamp": "2023-01-19T01:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.1270137,
"TariffReturn": 0.10497
},
{
"Timestamp": "2023-01-19T02:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.1230812,
"TariffReturn": 0.10172
},
{
"Timestamp": "2023-01-19T03:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.1297483,
"TariffReturn": 0.10723
},
{
"Timestamp": "2023-01-19T04:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.1386902,
"TariffReturn": 0.11462
},
{
"Timestamp": "2023-01-19T05:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.1439174,
"TariffReturn": 0.11894
},
{
"Timestamp": "2023-01-19T06:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.193479,
"TariffReturn": 0.1599
},
{
"Timestamp": "2023-01-19T07:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.19844,
"TariffReturn": 0.164
},
{
"Timestamp": "2023-01-19T08:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.2077449,
"TariffReturn": 0.17169
},
{
"Timestamp": "2023-01-19T09:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.16819,
"TariffReturn": 0.139
},
{
"Timestamp": "2023-01-19T10:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.1649835,
"TariffReturn": 0.13635
},
{
"Timestamp": "2023-01-19T11:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.156816,
"TariffReturn": 0.1296
},
{
"Timestamp": "2023-01-19T12:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.1873927,
"TariffReturn": 0.15487
},
{
"Timestamp": "2023-01-19T13:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.1941929,
"TariffReturn": 0.16049
},
{
"Timestamp": "2023-01-19T14:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.2129116,
"TariffReturn": 0.17596
},
{
"Timestamp": "2023-01-19T15:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.2254109,
"TariffReturn": 0.18629
},
{
"Timestamp": "2023-01-19T16:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.2467674,
"TariffReturn": 0.20394
},
{
"Timestamp": "2023-01-19T17:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.2390597,
"TariffReturn": 0.19757
},
{
"Timestamp": "2023-01-19T18:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.2074303,
"TariffReturn": 0.17143
},
{
"Timestamp": "2023-01-19T19:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.1815,
"TariffReturn": 0.15
},
{
"Timestamp": "2023-01-19T20:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.1795761,
"TariffReturn": 0.14841
},
{
"Timestamp": "2023-01-19T21:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.1807014,
"TariffReturn": 0.14934
},
{
"Timestamp": "2023-01-19T22:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.16819,
"TariffReturn": 0.139
}
]
{
"providedAt": "2026-04-19T22:16:44.4866876Z",
"prices": [
{
"from": "2026-04-19T00:00:00.0000000",
"until": "2026-04-19T01:00:00.0000000",
"price": 0.11549,
"unit": "kWh",
"priceIncVat": 0.13975,
"energyTax": 0.11085,
"purchasePrice": 0.02178,
"invoicePrice": 0.27238,
"average": 0.0786,
"averageInc": 0.09516,
"granularity": "hour"
},
{
"from": "2026-04-19T01:00:00.0000000",
"until": "2026-04-19T02:00:00.0000000",
"price": 0.10522,
"unit": "kWh",
"priceIncVat": 0.12732,
"energyTax": 0.11085,
"purchasePrice": 0.02178,
"invoicePrice": 0.25995,
"average": 0.0786,
"averageInc": 0.09516,
"granularity": "hour"
},
{
"from": "2026-04-19T02:00:00.0000000",
"until": "2026-04-19T03:00:00.0000000",
"price": 0.1092,
"unit": "kWh",
"priceIncVat": 0.13213,
"energyTax": 0.11085,
"purchasePrice": 0.02178,
"invoicePrice": 0.26476,
"average": 0.0786,
"averageInc": 0.09516,
"granularity": "hour"
},
{
"from": "2026-04-19T03:00:00.0000000",
"until": "2026-04-19T04:00:00.0000000",
"price": 0.10325,
"unit": "kWh",
"priceIncVat": 0.12493,
"energyTax": 0.11085,
"purchasePrice": 0.02178,
"invoicePrice": 0.25756,
"average": 0.0786,
"averageInc": 0.09516,
"granularity": "hour"
},
{
"from": "2026-04-19T04:00:00.0000000",
"until": "2026-04-19T05:00:00.0000000",
"price": 0.10346,
"unit": "kWh",
"priceIncVat": 0.12519,
"energyTax": 0.11085,
"purchasePrice": 0.02178,
"invoicePrice": 0.25782,
"average": 0.0786,
"averageInc": 0.09516,
"granularity": "hour"
},
{
"from": "2026-04-19T05:00:00.0000000",
"until": "2026-04-19T06:00:00.0000000",
"price": 0.09795,
"unit": "kWh",
"priceIncVat": 0.11852,
"energyTax": 0.11085,
"purchasePrice": 0.02178,
"invoicePrice": 0.25115,
"average": 0.0786,
"averageInc": 0.09516,
"granularity": "hour"
},
{
"from": "2026-04-19T06:00:00.0000000",
"until": "2026-04-19T07:00:00.0000000",
"price": 0.10071,
"unit": "kWh",
"priceIncVat": 0.12186,
"energyTax": 0.11085,
"purchasePrice": 0.02178,
"invoicePrice": 0.25449,
"average": 0.0786,
"averageInc": 0.09516,
"granularity": "hour"
},
{
"from": "2026-04-19T07:00:00.0000000",
"until": "2026-04-19T08:00:00.0000000",
"price": 0.09793,
"unit": "kWh",
"priceIncVat": 0.1185,
"energyTax": 0.11085,
"purchasePrice": 0.02178,
"invoicePrice": 0.25113,
"average": 0.0786,
"averageInc": 0.09516,
"granularity": "hour"
},
{
"from": "2026-04-19T08:00:00.0000000",
"until": "2026-04-19T09:00:00.0000000",
"price": 0.09725,
"unit": "kWh",
"priceIncVat": 0.11768,
"energyTax": 0.11085,
"purchasePrice": 0.02178,
"invoicePrice": 0.25031,
"average": 0.0786,
"averageInc": 0.09516,
"granularity": "hour"
},
{
"from": "2026-04-19T09:00:00.0000000",
"until": "2026-04-19T10:00:00.0000000",
"price": 0.08766,
"unit": "kWh",
"priceIncVat": 0.10607,
"energyTax": 0.11085,
"purchasePrice": 0.02178,
"invoicePrice": 0.2387,
"average": 0.0786,
"averageInc": 0.09516,
"granularity": "hour"
},
{
"from": "2026-04-19T10:00:00.0000000",
"until": "2026-04-19T11:00:00.0000000",
"price": 0.06132,
"unit": "kWh",
"priceIncVat": 0.07419,
"energyTax": 0.11085,
"purchasePrice": 0.02178,
"invoicePrice": 0.20682,
"average": 0.0786,
"averageInc": 0.09516,
"granularity": "hour"
},
{
"from": "2026-04-19T11:00:00.0000000",
"until": "2026-04-19T12:00:00.0000000",
"price": 0.02832,
"unit": "kWh",
"priceIncVat": 0.03426,
"energyTax": 0.11085,
"purchasePrice": 0.02178,
"invoicePrice": 0.16689,
"average": 0.0786,
"averageInc": 0.09516,
"granularity": "hour"
},
{
"from": "2026-04-19T12:00:00.0000000",
"until": "2026-04-19T13:00:00.0000000",
"price": 0.00806,
"unit": "kWh",
"priceIncVat": 0.00975,
"energyTax": 0.11085,
"purchasePrice": 0.02178,
"invoicePrice": 0.14238,
"average": 0.0786,
"averageInc": 0.09516,
"granularity": "hour"
},
{
"from": "2026-04-19T13:00:00.0000000",
"until": "2026-04-19T14:00:00.0000000",
"price": -0.00085,
"unit": "kWh",
"priceIncVat": -0.00085,
"energyTax": 0.11085,
"purchasePrice": 0.02178,
"invoicePrice": 0.13178,
"average": 0.0786,
"averageInc": 0.09516,
"granularity": "hour"
},
{
"from": "2026-04-19T14:00:00.0000000",
"until": "2026-04-19T15:00:00.0000000",
"price": -0.003,
"unit": "kWh",
"priceIncVat": -0.003,
"energyTax": 0.11085,
"purchasePrice": 0.02178,
"invoicePrice": 0.12963,
"average": 0.0786,
"averageInc": 0.09516,
"granularity": "hour"
},
{
"from": "2026-04-19T15:00:00.0000000",
"until": "2026-04-19T16:00:00.0000000",
"price": -0.00226,
"unit": "kWh",
"priceIncVat": -0.00226,
"energyTax": 0.11085,
"purchasePrice": 0.02178,
"invoicePrice": 0.13037,
"average": 0.0786,
"averageInc": 0.09516,
"granularity": "hour"
},
{
"from": "2026-04-19T16:00:00.0000000",
"until": "2026-04-19T17:00:00.0000000",
"price": 0.01348,
"unit": "kWh",
"priceIncVat": 0.01631,
"energyTax": 0.11085,
"purchasePrice": 0.02178,
"invoicePrice": 0.14894,
"average": 0.0786,
"averageInc": 0.09516,
"granularity": "hour"
},
{
"from": "2026-04-19T17:00:00.0000000",
"until": "2026-04-19T18:00:00.0000000",
"price": 0.06533,
"unit": "kWh",
"priceIncVat": 0.07905,
"energyTax": 0.11085,
"purchasePrice": 0.02178,
"invoicePrice": 0.21168,
"average": 0.0786,
"averageInc": 0.09516,
"granularity": "hour"
},
{
"from": "2026-04-19T18:00:00.0000000",
"until": "2026-04-19T19:00:00.0000000",
"price": 0.10385,
"unit": "kWh",
"priceIncVat": 0.12566,
"energyTax": 0.11085,
"purchasePrice": 0.02178,
"invoicePrice": 0.25829,
"average": 0.0786,
"averageInc": 0.09516,
"granularity": "hour"
},
{
"from": "2026-04-19T19:00:00.0000000",
"until": "2026-04-19T20:00:00.0000000",
"price": 0.11681,
"unit": "kWh",
"priceIncVat": 0.14134,
"energyTax": 0.11085,
"purchasePrice": 0.02178,
"invoicePrice": 0.27397,
"average": 0.0786,
"averageInc": 0.09516,
"granularity": "hour"
},
{
"from": "2026-04-19T20:00:00.0000000",
"until": "2026-04-19T21:00:00.0000000",
"price": 0.12464,
"unit": "kWh",
"priceIncVat": 0.15082,
"energyTax": 0.11085,
"purchasePrice": 0.02178,
"invoicePrice": 0.28345,
"average": 0.0786,
"averageInc": 0.09516,
"granularity": "hour"
},
{
"from": "2026-04-19T21:00:00.0000000",
"until": "2026-04-19T22:00:00.0000000",
"price": 0.12214,
"unit": "kWh",
"priceIncVat": 0.14779,
"energyTax": 0.11085,
"purchasePrice": 0.02178,
"invoicePrice": 0.28042,
"average": 0.0786,
"averageInc": 0.09516,
"granularity": "hour"
},
{
"from": "2026-04-19T22:00:00.0000000",
"until": "2026-04-19T23:00:00.0000000",
"price": 0.11906,
"unit": "kWh",
"priceIncVat": 0.14407,
"energyTax": 0.11085,
"purchasePrice": 0.02178,
"invoicePrice": 0.2767,
"average": 0.0786,
"averageInc": 0.09516,
"granularity": "hour"
},
{
"from": "2026-04-19T23:00:00.0000000",
"until": "2026-04-20T00:00:00.0000000",
"price": 0.1113,
"unit": "kWh",
"priceIncVat": 0.13467,
"energyTax": 0.11085,
"purchasePrice": 0.02178,
"invoicePrice": 0.2673,
"average": 0.0786,
"averageInc": 0.09516,
"granularity": "hour"
}
]
}
@@ -1,146 +1,31 @@
[
{
"Timestamp": "2023-01-19T05:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.7252982,
"TariffReturn": 0.7252982
},
{
"Timestamp": "2023-01-19T06:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.7252982,
"TariffReturn": 0.7252982
},
{
"Timestamp": "2023-01-19T07:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.7252982,
"TariffReturn": 0.7252982
},
{
"Timestamp": "2023-01-19T08:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.7252982,
"TariffReturn": 0.7252982
},
{
"Timestamp": "2023-01-19T09:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.7252982,
"TariffReturn": 0.7252982
},
{
"Timestamp": "2023-01-19T10:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.7252982,
"TariffReturn": 0.7252982
},
{
"Timestamp": "2023-01-19T11:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.7252982,
"TariffReturn": 0.7252982
},
{
"Timestamp": "2023-01-19T12:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.7252982,
"TariffReturn": 0.7252982
},
{
"Timestamp": "2023-01-19T13:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.7252982,
"TariffReturn": 0.7252982
},
{
"Timestamp": "2023-01-19T14:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.7252982,
"TariffReturn": 0.7252982
},
{
"Timestamp": "2023-01-19T15:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.7252982,
"TariffReturn": 0.7252982
},
{
"Timestamp": "2023-01-19T16:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.7252982,
"TariffReturn": 0.7252982
},
{
"Timestamp": "2023-01-19T17:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.7252982,
"TariffReturn": 0.7252982
},
{
"Timestamp": "2023-01-19T18:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.7252982,
"TariffReturn": 0.7252982
},
{
"Timestamp": "2023-01-19T19:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.7252982,
"TariffReturn": 0.7252982
},
{
"Timestamp": "2023-01-19T20:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.7252982,
"TariffReturn": 0.7252982
},
{
"Timestamp": "2023-01-19T21:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.7252982,
"TariffReturn": 0.7252982
},
{
"Timestamp": "2023-01-19T22:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.7252982,
"TariffReturn": 0.7252982
},
{
"Timestamp": "2023-01-19T23:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.7252982,
"TariffReturn": 0.7252982
},
{
"Timestamp": "2023-01-20T00:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.7252982,
"TariffReturn": 0.7252982
},
{
"Timestamp": "2023-01-20T01:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.7252982,
"TariffReturn": 0.7252982
},
{
"Timestamp": "2023-01-20T02:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.7252982,
"TariffReturn": 0.7252982
},
{
"Timestamp": "2023-01-20T03:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.7252982,
"TariffReturn": 0.7252982
},
{
"Timestamp": "2023-01-20T04:00:00+00:00",
"SupplierId": 0,
"TariffUsage": 0.7252982,
"TariffReturn": 0.7252982
}
]
{
"providedAt": "2026-04-19T22:16:43.4740091Z",
"prices": [
{
"from": "2026-04-19T00:00:00.0000000",
"until": "2026-04-20T00:00:00.0000000",
"price": 0.50983,
"unit": "m3",
"priceIncVat": 0.6169,
"energyTax": 0.7268,
"purchasePrice": 0.079,
"invoicePrice": 1.4227,
"average": 0.49402,
"averageInc": 0.59776,
"granularity": "day"
},
{
"from": "2026-04-20T00:00:00.0000000",
"until": "2026-04-21T00:00:00.0000000",
"price": 0.4782,
"unit": "m3",
"priceIncVat": 0.57862,
"energyTax": 0.7268,
"purchasePrice": 0.079,
"invoicePrice": 1.38442,
"average": 0.49402,
"averageInc": 0.59776,
"granularity": "day"
}
]
}
@@ -2,55 +2,55 @@
# name: test_diagnostics
dict({
'energy_return': dict({
'average_price': 0.14599,
'current_hour_price': 0.18629,
'highest_price_time': '2023-01-19T16:00:00+00:00',
'lowest_price_time': '2023-01-19T02:00:00+00:00',
'max_price': 0.20394,
'min_price': 0.10172,
'next_hour_price': 0.20394,
'percentage_of_max': 91.35,
'average_price': 0.09516,
'current_hour_price': -0.00226,
'highest_price_time': '2026-04-19T18:00:00+00:00',
'lowest_price_time': '2026-04-19T12:00:00+00:00',
'max_price': 0.15082,
'min_price': -0.003,
'next_hour_price': 0.01631,
'percentage_of_max': -1.5,
}),
'energy_usage': dict({
'average_price': 0.17665,
'current_hour_price': 0.22541,
'highest_price_time': '2023-01-19T16:00:00+00:00',
'lowest_price_time': '2023-01-19T02:00:00+00:00',
'max_price': 0.24677,
'min_price': 0.12308,
'next_hour_price': 0.24677,
'percentage_of_max': 91.34,
'average_price': 0.09516,
'current_hour_price': -0.00226,
'highest_price_time': '2026-04-19T18:00:00+00:00',
'lowest_price_time': '2026-04-19T12:00:00+00:00',
'max_price': 0.15082,
'min_price': -0.003,
'next_hour_price': 0.01631,
'percentage_of_max': -1.5,
}),
'entry': dict({
'title': 'energy',
}),
'gas': dict({
'current_hour_price': 0.7253,
'next_hour_price': 0.7253,
'current_hour_price': 0.6169,
'next_hour_price': 0.6169,
}),
})
# ---
# name: test_diagnostics_no_gas_today
dict({
'energy_return': dict({
'average_price': 0.14599,
'current_hour_price': 0.18629,
'highest_price_time': '2023-01-19T16:00:00+00:00',
'lowest_price_time': '2023-01-19T02:00:00+00:00',
'max_price': 0.20394,
'min_price': 0.10172,
'next_hour_price': 0.20394,
'percentage_of_max': 91.35,
'average_price': 0.09516,
'current_hour_price': -0.00226,
'highest_price_time': '2026-04-19T18:00:00+00:00',
'lowest_price_time': '2026-04-19T12:00:00+00:00',
'max_price': 0.15082,
'min_price': -0.003,
'next_hour_price': 0.01631,
'percentage_of_max': -1.5,
}),
'energy_usage': dict({
'average_price': 0.17665,
'current_hour_price': 0.22541,
'highest_price_time': '2023-01-19T16:00:00+00:00',
'lowest_price_time': '2023-01-19T02:00:00+00:00',
'max_price': 0.24677,
'min_price': 0.12308,
'next_hour_price': 0.24677,
'percentage_of_max': 91.34,
'average_price': 0.09516,
'current_hour_price': -0.00226,
'highest_price_time': '2026-04-19T18:00:00+00:00',
'lowest_price_time': '2026-04-19T12:00:00+00:00',
'max_price': 0.15082,
'min_price': -0.003,
'next_hour_price': 0.01631,
'percentage_of_max': -1.5,
}),
'entry': dict({
'title': 'energy',
File diff suppressed because it is too large Load Diff
@@ -19,7 +19,7 @@ from tests.components.diagnostics import get_diagnostics_for_config_entry
from tests.typing import ClientSessionGenerator
@pytest.mark.freeze_time("2023-01-19 15:00:00")
@pytest.mark.freeze_time("2026-04-19 13:00:00+00:00")
async def test_diagnostics(
hass: HomeAssistant,
hass_client: ClientSessionGenerator,
@@ -33,7 +33,7 @@ async def test_diagnostics(
)
@pytest.mark.freeze_time("2023-01-19 15:00:00")
@pytest.mark.freeze_time("2026-04-19 13:00:00+00:00")
async def test_diagnostics_no_gas_today(
hass: HomeAssistant,
hass_client: ClientSessionGenerator,
+15 -15
View File
@@ -33,7 +33,7 @@ from homeassistant.setup import async_setup_component
from tests.common import MockConfigEntry
@pytest.mark.freeze_time("2023-01-19 15:00:00")
@pytest.mark.freeze_time("2026-04-19 13:00:00+00:00")
async def test_energy_usage_today(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
@@ -51,7 +51,7 @@ async def test_energy_usage_today(
assert entry
assert state
assert entry.unique_id == f"{entry_id}_today_energy_usage_current_hour_price"
assert state.state == "0.22541"
assert state.state == "-0.00226"
assert (
state.attributes.get(ATTR_FRIENDLY_NAME)
== "Energy market price - Usage Current hour"
@@ -72,7 +72,7 @@ async def test_energy_usage_today(
assert entry
assert state
assert entry.unique_id == f"{entry_id}_today_energy_usage_average_price"
assert state.state == "0.17665"
assert state.state == "0.09516"
assert (
state.attributes.get(ATTR_FRIENDLY_NAME)
== "Energy market price - Usage Average - today"
@@ -90,7 +90,7 @@ async def test_energy_usage_today(
assert entry
assert state
assert entry.unique_id == f"{entry_id}_today_energy_usage_max_price"
assert state.state == "0.24677"
assert state.state == "0.15082"
assert (
state.attributes.get(ATTR_FRIENDLY_NAME)
== "Energy market price - Usage Highest price - today"
@@ -110,7 +110,7 @@ async def test_energy_usage_today(
assert entry
assert state
assert entry.unique_id == f"{entry_id}_today_energy_usage_highest_price_time"
assert state.state == "2023-01-19T16:00:00+00:00"
assert state.state == "2026-04-19T18:00:00+00:00"
assert (
state.attributes.get(ATTR_FRIENDLY_NAME)
== "Energy market price - Usage Time of highest price - today"
@@ -140,7 +140,7 @@ async def test_energy_usage_today(
assert (
entry.unique_id == f"{entry_id}_today_energy_usage_hours_priced_equal_or_lower"
)
assert state.state == "21"
assert state.state == "2"
assert (
state.attributes.get(ATTR_FRIENDLY_NAME)
== "Energy market price - Usage Hours priced equal or lower than current - today"
@@ -148,7 +148,7 @@ async def test_energy_usage_today(
assert ATTR_DEVICE_CLASS not in state.attributes
@pytest.mark.freeze_time("2023-01-19 15:00:00")
@pytest.mark.freeze_time("2026-04-19 13:00:00+00:00")
async def test_energy_return_today(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
@@ -166,7 +166,7 @@ async def test_energy_return_today(
assert entry
assert state
assert entry.unique_id == f"{entry_id}_today_energy_return_current_hour_price"
assert state.state == "0.18629"
assert state.state == "-0.00226"
assert (
state.attributes.get(ATTR_FRIENDLY_NAME)
== "Energy market price - Return Current hour"
@@ -187,7 +187,7 @@ async def test_energy_return_today(
assert entry
assert state
assert entry.unique_id == f"{entry_id}_today_energy_return_average_price"
assert state.state == "0.14599"
assert state.state == "0.09516"
assert (
state.attributes.get(ATTR_FRIENDLY_NAME)
== "Energy market price - Return Average - today"
@@ -205,7 +205,7 @@ async def test_energy_return_today(
assert entry
assert state
assert entry.unique_id == f"{entry_id}_today_energy_return_max_price"
assert state.state == "0.20394"
assert state.state == "0.15082"
assert (
state.attributes.get(ATTR_FRIENDLY_NAME)
== "Energy market price - Return Highest price - today"
@@ -225,7 +225,7 @@ async def test_energy_return_today(
assert entry
assert state
assert entry.unique_id == f"{entry_id}_today_energy_return_highest_price_time"
assert state.state == "2023-01-19T16:00:00+00:00"
assert state.state == "2026-04-19T18:00:00+00:00"
assert (
state.attributes.get(ATTR_FRIENDLY_NAME)
== "Energy market price - Return Time of highest price - today"
@@ -256,7 +256,7 @@ async def test_energy_return_today(
entry.unique_id
== f"{entry_id}_today_energy_return_hours_priced_equal_or_higher"
)
assert state.state == "3"
assert state.state == "23"
assert (
state.attributes.get(ATTR_FRIENDLY_NAME)
== "Energy market price - Return Hours priced equal or higher than current - today"
@@ -264,7 +264,7 @@ async def test_energy_return_today(
assert ATTR_DEVICE_CLASS not in state.attributes
@pytest.mark.freeze_time("2023-01-19 10:00:00")
@pytest.mark.freeze_time("2026-04-19 10:00:00+00:00")
async def test_gas_today(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
@@ -280,7 +280,7 @@ async def test_gas_today(
assert entry
assert state
assert entry.unique_id == f"{entry_id}_today_gas_current_hour_price"
assert state.state == "0.7253"
assert state.state == "0.6169"
assert state.attributes.get(ATTR_FRIENDLY_NAME) == "Gas market price Current hour"
assert (
state.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
@@ -301,7 +301,7 @@ async def test_gas_today(
assert not device_entry.sw_version
@pytest.mark.freeze_time("2023-01-19 15:00:00")
@pytest.mark.freeze_time("2026-04-19 13:00:00+00:00")
async def test_no_gas_today(
hass: HomeAssistant, mock_easyenergy: MagicMock, init_integration: MockConfigEntry
) -> None:
+202 -51
View File
@@ -1,5 +1,9 @@
"""Tests for the services provided by the easyEnergy integration."""
from datetime import date
from unittest.mock import MagicMock
from easyenergy import VatOption
import pytest
from syrupy.assertion import SnapshotAssertion
import voluptuous as vol
@@ -37,8 +41,8 @@ async def test_has_services(
],
)
@pytest.mark.parametrize("incl_vat", [{"incl_vat": False}, {"incl_vat": True}])
@pytest.mark.parametrize("start", [{"start": "2023-01-01 00:00:00"}, {}])
@pytest.mark.parametrize("end", [{"end": "2023-01-01 00:00:00"}, {}])
@pytest.mark.parametrize("start", [{"start": "2023-01-01"}, {}])
@pytest.mark.parametrize("end", [{"end": "2023-01-01"}, {}])
async def test_service(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
@@ -48,8 +52,10 @@ async def test_service(
start: dict[str, str],
end: dict[str, str],
) -> None:
"""Test the EnergyZero Service."""
"""Test the easyEnergy service."""
entry = {ATTR_CONFIG_ENTRY: mock_config_entry.entry_id}
if service == ENERGY_RETURN_SERVICE_NAME:
incl_vat = {}
data = entry | incl_vat | start | end
@@ -62,6 +68,75 @@ async def test_service(
)
@pytest.mark.usefixtures("init_integration")
@pytest.mark.parametrize(
("service", "expected_prices"),
[
(
GAS_SERVICE_NAME,
[
{"timestamp": "2026-04-18 22:00:00+00:00", "price": 0.6169},
],
),
(
ENERGY_USAGE_SERVICE_NAME,
[
{"timestamp": "2026-04-19 00:00:00+00:00", "price": 0.13213},
{"timestamp": "2026-04-19 01:00:00+00:00", "price": 0.12493},
{"timestamp": "2026-04-19 02:00:00+00:00", "price": 0.12519},
],
),
(
ENERGY_RETURN_SERVICE_NAME,
[
{"timestamp": "2026-04-19 00:00:00+00:00", "price": 0.13213},
{"timestamp": "2026-04-19 01:00:00+00:00", "price": 0.12493},
{"timestamp": "2026-04-19 02:00:00+00:00", "price": 0.12519},
],
),
],
)
async def test_service_filters_datetime_range(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_easyenergy: MagicMock,
service: str,
expected_prices: list[dict[str, str | float]],
) -> None:
"""Test easyEnergy services filter returned day data to a datetime range."""
service_data: dict[str, str | bool] = {
ATTR_CONFIG_ENTRY: mock_config_entry.entry_id,
"start": "2026-04-19 02:00:00+02:00",
"end": "2026-04-19 05:00:00+02:00",
}
if service != ENERGY_RETURN_SERVICE_NAME:
service_data["incl_vat"] = True
mock_easyenergy.reset_mock()
response = await hass.services.async_call(
DOMAIN,
service,
service_data,
blocking=True,
return_response=True,
)
assert response == {"prices": expected_prices}
expected_call = {
"start_date": date(2026, 4, 19),
"end_date": date(2026, 4, 19),
"vat": VatOption.INCLUDE,
}
if service == GAS_SERVICE_NAME:
mock_easyenergy.gas_prices.assert_called_once_with(**expected_call)
mock_easyenergy.energy_prices.assert_not_called()
else:
mock_easyenergy.energy_prices.assert_called_once_with(**expected_call)
mock_easyenergy.gas_prices.assert_not_called()
@pytest.fixture
def config_entry_data(
mock_config_entry: MockConfigEntry, request: pytest.FixtureRequest
@@ -83,65 +158,22 @@ def config_entry_data(
],
)
@pytest.mark.parametrize(
("config_entry_data", "service_data", "error", "error_message"),
("config_entry_data", "service_data", "error_message"),
[
({}, {}, vol.er.Error, "required key not provided .+"),
(
{"config_entry": True},
{},
vol.er.Error,
"required key not provided .+",
),
(
{},
{"incl_vat": True},
vol.er.Error,
"required key not provided .+",
),
(
{"config_entry": True},
{"incl_vat": "incorrect vat"},
vol.er.Error,
"expected bool for dictionary value .+",
),
(
{"config_entry": "incorrect entry"},
{"incl_vat": True},
ServiceValidationError,
"config entry with ID incorrect entry was not found",
),
(
{"config_entry": True},
{
"incl_vat": True,
"start": "incorrect date",
},
ServiceValidationError,
"Invalid datetime provided.",
),
(
{"config_entry": True},
{
"incl_vat": True,
"end": "incorrect date",
},
ServiceValidationError,
"Invalid datetime provided.",
),
({}, {}, "required key not provided .+"),
],
indirect=["config_entry_data"],
)
async def test_service_validation(
async def test_service_schema_validation(
hass: HomeAssistant,
service: str,
config_entry_data: dict[str, str],
service_data: dict[str, str | bool],
error: type[Exception],
error_message: str,
) -> None:
"""Test the easyEnergy Service."""
"""Test easyEnergy service schema validation."""
with pytest.raises(error, match=error_message):
with pytest.raises(vol.er.Error, match=error_message):
await hass.services.async_call(
DOMAIN,
service,
@@ -149,3 +181,122 @@ async def test_service_validation(
blocking=True,
return_response=True,
)
@pytest.mark.usefixtures("init_integration")
@pytest.mark.parametrize("service", [GAS_SERVICE_NAME, ENERGY_USAGE_SERVICE_NAME])
@pytest.mark.parametrize(
("service_data", "error_message"),
[
({}, "required key not provided .+"),
({"incl_vat": "incorrect vat"}, "expected bool for dictionary value .+"),
],
)
async def test_service_schema_validation_vat(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
service: str,
service_data: dict[str, str | bool],
error_message: str,
) -> None:
"""Test easyEnergy service schema validation for VAT."""
with pytest.raises(vol.er.Error, match=error_message):
await hass.services.async_call(
DOMAIN,
service,
{ATTR_CONFIG_ENTRY: mock_config_entry.entry_id} | service_data,
blocking=True,
return_response=True,
)
@pytest.mark.usefixtures("init_integration")
async def test_service_schema_validation_return_vat(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test return prices do not accept VAT selection."""
with pytest.raises(vol.er.Error, match="extra keys not allowed .+"):
await hass.services.async_call(
DOMAIN,
ENERGY_RETURN_SERVICE_NAME,
{ATTR_CONFIG_ENTRY: mock_config_entry.entry_id, "incl_vat": True},
blocking=True,
return_response=True,
)
@pytest.mark.usefixtures("init_integration")
@pytest.mark.parametrize(
"service",
[
GAS_SERVICE_NAME,
ENERGY_USAGE_SERVICE_NAME,
ENERGY_RETURN_SERVICE_NAME,
],
)
async def test_service_validation_config_entry_not_found(
hass: HomeAssistant,
service: str,
) -> None:
"""Test config entry validation for easyEnergy services."""
service_data: dict[str, str | bool] = {ATTR_CONFIG_ENTRY: "incorrect entry"}
if service != ENERGY_RETURN_SERVICE_NAME:
service_data["incl_vat"] = True
with pytest.raises(ServiceValidationError) as err:
await hass.services.async_call(
DOMAIN,
service,
service_data,
blocking=True,
return_response=True,
)
assert err.value.translation_key == "service_config_entry_not_found"
assert err.value.translation_placeholders == {
"domain": DOMAIN,
"entry_id": "incorrect entry",
}
@pytest.mark.usefixtures("init_integration")
@pytest.mark.parametrize(
"service",
[
GAS_SERVICE_NAME,
ENERGY_USAGE_SERVICE_NAME,
ENERGY_RETURN_SERVICE_NAME,
],
)
@pytest.mark.parametrize("date_field", ["start", "end"])
@pytest.mark.parametrize("date_value", ["incorrect date"])
async def test_service_validation_invalid_date(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
service: str,
date_field: str,
date_value: str,
) -> None:
"""Test invalid date validation for easyEnergy services."""
service_data: dict[str, str | bool] = {
ATTR_CONFIG_ENTRY: mock_config_entry.entry_id,
date_field: date_value,
}
if service != ENERGY_RETURN_SERVICE_NAME:
service_data["incl_vat"] = True
with pytest.raises(ServiceValidationError) as err:
await hass.services.async_call(
DOMAIN,
service,
service_data,
blocking=True,
return_response=True,
)
assert str(err.value) == f"Invalid date provided. Got {date_value}"
assert err.value.translation_key == "invalid_date"
assert err.value.translation_placeholders == {"date": date_value}