diff --git a/.gitignore b/.gitignore index 513930b..7fbfb6d 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ test_hass/custom_components test_hass/.HA_VERSION __pycache__ .venv +.vscode diff --git a/custom_components/cz_energy_spot_prices/__init__.py b/custom_components/cz_energy_spot_prices/__init__.py index 1123ea0..2f1105f 100644 --- a/custom_components/cz_energy_spot_prices/__init__.py +++ b/custom_components/cz_energy_spot_prices/__init__.py @@ -6,7 +6,7 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_CURRENCY, CONF_UNIT_OF_MEASUREMENT -from .const import DOMAIN, PLATFORMS +from .const import DOMAIN, PLATFORMS, ADDITIONAL_COSTS_BUY_ELECTRICITY, ADDITIONAL_COSTS_SELL_ELECTRICITY, ADDITIONAL_COSTS_BUY_GAS from .coordinator import SpotRateCoordinator from .spot_rate import SpotRate @@ -31,6 +31,9 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: SpotRateConfigEnt spot_rate=spot_rate, in_eur=config_entry.data[CONF_CURRENCY] == 'EUR', unit=config_entry.data[CONF_UNIT_OF_MEASUREMENT], + electricity_buy_rate_template_code = config_entry.options.get(ADDITIONAL_COSTS_BUY_ELECTRICITY) or '', + electricity_sell_rate_template_code = config_entry.options.get(ADDITIONAL_COSTS_SELL_ELECTRICITY) or '', + gas_buy_rate_template_code = config_entry.options.get(ADDITIONAL_COSTS_BUY_GAS) or '', ) await coordinator.async_config_entry_first_refresh() diff --git a/custom_components/cz_energy_spot_prices/binary_sensor.py b/custom_components/cz_energy_spot_prices/binary_sensor.py index 4bae02e..1bd4725 100644 --- a/custom_components/cz_energy_spot_prices/binary_sensor.py +++ b/custom_components/cz_energy_spot_prices/binary_sensor.py @@ -11,7 +11,7 @@ from . import SpotRateConfigEntry from .coordinator import SpotRateCoordinator, SpotRateData, CONSECUTIVE_HOURS -from .spot_rate_mixin import SpotRateSensorMixin +from .spot_rate_mixin import ElectricitySpotRateSensorMixin, GasSpotRateSensorMixin, Trade from .spot_rate_settings import SpotRateSettings logger = logging.getLogger(__name__) @@ -40,12 +40,14 @@ async def async_setup_entry(hass: HomeAssistant, entry: SpotRateConfigEntry, asy hass=hass, settings=settings, coordinator=coordinator, + trade = Trade.SPOT, ) has_tomorrow_gas_data = HasTomorrowGasData( hass=hass, settings=settings, coordinator=coordinator, + trade = Trade.SPOT, ) sensors = [ @@ -60,33 +62,60 @@ async def async_setup_entry(hass: HomeAssistant, entry: SpotRateConfigEntry, asy hass=hass, settings=settings, coordinator=coordinator, + trade = Trade.SPOT, ) ) + if coordinator._electricity_buy_rate_template is not None: + for i in CONSECUTIVE_HOURS: + sensors.append( + ConsecutiveCheapestElectricitySensor( + hours=i, + hass=hass, + settings=settings, + coordinator=coordinator, + trade = Trade.BUY, + ) + ) + + if coordinator._electricity_sell_rate_template is not None: + for i in CONSECUTIVE_HOURS: + sensors.append( + ConsecutiveCheapestElectricitySensor( + hours=i, + hass=hass, + settings=settings, + coordinator=coordinator, + trade = Trade.SELL, + ) + ) + async_add_entities(sensors) -class BinarySpotRateSensorBase(SpotRateSensorMixin, BinarySensorEntity): +class ElectricityBinarySpotRateSensorBase(ElectricitySpotRateSensorMixin, BinarySensorEntity): pass -class ConsecutiveCheapestElectricitySensor(BinarySpotRateSensorBase): +class ConsecutiveCheapestElectricitySensor(ElectricityBinarySpotRateSensorBase): _attr_icon = 'mdi:cash-clock' - def __init__(self, hours: int, hass: HomeAssistant, settings: SpotRateSettings, coordinator: SpotRateCoordinator) -> None: + def __init__(self, hours: int, hass: HomeAssistant, settings: SpotRateSettings, coordinator: SpotRateCoordinator, trade: Trade) -> None: self.hours = hours if self.hours == 1: - self._attr_unique_id = 'sensor.spot_electricity_is_cheapest' - self._attr_translation_key = 'current_spot_electricity_is_cheapest' + self._attr_unique_id = f'binary_sensor.{trade.lower()}_electricity_is_cheapest' + self._attr_translation_key = f'{trade.lower()}_electricity_is_cheapest' else: - self._attr_unique_id = f'sensor.spot_electricity_is_cheapest_{self.hours}_hours_block' - self._attr_translation_key = 'current_spot_electricity_is_cheapest_hours_block' + self._attr_unique_id = f'binary_sensor.{trade.lower()}_electricity_is_cheapest_{self.hours}_hours_block' + self._attr_translation_key = f'{trade.lower()}_electricity_is_cheapest_hours_block' self._attr_translation_placeholders = { 'hours': self.hours, } - super().__init__(hass=hass, settings=settings, coordinator=coordinator) + self.entity_id = self._attr_unique_id + + super().__init__(hass=hass, settings=settings, coordinator=coordinator, trade=trade) def _compute_attr(self, rate_data: SpotRateData, start: datetime, end: datetime) -> dict: dt = start @@ -95,8 +124,9 @@ def _compute_attr(self, rate_data: SpotRateData, start: datetime, end: datetime) sum_price: Decimal = Decimal(0) count: int = 0 + hourly_rates = self._get_trade_rates(rate_data) while dt <= end: - hour = rate_data.electricity.hour_for_dt(dt) + hour = hourly_rates.hour_for_dt(dt) sum_price += hour.price count += 1 if min_price is None or hour.price < min_price: @@ -118,61 +148,79 @@ def _compute_attr(self, rate_data: SpotRateData, start: datetime, end: datetime) def update(self, rate_data: Optional[SpotRateData]): self._attr = {} - self._attr_is_on = None if not rate_data: self._available = False - else: - is_on = False + self._attr_is_on = None + return - for hour in rate_data.electricity.hours_by_dt.values(): - start = hour.dt_local - timedelta(hours=self.hours - 1) - end = hour.dt_local + timedelta(hours=1, seconds=-1) + is_on = False + hourly_rates = self._get_trade_rates(rate_data) + for hour in hourly_rates.hours_by_dt.values(): + start = hour.dt_local - timedelta(hours=self.hours - 1) + end = hour.dt_local + timedelta(hours=1, seconds=-1) - # Ignore start times before now, we only want future blocks - if end < rate_data.electricity.now: - continue + # Ignore start times before now, we only want future blocks + if end < hourly_rates.now: + continue - if hour.cheapest_consecutive_order[self.hours] == 1: - if not self._attr: - # Only put it there once, so to contains closes interval in the future - self._attr = self._compute_attr(rate_data, start, end) + if hour.cheapest_consecutive_order[self.hours] == 1: + if not self._attr: + # Only put it there once, so to contains closes interval in the future + self._attr = self._compute_attr(rate_data, start, end) - if start <= rate_data.electricity.now <= end: - is_on = True + if start <= hourly_rates.now <= end: + is_on = True self._attr_is_on = is_on self._available = True -class HasTomorrowElectricityData(BinarySpotRateSensorBase): - _attr_unique_id = 'sensor.spot_electricity_has_tomorrow_data' - _attr_translation_key = 'tomorrow_spot_electricity_has_data' +class HasTomorrowElectricityData(ElectricityBinarySpotRateSensorBase): _attr_icon = 'mdi:cash-clock' + def __init__(self, hass: HomeAssistant, settings: SpotRateSettings, coordinator: SpotRateCoordinator, trade: Trade) -> None: + self._attr_unique_id = f'binary_sensor.{trade.lower()}_electricity_has_tomorrow_data' + self._attr_translation_key = f'{trade.lower()}_electricity_has_tomorrow_data' + + self.entity_id = self._attr_unique_id + + super().__init__(hass=hass, settings=settings, coordinator=coordinator, trade=trade) + def update(self, rate_data: Optional[SpotRateData]): self._attr = {} - self._attr_is_on = None if not rate_data: + self._attr_is_on = None self._available = False - else: - self._attr_is_on = rate_data.electricity.tomorrow is not None - self._available = True + return + + self._attr_is_on = self._get_trade_rates(rate_data).tomorrow is not None + self._available = True +class GasBinarySpotRateSensorBase(GasSpotRateSensorMixin, BinarySensorEntity): + pass -class HasTomorrowGasData(BinarySpotRateSensorBase): - _attr_unique_id = 'sensor.spot_gas_has_tomorrow_data' - _attr_translation_key = 'tomorrow_spot_gas_has_data' + +class HasTomorrowGasData(GasBinarySpotRateSensorBase): _attr_icon = 'mdi:cash-clock' + def __init__(self, hass: HomeAssistant, settings: SpotRateSettings, coordinator: SpotRateCoordinator, trade: Trade) -> None: + self._attr_unique_id = f'binary_sensor.{trade.lower()}_gas_has_tomorrow_data' + self._attr_translation_key = f'{trade.lower()}_gas_has_tomorrow_data' + + self.entity_id = self._attr_unique_id + + super().__init__(hass=hass, settings=settings, coordinator=coordinator, trade=trade) + def update(self, rate_data: Optional[SpotRateData]): self._attr = {} - self._attr_is_on = None if not rate_data: + self._attr_is_on = None self._available = False - else: - self._attr_is_on = rate_data.gas.tomorrow is not None - self._available = True + return + + self._attr_is_on = self._get_trade_rates(rate_data).tomorrow is not None + self._available = True diff --git a/custom_components/cz_energy_spot_prices/cnb_rate.py b/custom_components/cz_energy_spot_prices/cnb_rate.py index d81edb2..37a74c3 100644 --- a/custom_components/cz_energy_spot_prices/cnb_rate.py +++ b/custom_components/cz_energy_spot_prices/cnb_rate.py @@ -56,4 +56,4 @@ async def get_current_rates(self): cnb_rate = CnbRate() rates = asyncio.run(cnb_rate.get_current_rates()) for iso, rate in rates.items(): - print(iso, rate) \ No newline at end of file + print(iso, rate) diff --git a/custom_components/cz_energy_spot_prices/config_flow.py b/custom_components/cz_energy_spot_prices/config_flow.py index 13c7d2e..e4b87c2 100644 --- a/custom_components/cz_energy_spot_prices/config_flow.py +++ b/custom_components/cz_energy_spot_prices/config_flow.py @@ -68,17 +68,14 @@ async def async_step_init( options_schema = vol.Schema({ vol.Optional( ADDITIONAL_COSTS_BUY_ELECTRICITY, - description='Additional costs when buying electricity', default=self.config_entry.options.get(ADDITIONAL_COSTS_BUY_ELECTRICITY, ''), ): TemplateSelector(), vol.Optional( ADDITIONAL_COSTS_SELL_ELECTRICITY, - description='Additional costs when selling electricity', default=self.config_entry.options.get(ADDITIONAL_COSTS_SELL_ELECTRICITY, ''), ): TemplateSelector(), vol.Optional( ADDITIONAL_COSTS_BUY_GAS, - description='Additional costs when buying gas', default=self.config_entry.options.get(ADDITIONAL_COSTS_BUY_GAS, ''), ): TemplateSelector(), }) diff --git a/custom_components/cz_energy_spot_prices/coordinator.py b/custom_components/cz_energy_spot_prices/coordinator.py index 504214c..c6d834a 100644 --- a/custom_components/cz_energy_spot_prices/coordinator.py +++ b/custom_components/cz_energy_spot_prices/coordinator.py @@ -9,6 +9,7 @@ import async_timeout from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers.template import Template, TemplateError from homeassistant.helpers.update_coordinator import ( DataUpdateCoordinator, UpdateFailed, @@ -67,7 +68,7 @@ def most_expensive_hour(self) -> Optional[SpotRateHour]: class HourlySpotRateData: - def __init__(self, rates: SpotRate.RateByDatetime, zoneinfo: ZoneInfo) -> None: + def __init__(self, rates: SpotRate.RateByDatetime, zoneinfo: ZoneInfo, rate_template: Optional[Template]) -> None: self.now = get_now(zoneinfo) self.today_date = self.now.date() self.tomorrow_date = self.today_date + timedelta(days=1) @@ -79,6 +80,13 @@ def __init__(self, rates: SpotRate.RateByDatetime, zoneinfo: ZoneInfo) -> None: # Create individual SpotRateHour instances and compute statistics while doing that for utc_hour, rate in rates.items(): + if rate_template is not None: + rate = Decimal( + rate_template.async_render({ + 'value': float(rate), + 'hour': utc_hour, + }) + ) rate_hour = SpotRateHour(utc_hour, utc_hour.astimezone(zoneinfo), rate) self.hours_by_dt[utc_hour] = rate_hour @@ -134,8 +142,23 @@ def tomorrow(self) -> Optional[SpotRateDay]: return self.tomorrow_day +class HourlyTradeRateData: + def __init__(self, rates: SpotRate.RateByDatetime, zoneinfo: ZoneInfo, buy_rate_template: Optional[Template], sell_rate_template: Optional[Template]) -> None: + self.spot_rates = HourlySpotRateData(rates, zoneinfo, None) + + if buy_rate_template is None: + self.buy_rates = self.spot_rates + else: + self.buy_rates = HourlySpotRateData(rates, zoneinfo, buy_rate_template) + + if sell_rate_template is None: + self.sell_rates = self.spot_rates + else: + self.sell_rates = HourlySpotRateData(rates, zoneinfo, sell_rate_template) + + class DailySpotRateData: - def __init__(self, rates: SpotRate.RateByDatetime, zoneinfo: ZoneInfo) -> None: + def __init__(self, rates: SpotRate.RateByDatetime, zoneinfo: ZoneInfo, rate_template: Optional[Template]) -> None: self.now = get_now(zoneinfo) today = self.now.date() @@ -146,10 +169,9 @@ def __init__(self, rates: SpotRate.RateByDatetime, zoneinfo: ZoneInfo) -> None: midnight_yesterday = datetime.combine(date=yesterday, time=time(hour=0), tzinfo=zoneinfo).astimezone(timezone.utc) # It's 0 when there are no data, we want None - self._yesteday = rates.get(midnight_yesterday, None) or None - self._today = rates.get(midnight_today, None) or None - self._tomorrow = rates.get(midnight_tomorrow, None) or None - + self._yesteday = self._get_trade_rate(rates, midnight_yesterday, rate_template) or None + self._today = self._get_trade_rate(rates, midnight_today, rate_template) or None + self._tomorrow = self._get_trade_rate(rates, midnight_tomorrow, rate_template) or None @property def today(self) -> Decimal: @@ -163,9 +185,31 @@ def today(self) -> Decimal: def tomorrow(self) -> Optional[Decimal]: return self._tomorrow + def _get_trade_rate(self, rates: SpotRate.RateByDatetime, dt: datetime, rate_template: Optional[Template]) -> Decimal: + rate = rates.get(dt, None) or None + + if rate is not None and rate_template is not None: + rate = Decimal( + rate_template.async_render({ + 'value': float(rate), + 'day': dt, + }) + ) + + return rate + + +class DailyTradeRateData: + def __init__(self, rates: SpotRate.RateByDatetime, zoneinfo: ZoneInfo, buy_rate_template: Optional[Template]) -> None: + self.spot_rates = DailySpotRateData(rates, zoneinfo, None) + if buy_rate_template is None: + self.buy_rates = self.spot_rates + else: + self.buy_rates = DailySpotRateData(rates, zoneinfo, buy_rate_template) + class SpotRateData: - def __init__(self, electricity: HourlySpotRateData, gas: DailySpotRateData): + def __init__(self, electricity: HourlyTradeRateData, gas: DailyTradeRateData): self.electricity = electricity self.gas = gas @@ -176,7 +220,7 @@ def get_now(self, zoneinfo: Union[timezone, ZoneInfo] = timezone.utc) -> datetim class SpotRateCoordinator(DataUpdateCoordinator[SpotRateData]): """My custom coordinator.""" - def __init__(self, hass: HomeAssistant, spot_rate: SpotRate, in_eur: bool, unit: SpotRate.EnergyUnit): + def __init__(self, hass: HomeAssistant, spot_rate: SpotRate, in_eur: bool, unit: SpotRate.EnergyUnit, electricity_buy_rate_template_code: str, electricity_sell_rate_template_code: str, gas_buy_rate_template_code: str): """Initialize my coordinator.""" logger.debug('SpotRateCoordinator.__init__') super().__init__( @@ -193,6 +237,27 @@ def __init__(self, hass: HomeAssistant, spot_rate: SpotRate, in_eur: bool, unit: # Delays in seconds, total needs to be less than 3600 (one hour) as the `on_schedule` is scheduled once an hour self._retry_attempt_delays = [2, 4, 8, 16, 32, 64, 128, 256, 512, 1024] + self._electricity_buy_rate_template = None + if electricity_buy_rate_template_code.strip(): + try: + self._electricity_buy_rate_template = Template(electricity_buy_rate_template_code, hass) + except TemplateError as e: + logger.error('Template error in %s: %s', self.unique_id, e) + + self._electricity_sell_rate_template = None + if electricity_sell_rate_template_code.strip(): + try: + self._electricity_sell_rate_template = Template(electricity_sell_rate_template_code, hass) + except TemplateError as e: + logger.error('Template error in %s: %s', self.unique_id, e) + + self._gas_buy_rate_template = None + if gas_buy_rate_template_code.strip(): + try: + self._gas_buy_rate_template = Template(gas_buy_rate_template_code, hass) + except TemplateError as e: + logger.error('Template error in %s: %s', self.unique_id, e) + # TODO: do we need to unschedule it? self._unschedule = event.async_track_utc_time_change(hass, self.on_schedule, minute=0, second=0) @@ -213,8 +278,8 @@ async def fetch_data(self): ) self._retry_attempt = 0 return SpotRateData( - electricity=HourlySpotRateData(electricity_rates, zoneinfo), - gas=DailySpotRateData(gas_rates, zoneinfo=zoneinfo), + electricity=HourlyTradeRateData(electricity_rates, zoneinfo, self._electricity_buy_rate_template, self._electricity_sell_rate_template), + gas=DailyTradeRateData(gas_rates, zoneinfo, self._gas_buy_rate_template), ) def retry_maybe(self, exc_info: Exception | None=None): diff --git a/custom_components/cz_energy_spot_prices/manifest.json b/custom_components/cz_energy_spot_prices/manifest.json index 5632ad8..1496503 100644 --- a/custom_components/cz_energy_spot_prices/manifest.json +++ b/custom_components/cz_energy_spot_prices/manifest.json @@ -1,13 +1,13 @@ { - "domain": "cz_energy_spot_prices", - "name": "Czech Energy Spot Prices", - "codeowners": ["@rnovacek"], - "config_flow": true, - "dependencies": ["http"], - "documentation": "https://github.com/rnovacek/homeassistant_cz_energy_spot_prices", - "integration_type": "service", - "iot_class": "cloud_polling", - "issue_tracker": "https://github.com/rnovacek/homeassistant_cz_energy_spot_prices/issues", - "requirements": [], - "version": "0.6.4" + "domain": "cz_energy_spot_prices", + "name": "Czech Energy Spot Prices", + "codeowners": ["@rnovacek"], + "config_flow": true, + "dependencies": ["http"], + "documentation": "https://github.com/rnovacek/homeassistant_cz_energy_spot_prices", + "integration_type": "service", + "iot_class": "cloud_polling", + "issue_tracker": "https://github.com/rnovacek/homeassistant_cz_energy_spot_prices/issues", + "requirements": [], + "version": "0.6.4" } diff --git a/custom_components/cz_energy_spot_prices/sensor.py b/custom_components/cz_energy_spot_prices/sensor.py index 11995d4..53024c6 100644 --- a/custom_components/cz_energy_spot_prices/sensor.py +++ b/custom_components/cz_energy_spot_prices/sensor.py @@ -1,7 +1,7 @@ from __future__ import annotations import logging from datetime import datetime, timedelta -from typing import Dict, Optional, Literal +from typing import Dict, Optional from decimal import Decimal from zoneinfo import ZoneInfo @@ -12,9 +12,9 @@ from . import SpotRateConfigEntry from .const import ADDITIONAL_COSTS_SELL_ELECTRICITY, ADDITIONAL_COSTS_BUY_ELECTRICITY, ADDITIONAL_COSTS_BUY_GAS +from .binary_sensor import ElectricityBinarySpotRateSensorBase, GasBinarySpotRateSensorBase from .coordinator import SpotRateCoordinator, SpotRateData, SpotRateHour, CONSECUTIVE_HOURS -from .binary_sensor import BinarySpotRateSensorBase -from .spot_rate_mixin import SpotRateSensorMixin +from .spot_rate_mixin import ElectricitySpotRateSensorMixin, GasSpotRateSensorMixin, Trade from .spot_rate_settings import SpotRateSettings logger = logging.getLogger(__name__) @@ -39,111 +39,143 @@ async def async_setup_entry(hass: HomeAssistant, entry: SpotRateConfigEntry, asy zoneinfo=ZoneInfo(hass.config.time_zone), ) + # Electricity sensors + sensors = __get_electricity_sensors(hass, settings, coordinator, Trade.SPOT) + if coordinator._electricity_buy_rate_template is not None: + sensors += __get_electricity_sensors(hass, settings, coordinator, Trade.BUY) + if coordinator._electricity_sell_rate_template is not None: + sensors += __get_electricity_sensors(hass, settings, coordinator, Trade.SELL) + + # Gas sensors + sensors += __get_gas_sensors(hass, settings, coordinator, Trade.SPOT) + if coordinator._gas_buy_rate_template is not None: + sensors += __get_gas_sensors(hass, settings, coordinator, Trade.BUY) + + # Deprecated sensors + sensors += __get_deprecated_sensors(hass, settings, coordinator) + + async_add_entities(sensors) + +def __get_electricity_sensors(hass: HomeAssistant, settings: SpotRateSettings, coordinator: SpotRateCoordinator, trade: Trade): electricity_rate_sensor = SpotRateElectricitySensor( hass=hass, settings=settings, coordinator=coordinator, + trade = trade, ) cheapest_today_electricity_sensor = CheapestTodayElectricitySensor( hass=hass, settings=settings, coordinator=coordinator, + trade = trade, ) cheapest_tomorrow_electricity_sensor = CheapestTomorrowElectricitySensor( hass=hass, settings=settings, coordinator=coordinator, + trade = trade, ) most_expensive_today_electricity_sensor = MostExpensiveTodayElectricitySensor( hass=hass, settings=settings, coordinator=coordinator, + trade = trade, ) most_expensive_tomorrow_electricity_sensor = MostExpensiveTomorrowElectricitySensor( hass=hass, settings=settings, coordinator=coordinator, + trade = trade, ) current_electricity_hour_order = CurrentElectricityHourOrder( hass=hass, settings=settings, coordinator=coordinator, + trade = trade, ) tomorrow_electricity_hour_order = TomorrowElectricityHourOrder( hass=hass, settings=settings, coordinator=coordinator, + trade = trade, + ) + + sensors = [ + electricity_rate_sensor, + cheapest_today_electricity_sensor, + cheapest_tomorrow_electricity_sensor, + most_expensive_today_electricity_sensor, + most_expensive_tomorrow_electricity_sensor, + current_electricity_hour_order, + tomorrow_electricity_hour_order, + ] + + return sensors + +def __get_gas_sensors(hass: HomeAssistant, settings: SpotRateSettings, coordinator: SpotRateCoordinator, trade: Trade): + today_gas = TodayGasSensor( + hass=hass, + settings=settings, + coordinator=coordinator, + trade = trade, ) - has_tomorrow_electricity_data = HasTomorrowElectricityData( + tomorrow_gas = TomorrowGasSensor( hass=hass, settings=settings, coordinator=coordinator, + trade = trade, ) - today_gas = TodayGasSensor( + sensors = [ + today_gas, + tomorrow_gas, + ] + + return sensors + +def __get_deprecated_sensors(hass: HomeAssistant, settings: SpotRateSettings, coordinator: SpotRateCoordinator): + deprecated_buy_electricity_price = SpotRateElectricitySensor( hass=hass, settings=settings, coordinator=coordinator, + trade = Trade.BUY, + deprecated = True, ) - tomorrow_gas = TomorrowGasSensor( + deprecated_sell_electricity_price = SpotRateElectricitySensor( hass=hass, settings=settings, coordinator=coordinator, + trade = Trade.SELL, + deprecated = True, ) - has_tomorrow_gas_data = HasTomorrowGasData( + deprecated_has_tomorrow_electricity_data = HasTomorrowElectricityData( hass=hass, settings=settings, coordinator=coordinator, + trade = Trade.SPOT, + ) + deprecated_buy_gas_price = TodayGasSensor( + hass=hass, + settings=settings, + coordinator=coordinator, + trade = Trade.BUY, + deprecated = True, + ) + deprecated_has_tomorrow_gas_data = HasTomorrowGasData( + hass=hass, + settings=settings, + coordinator=coordinator, + trade = Trade.SPOT, ) - - additional_costs_buy_electricity = entry.options.get(ADDITIONAL_COSTS_BUY_ELECTRICITY) or '' - additional_costs_sell_electricity = entry.options.get(ADDITIONAL_COSTS_SELL_ELECTRICITY) or '' - additional_costs_buy_gas = entry.options.get(ADDITIONAL_COSTS_BUY_GAS) or '' sensors = [ - electricity_rate_sensor, - cheapest_today_electricity_sensor, - cheapest_tomorrow_electricity_sensor, - most_expensive_today_electricity_sensor, - most_expensive_tomorrow_electricity_sensor, - current_electricity_hour_order, - tomorrow_electricity_hour_order, - has_tomorrow_electricity_data, - today_gas, - tomorrow_gas, - has_tomorrow_gas_data + deprecated_buy_electricity_price, + deprecated_sell_electricity_price, + deprecated_has_tomorrow_electricity_data, + deprecated_buy_gas_price, + deprecated_has_tomorrow_gas_data, ] - if additional_costs_buy_electricity: - energy_price_buy_electricity_sensor = ElectricityPriceBuy( - hass=hass, - resource='electricity', - settings=settings, - coordinator=coordinator, - template_code=additional_costs_buy_electricity, - ) - sensors.append(energy_price_buy_electricity_sensor) - - if additional_costs_sell_electricity: - energy_price_sell_electricity_sensor = ElectricityPriceSell( - hass=hass, - resource='electricity', - settings=settings, - coordinator=coordinator, - template_code=additional_costs_sell_electricity, - ) - sensors.append(energy_price_sell_electricity_sensor) - - if additional_costs_buy_gas: - energy_price_buy_gas_sensor = GasPriceBuy( - hass=hass, - resource='gas', - settings=settings, - coordinator=coordinator, - template_code=additional_costs_buy_gas, - ) - sensors.append(energy_price_buy_gas_sensor) - for i in CONSECUTIVE_HOURS: sensors.append( ConsecutiveCheapestElectricitySensor( @@ -151,29 +183,46 @@ async def async_setup_entry(hass: HomeAssistant, entry: SpotRateConfigEntry, asy hass=hass, settings=settings, coordinator=coordinator, + trade = Trade.SPOT, ) ) - async_add_entities(sensors) + return sensors -class SpotRateSensorBase(SpotRateSensorMixin, SensorEntity): +class ElectricitySpotRateSensorBase(ElectricitySpotRateSensorMixin, SensorEntity): pass -class PriceSensor(SpotRateSensorBase, SensorEntity): - _attr_has_entity_name = True +class ElectricityPriceSensor(ElectricitySpotRateSensorBase): _attr_icon = 'mdi:cash' - def __init__(self, hass: HomeAssistant, settings: SpotRateSettings, coordinator: SpotRateCoordinator) -> None: - self._attr_unit_of_measurement = f'{settings.currency_human}/{settings.unit}' + def __init__(self, hass: HomeAssistant, settings: SpotRateSettings, coordinator: SpotRateCoordinator, trade: Trade) -> None: + self._attr_native_unit_of_measurement = f'{settings.currency_human}/{settings.unit}' - super().__init__(hass, settings, coordinator) + super().__init__(hass=hass, settings=settings, coordinator=coordinator, trade=trade) -class SpotRateElectricitySensor(PriceSensor): - _attr_unique_id = 'sensor.current_spot_electricity_price' - _attr_translation_key = 'current_spot_electricity_price' +class SpotRateElectricitySensor(ElectricityPriceSensor): + def __init__(self, hass: HomeAssistant, settings: SpotRateSettings, coordinator: SpotRateCoordinator, trade: Trade, deprecated: bool = False) -> None: + self._deprecated = deprecated + + if self._deprecated: + self._attr_unique_id = f'sensor.current_spot_electricity_{trade.lower()}_price' + self._attr_translation_key = f'current_spot_electricity_{trade.lower()}_price' + else: + self._attr_unique_id = f'sensor.current_{trade.lower()}_electricity_price' + self._attr_translation_key = f'current_{trade.lower()}_electricity_price' + + match trade: + case Trade.BUY: + self._attr_icon = 'mdi:cash-minus' + case Trade.SELL: + self._attr_icon = 'mdi:cash-plus' + + self.entity_id = self._attr_unique_id + + super().__init__(hass=hass, settings=settings, coordinator=coordinator, trade=trade) def update(self, rate_data: Optional[SpotRateData]): attributes: Dict[str, float] = {} @@ -185,33 +234,36 @@ def update(self, rate_data: Optional[SpotRateData]): return try: - current_hour = rate_data.electricity.current_hour - self._available = True + hourly_rates = self._get_trade_rates(rate_data) + self._value = hourly_rates.current_hour.price except LookupError: logger.error( 'Current time "%s" is not found in SpotRate values:\n%s', rate_data.get_now(), - '\n\t'.join([dt.isoformat() for dt in rate_data.electricity.hour_for_dt.keys()]), + '\n\t'.join([dt.isoformat() for dt in hourly_rates.hour_for_dt.keys()]), ) self._available = False return - current_value = current_hour.price + if self._deprecated: + self._attr = {} + self._available = True + return - for hour_data in rate_data.electricity.today_day.hours_by_dt.values(): + for hour_data in hourly_rates.today_day.hours_by_dt.values(): dt_local = hour_data.dt_local.isoformat() attributes[dt_local] = float(hour_data.price) - if rate_data.electricity.tomorrow_day: - for hour_data in rate_data.electricity.tomorrow_day.hours_by_dt.values(): + if hourly_rates.tomorrow_day: + for hour_data in hourly_rates.tomorrow_day.hours_by_dt.values(): dt_local = hour_data.dt_local.isoformat() attributes[dt_local] = float(hour_data.price) self._attr = attributes - self._value = current_value + self._available = True -class HourFindSensor(PriceSensor): +class HourFindSensor(ElectricityPriceSensor): def find_hour(self, rate_data: Optional[SpotRateData]) -> Optional[SpotRateHour]: raise NotImplementedError() @@ -241,86 +293,122 @@ def update(self, rate_data: Optional[SpotRateData]): class CheapestTodayElectricitySensor(HourFindSensor): - _attr_unique_id = 'sensor.current_spot_electricity_cheapest_today' - _attr_translation_key = 'today_spot_electricity_cheapest' + def __init__(self, hass: HomeAssistant, settings: SpotRateSettings, coordinator: SpotRateCoordinator, trade: Trade) -> None: + self._attr_unique_id = f'sensor.current_{trade.lower()}_electricity_cheapest_today' + self._attr_translation_key = f'{trade.lower()}_electricity_cheapest_today' + + self.entity_id = f'sensor.{trade.lower()}_cheapest_electricity_today' + + super().__init__(hass=hass, settings=settings, coordinator=coordinator, trade=trade) def find_hour(self, rate_data: Optional[SpotRateData]) -> Optional[SpotRateHour]: if not rate_data: return None - return rate_data.electricity.today_day.cheapest_hour() + hourly_rates = self._get_trade_rates(rate_data) + return hourly_rates.today_day.cheapest_hour() class CheapestTomorrowElectricitySensor(HourFindSensor): - _attr_unique_id = 'sensor.current_spot_electricity_cheapest_tomorrow' - _attr_translation_key = 'tomorrow_spot_electricity_cheapest' + def __init__(self, hass: HomeAssistant, settings: SpotRateSettings, coordinator: SpotRateCoordinator, trade: Trade) -> None: + self._attr_unique_id = f'sensor.current_{trade.lower()}_electricity_cheapest_tomorrow' + self._attr_translation_key = f'{trade.lower()}_electricity_cheapest_tomorrow' + + self.entity_id = f'sensor.{trade.lower()}_cheapest_electricity_tomorrow' + + super().__init__(hass=hass, settings=settings, coordinator=coordinator, trade=trade) def find_hour(self, rate_data: Optional[SpotRateData]) -> Optional[SpotRateHour]: if not rate_data: return None - if not rate_data.electricity.tomorrow: + hourly_rates = self._get_trade_rates(rate_data) + if not hourly_rates.tomorrow: return None - return rate_data.electricity.tomorrow.cheapest_hour() + return hourly_rates.tomorrow.cheapest_hour() class MostExpensiveTodayElectricitySensor(HourFindSensor): - _attr_unique_id = 'sensor.current_spot_electricity_most_expensive_today' - _attr_translation_key = 'today_spot_electricity_most_expensive' + def __init__(self, hass: HomeAssistant, settings: SpotRateSettings, coordinator: SpotRateCoordinator, trade: Trade) -> None: + self._attr_unique_id = f'sensor.current_{trade.lower()}_electricity_most_expensive_today' + self._attr_translation_key = f'{trade.lower()}_electricity_most_expensive_today' + + self.entity_id = f'sensor.{trade.lower()}_most_expensive_electricity_today' + + super().__init__(hass=hass, settings=settings, coordinator=coordinator, trade=trade) def find_hour(self, rate_data: Optional[SpotRateData]) -> Optional[SpotRateHour]: if not rate_data: return None - return rate_data.electricity.today.most_expensive_hour() + hourly_rates = self._get_trade_rates(rate_data) + return hourly_rates.today.most_expensive_hour() class MostExpensiveTomorrowElectricitySensor(HourFindSensor): - _attr_unique_id = 'sensor.current_spot_electricity_most_expensive_tomorrow' - _attr_translation_key = 'tomorrow_spot_electricity_most_expensive' + def __init__(self, hass: HomeAssistant, settings: SpotRateSettings, coordinator: SpotRateCoordinator, trade: Trade) -> None: + self._attr_unique_id = f'sensor.current_{trade.lower()}_electricity_most_expensive_tomorrow' + self._attr_translation_key = f'{trade.lower()}_electricity_most_expensive_tomorrow' + + self.entity_id = f'sensor.{trade.lower()}_most_expensive_electricity_tomorrow' + + super().__init__(hass=hass, settings=settings, coordinator=coordinator, trade=trade) def find_hour(self, rate_data: Optional[SpotRateData]) -> Optional[SpotRateHour]: if not rate_data: return None - if not rate_data.electricity.tomorrow: + hourly_rates = self._get_trade_rates(rate_data) + if not hourly_rates.tomorrow: return None - return rate_data.electricity.tomorrow.most_expensive_hour() + return hourly_rates.tomorrow.most_expensive_hour() -class EnergyHourOrder(SpotRateSensorBase): +class EnergyHourOrder(ElectricitySpotRateSensorBase): _attr_icon = 'mdi:hours-24' class CurrentElectricityHourOrder(EnergyHourOrder): - _attr_unique_id = 'sensor.current_spot_electricity_hour_order' - _attr_translation_key = 'current_spot_electricity_hour_order' + def __init__(self, hass: HomeAssistant, settings: SpotRateSettings, coordinator: SpotRateCoordinator, trade: Trade) -> None: + self._attr_unique_id = f'sensor.current_{trade.lower()}_electricity_hour_order' + self._attr_translation_key = f'{trade.lower()}_electricity_hour_order_today' + + self.entity_id = self._attr_unique_id + + super().__init__(hass=hass, settings=settings, coordinator=coordinator, trade=trade) def update(self, rate_data: Optional[SpotRateData]): self._attr = {} + if rate_data is None: self._available = False self._value = None return - cheapest_order = rate_data.electricity.current_hour.cheapest_consecutive_order[1] + hourly_rates = self._get_trade_rates(rate_data) + cheapest_order = hourly_rates.current_hour.cheapest_consecutive_order[1] if cheapest_order != self._value: logger.debug('%s updated from %s to %s', self.unique_id, self._value, cheapest_order) self._value = cheapest_order else: logger.debug('%s unchanged with %d', self.unique_id, cheapest_order) - for hour in rate_data.electricity.today.hours_by_dt.values(): + for hour in hourly_rates.today.hours_by_dt.values(): self._attr[hour.dt_local.isoformat()] = [hour.cheapest_consecutive_order[1], float(round(hour.price, 3))] self._available = True class TomorrowElectricityHourOrder(EnergyHourOrder): - _attr_unique_id = 'sensor.tomorrow_spot_electricity_hour_order' - _attr_translation_key = 'tomorrow_spot_electricity_hour_order' + def __init__(self, hass: HomeAssistant, settings: SpotRateSettings, coordinator: SpotRateCoordinator, trade: Trade) -> None: + self._attr_unique_id = f'sensor.tomorrow_{trade.lower()}_electricity_hour_order' + self._attr_translation_key = f'{trade.lower()}_electricity_hour_order_tomorrow' + + self.entity_id = self._attr_unique_id + + super().__init__(hass=hass, settings=settings, coordinator=coordinator, trade=trade) def update(self, rate_data: Optional[SpotRateData]): self._attr = {} @@ -328,92 +416,39 @@ def update(self, rate_data: Optional[SpotRateData]): if not rate_data: self._available = False - elif rate_data.electricity.tomorrow is None: - self._available = False - else: - self._available = True - - for hour in rate_data.electricity.tomorrow.hours_by_dt.values(): - self._attr[hour.dt_local.isoformat()] = [hour.cheapest_consecutive_order[1], float(round(hour.price, 3))] - - -class TemplatePriceSensor(PriceSensor): - def __init__(self, hass: HomeAssistant, resource: Literal['electricity', 'gas'], settings: SpotRateSettings, coordinator: SpotRateCoordinator, template_code: str) -> None: - super().__init__(hass, settings, coordinator) - self._resource = resource - try: - self.template = Template(template_code, hass=hass) - except TemplateError as e: - logger.error('Template error in %s: %s', self.unique_id, e) - self.template = None - - def get_current_price(self, rate_data: SpotRateData) -> float: - if self._resource == 'gas': - return float(rate_data.gas.today) - return float(rate_data.electricity.current_hour.price) - - def update(self, rate_data: Optional[SpotRateData]): - if rate_data is None or not self.template: - self._available = False - self._value = None - self._attr = {} return - try: - current_price = self.get_current_price(rate_data) - self._available = True - except LookupError: - logger.error( - 'Current time "%s" is not found in SpotRate values:\n%s', - rate_data.get_now(), - '\n\t'.join([dt.isoformat() for dt in rate_data.electricity.hour_for_dt.keys()]), - ) + hourly_rates = self._get_trade_rates(rate_data) + if hourly_rates.tomorrow is None: self._available = False return - current_value = self.template.async_render({ - 'value': float(current_price), - }) - logger.info('%s updated from %s to %s', self.unique_id, self._value, current_value) - - self._value = current_value - - -class ElectricityPriceBuy(TemplatePriceSensor): - _attr_unique_id = 'sensor.current_spot_electricity_buy_price' - _attr_translation_key = 'current_spot_electricity_buy_price' - _attr_icon = 'mdi:cash-minus' - - -class ElectricityPriceSell(TemplatePriceSensor): - _attr_unique_id = 'sensor.current_spot_electricity_sell_price' - _attr_translation_key = 'current_spot_electricity_sell_price' - _attr_icon = 'mdi:cash-plus' + for hour in hourly_rates.tomorrow.hours_by_dt.values(): + self._attr[hour.dt_local.isoformat()] = [hour.cheapest_consecutive_order[1], float(round(hour.price, 3))] + self._available = True -class GasPriceBuy(TemplatePriceSensor): - _attr_unique_id = 'sensor.current_spot_gas_buy_price' - _attr_translation_key = 'current_spot_gas_buy_price' - _attr_icon = 'mdi:cash-minus' #BC -class ConsecutiveCheapestElectricitySensor(BinarySpotRateSensorBase): +class ConsecutiveCheapestElectricitySensor(ElectricityBinarySpotRateSensorBase): _attr_icon = 'mdi:cash-clock' - def __init__(self, hours: int, hass: HomeAssistant, settings: SpotRateSettings, coordinator: SpotRateCoordinator) -> None: + def __init__(self, hours: int, hass: HomeAssistant, settings: SpotRateSettings, coordinator: SpotRateCoordinator, trade: Trade) -> None: self.hours = hours if self.hours == 1: - self._attr_unique_id = 'sensor.spot_electricity_is_cheapest' - self._attr_translation_key = 'current_spot_electricity_is_cheapest' + self._attr_unique_id = f'sensor.{trade.lower()}_electricity_is_cheapest' + self._attr_translation_key = f'{trade.lower()}_electricity_is_cheapest' else: - self._attr_unique_id = f'sensor.spot_electricity_is_cheapest_{self.hours}_hours_block' - self._attr_translation_key = 'current_spot_electricity_is_cheapest_hours_block' + self._attr_unique_id = f'sensor.{trade.lower()}_electricity_is_cheapest_{self.hours}_hours_block' + self._attr_translation_key = f'{trade.lower()}_electricity_is_cheapest_hours_block' self._attr_translation_placeholders = { 'hours': self.hours, } - super().__init__(hass=hass, settings=settings, coordinator=coordinator) + self.entity_id = self._attr_unique_id + + super().__init__(hass=hass, settings=settings, coordinator=coordinator, trade=trade) def _compute_attr(self, rate_data: SpotRateData, start: datetime, end: datetime) -> dict: dt = start @@ -422,8 +457,9 @@ def _compute_attr(self, rate_data: SpotRateData, start: datetime, end: datetime) sum_price: Decimal = Decimal(0) count: int = 0 + hourly_rates = self._get_trade_rates(rate_data) while dt <= end: - hour = rate_data.electricity.hour_for_dt(dt) + hour = hourly_rates.hour_for_dt(dt) sum_price += hour.price count += 1 if min_price is None or hour.price < min_price: @@ -445,92 +481,147 @@ def _compute_attr(self, rate_data: SpotRateData, start: datetime, end: datetime) def update(self, rate_data: Optional[SpotRateData]): self._attr = {} - self._attr_is_on = None if not rate_data: self._available = False - else: - is_on = False + self._attr_is_on = None + return - for hour in rate_data.electricity.hours_by_dt.values(): - start = hour.dt_local - timedelta(hours=self.hours - 1) - end = hour.dt_local + timedelta(hours=1, seconds=-1) + is_on = False + hourly_rates = self._get_trade_rates(rate_data) + for hour in hourly_rates.hours_by_dt.values(): + start = hour.dt_local - timedelta(hours=self.hours - 1) + end = hour.dt_local + timedelta(hours=1, seconds=-1) - # Ignore start times before now, we only want future blocks - if end < rate_data.electricity.now: - continue + # Ignore start times before now, we only want future blocks + if end < hourly_rates.now: + continue - if hour.cheapest_consecutive_order[self.hours] == 1: - if not self._attr: - # Only put it there once, so to contains closes interval in the future - self._attr = self._compute_attr(rate_data, start, end) + if hour.cheapest_consecutive_order[self.hours] == 1: + if not self._attr: + # Only put it there once, so to contains closes interval in the future + self._attr = self._compute_attr(rate_data, start, end) - if start <= rate_data.electricity.now <= end: - is_on = True + if start <= hourly_rates.now <= end: + is_on = True self._attr_is_on = is_on self._available = True + #BC -class HasTomorrowElectricityData(BinarySpotRateSensorBase): - _attr_unique_id = 'sensor.spot_electricity_has_tomorrow_data' - _attr_translation_key = 'tomorrow_spot_electricity_has_data' +class HasTomorrowElectricityData(ElectricityBinarySpotRateSensorBase): _attr_icon = 'mdi:cash-clock' + def __init__(self, hass: HomeAssistant, settings: SpotRateSettings, coordinator: SpotRateCoordinator, trade: Trade) -> None: + self._attr_unique_id = f'sensor.{trade.lower()}_electricity_has_tomorrow_data' + self._attr_translation_key = f'{trade.lower()}_electricity_has_tomorrow_data' + + self.entity_id = self._attr_unique_id + + super().__init__(hass=hass, settings=settings, coordinator=coordinator, trade=trade) + def update(self, rate_data: Optional[SpotRateData]): self._attr = {} - self._attr_is_on = None if not rate_data: + self._attr_is_on = None self._available = False + return + + self._attr_is_on = self._get_trade_rates(rate_data).tomorrow is not None + self._available = True + + +class GasSpotRateSensorBase(GasSpotRateSensorMixin, SensorEntity): + pass + + +class GasPriceSensor(GasSpotRateSensorBase): + _attr_icon = 'mdi:cash' + + def __init__(self, hass: HomeAssistant, settings: SpotRateSettings, coordinator: SpotRateCoordinator, trade: Trade) -> None: + self._attr_native_unit_of_measurement = f'{settings.currency_human}/{settings.unit}' + + super().__init__(hass=hass, settings=settings, coordinator=coordinator, trade=trade) + + +class TodayGasSensor(GasPriceSensor): + def __init__(self, hass: HomeAssistant, settings: SpotRateSettings, coordinator: SpotRateCoordinator, trade: Trade, deprecated: bool = False) -> None: + if deprecated: + self._attr_unique_id = f'sensor.current_spot_gas_{trade.lower()}_price' + self._attr_translation_key = f'current_spot_gas_{trade.lower()}_price' else: - self._attr_is_on = rate_data.electricity.tomorrow is not None - self._available = True + self._attr_unique_id = f'sensor.current_{trade.lower()}_gas_price' + self._attr_translation_key = f'current_{trade.lower()}_gas_price' + match trade: + case Trade.BUY: + self._attr_icon = 'mdi:cash-minus' + case Trade.SELL: + self._attr_icon = 'mdi:cash-plus' + self.entity_id = self._attr_unique_id -class TodayGasSensor(PriceSensor): - _attr_unique_id = 'sensor.current_spot_gas_price' - _attr_translation_key = 'current_spot_gas_price' + super().__init__(hass=hass, settings=settings, coordinator=coordinator, trade=trade) def update(self, rate_data: Optional[SpotRateData]): + self._attr = {} + if rate_data is None: self._available = False self._value = None - self._attr = {} return - self._value = rate_data.gas.today self._available = True + self._value = self._get_trade_rates(rate_data).today + + +class TomorrowGasSensor(GasPriceSensor): + def __init__(self, hass: HomeAssistant, settings: SpotRateSettings, coordinator: SpotRateCoordinator, trade: Trade) -> None: + self._attr_unique_id = f'sensor.tomorrow_{trade.lower()}_gas_price' + self._attr_translation_key = f'tomorrow_{trade.lower()}_gas_price' + + match trade: + case Trade.BUY: + self._attr_icon = 'mdi:cash-minus' + case Trade.SELL: + self._attr_icon = 'mdi:cash-plus' + self.entity_id = self._attr_unique_id -class TomorrowGasSensor(PriceSensor): - _attr_unique_id = 'sensor.tomorrow_spot_gas_price' - _attr_translation_key = 'tomorrow_spot_gas_price' + super().__init__(hass=hass, settings=settings, coordinator=coordinator, trade=trade) def update(self, rate_data: Optional[SpotRateData]): + self._attr = {} + if rate_data is None: self._available = False self._value = None - self._attr = {} return - self._value = rate_data.gas.tomorrow + self._value = self._get_trade_rates(rate_data).tomorrow self._available = self._value is not None -#BC -class HasTomorrowGasData(BinarySpotRateSensorBase): - _attr_unique_id = 'sensor.spot_gas_has_tomorrow_data' - _attr_translation_key = 'tomorrow_spot_gas_has_data' +class HasTomorrowGasData(GasBinarySpotRateSensorBase): _attr_icon = 'mdi:cash-clock' + def __init__(self, hass: HomeAssistant, settings: SpotRateSettings, coordinator: SpotRateCoordinator, trade: Trade) -> None: + self._attr_unique_id = f'sensor.{trade.lower()}_gas_has_tomorrow_data' + self._attr_translation_key = f'{trade.lower()}_gas_has_tomorrow_data' + + self.entity_id = self._attr_unique_id + + super().__init__(hass=hass, settings=settings, coordinator=coordinator, trade=trade) + def update(self, rate_data: Optional[SpotRateData]): self._attr = {} - self._attr_is_on = None if not rate_data: + self._attr_is_on = None self._available = False - else: - self._attr_is_on = rate_data.gas.tomorrow is not None - self._available = True + return + + self._attr_is_on = self._get_trade_rates(rate_data).tomorrow is not None + self._available = True diff --git a/custom_components/cz_energy_spot_prices/spot_rate_mixin.py b/custom_components/cz_energy_spot_prices/spot_rate_mixin.py index 6eabee9..136ef46 100644 --- a/custom_components/cz_energy_spot_prices/spot_rate_mixin.py +++ b/custom_components/cz_energy_spot_prices/spot_rate_mixin.py @@ -1,4 +1,5 @@ import logging +from enum import StrEnum from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.update_coordinator import CoordinatorEntity @@ -9,15 +10,22 @@ logger = logging.getLogger(__name__) +class Trade(StrEnum): + SPOT = 'Spot' + BUY = 'Buy' + SELL = 'Sell' + + class SpotRateSensorMixin(CoordinatorEntity): _attr_has_entity_name = True coordinator: SpotRateCoordinator - def __init__(self, hass: HomeAssistant, settings: SpotRateSettings, coordinator: SpotRateCoordinator): + def __init__(self, hass: HomeAssistant, settings: SpotRateSettings, coordinator: SpotRateCoordinator, trade: Trade): super().__init__(coordinator) self.hass = hass self._settings = settings + self._trade = trade self._value = None self._attr = None @@ -31,6 +39,19 @@ def _handle_coordinator_update(self) -> None: self.update(self.coordinator.data) super()._handle_coordinator_update() + def _get_utility_rate_data(self, rate_data: SpotRateData): + raise NotImplementedError() + + def _get_trade_rates(self, rate_data: SpotRateData): + utility_rate_data = self._get_utility_rate_data(rate_data) + match self._trade: + case Trade.SPOT: + return utility_rate_data.spot_rates + case Trade.BUY: + return utility_rate_data.buy_rates + case Trade.SELL: + return utility_rate_data.sell_rates + def update(self, rates_by_datetime: SpotRateData): raise NotImplementedError() @@ -48,3 +69,13 @@ def extra_state_attributes(self): def available(self): """Return True if entity is available.""" return self._available + + +class ElectricitySpotRateSensorMixin(SpotRateSensorMixin): + def _get_utility_rate_data(self, rate_data: SpotRateData): + return rate_data.electricity + + +class GasSpotRateSensorMixin(SpotRateSensorMixin): + def _get_utility_rate_data(self, rate_data: SpotRateData): + return rate_data.gas diff --git a/custom_components/cz_energy_spot_prices/translations/cs.json b/custom_components/cz_energy_spot_prices/translations/cs.json index 02e0acd..9055792 100644 --- a/custom_components/cz_energy_spot_prices/translations/cs.json +++ b/custom_components/cz_energy_spot_prices/translations/cs.json @@ -20,76 +20,142 @@ "additional_costs_buy_gas": "Cena plynu při nákupu" }, "data_description": { - "additional_costs_buy_electricity": "Šablona pro výpočet konečné ceny po zahrnutí dodatečných nákladů. Použijte `value` pro získání aktualní spotové ceny. Například pro přídání 21 procent DPH použijte `'{{ value * 1.21 }}`.", - "additional_costs_sell_electricity": "Šablona pro výpočet konečné ceny po zahrnutí dodatečných nákladů. Použijte `value` pro získání aktualní spotové ceny. Například pro přidání fixního poplatku operátora ve výši 0.25 použijte `'{{ value - 0.25 }}`.", - "additional_costs_buy_gas": "Šablona pro výpočet konečné ceny po zahrnutí dodatečných nákladů. Použijte `value` pro získání aktualní spotové ceny." + "additional_costs_buy_electricity": "Šablona pro výpočet konečné ceny po zahrnutí dodatečných nákladů. Použijte `value` pro získání aktualní ceny, například pro přidání 21 procent DPH použijte `'{{ value * 1.21 }}`. Použijte `hour` pro výpočet ceny v dané hodině, pokud se sazba v jednotlivých hodinách liší, například pro vysoký a nízký tarif. Hodnota `hour` je v UTC. Pokud potřebujete lokální čas použijte `as_local(hour)`. Pokud nezadáte žádnou šablonu, senzor nebude vytvořen.", + "additional_costs_sell_electricity": "Šablona pro výpočet konečné ceny po zahrnutí dodatečných nákladů. Použijte `value` pro získání aktualní ceny, například pro odečtení fixního poplatku operátora ve výši 0.25 použijte `'{{ value - 0.25 }}`. Použijte `hour` pro výpočet ceny v dané hodině, pokud se sazba v jednotlivých hodinách liší, například pro vysoký a nízký tarif. Hodnota `hour` je v UTC. Pokud potřebujete lokální čas použijte `as_local(hour)`. Pokud nezadáte žádnou šablonu, senzor nebude vytvořen.", + "additional_costs_buy_gas": "Šablona pro výpočet konečné ceny po zahrnutí dodatečných nákladů. Použijte `value` pro získání aktualní ceny. Můžete použít `day` v UTC pro spotové ceny. Pokud nezadáte žádnou šablonu, senzor nebude vytvořen." } } } }, "entity": { "binary_sensor": { - "current_spot_electricity_is_cheapest": { + "spot_electricity_has_tomorrow_data": { + "name": "K dispozici zítřejší spotové ceny elektřiny" + }, + "spot_electricity_is_cheapest": { "name": "Aktuální spotová cena elektřiny je nejlevnější" }, - "current_spot_electricity_is_cheapest_hours_block": { + "spot_electricity_is_cheapest_hours_block": { "name": "Aktuální blok {hours} hodin spotových cen elektřiny je nejlevnější" }, - "tomorrow_spot_electricity_has_data": { - "name": "K dispozici zítřejší spotové ceny elektřiny" - }, - "tomorrow_spot_gas_has_data": { + "spot_gas_has_tomorrow_data": { "name": "K dispozici zítřejší spotové ceny plynu" + }, + "buy_electricity_is_cheapest": { + "name": "Aktuální nákupní cena elektřiny je nejlevnější" + }, + "buy_electricity_is_cheapest_hours_block": { + "name": "Aktuální blok {hours} hodin nákupních cen elektřiny je nejlevnější" + }, + "sell_electricity_is_cheapest": { + "name": "Aktuální prodejní cena elektřiny je nejlevnější" + }, + "sell_electricity_is_cheapest_hours_block": { + "name": "Aktuální blok {hours} hodin prodejních cen elektřiny je nejlevnější" } }, "sensor": { "current_spot_electricity_price": { "name": "Aktuální spotová cena elektřiny" }, - "current_spot_electricity_buy_price": { - "name": "Aktuální nákupní spotová cena elektřiny" + "spot_electricity_cheapest_today": { + "name": "Dnešní nejlevnější spotová cena elektřiny" }, - "current_spot_electricity_sell_price": { - "name": "Aktuální prodejní spotová cena elektřiny" + "spot_electricity_cheapest_tomorrow": { + "name": "Zítřejší nejlevnější spotová cena elektřiny" }, - "current_spot_electricity_hour_order": { - "name": "Pořadí aktuální hodiny spotových cen elektřiny" + "spot_electricity_has_tomorrow_data": { + "name": "K dispozici zítřejší spotové ceny elektřiny (Zastaralé)" }, - "current_spot_electricity_is_cheapest": { + "spot_electricity_is_cheapest": { "name": "Aktuální spotová cena elektřiny je nejlevnější (Zastaralé)" }, - "current_spot_electricity_is_cheapest_hours_block": { + "spot_electricity_is_cheapest_hours_block": { "name": "Aktuální blok {hours} hodin spotových cen elektřiny je nejlevnější (Zastaralé)" }, - "today_spot_electricity_cheapest": { - "name": "Dnešní nejlevnější spotová cena elektřiny" + "spot_electricity_hour_order_today": { + "name": "Dnešní pořadí hodin spotových cen elektřiny" }, - "today_spot_electricity_most_expensive": { - "name": "Dnešní nejdražší spotová cena elektřiny" + "spot_electricity_hour_order_tomorrow": { + "name": "Pořadí zítřejších hodin spotových cen elektřiny" }, - "tomorrow_spot_electricity_cheapest": { - "name": "Zítřejší nejlevnější spotová cena elektřiny" + "spot_electricity_most_expensive_today": { + "name": "Dnešní nejdražší spotová cena elektřiny" }, - "tomorrow_spot_electricity_most_expensive": { + "spot_electricity_most_expensive_tomorrow": { "name": "Zítřejší nejdražší spotová cena elektřiny" }, - "tomorrow_spot_electricity_has_data": { - "name": "K dispozici zítřejší spotové ceny elektřiny (Zastaralé)" - }, - "tomorrow_spot_electricity_hour_order": { - "name": "Pořadí zítřejších hodin spotových cen elektřiny" + "spot_gas_has_tomorrow_data": { + "name": "K dispozici zítřejší spotové ceny plynu (Zastaralé)" }, "current_spot_gas_price": { "name": "Aktuální spotová cena plynu" }, - "current_spot_gas_buy_price": { - "name": "Aktuální nákupní spotová cena plynu" - }, "tomorrow_spot_gas_price": { "name": "Zítřejší spotová cena plynu" }, - "tomorrow_spot_gas_has_data": { - "name": "K dispozici zítřejší spotové ceny plynu (Zastaralé)" + + + + "current_buy_electricity_price": { + "name": "Aktuální nákupní cena elektřiny" + }, + "current_spot_electricity_buy_price": { + "name": "Aktuální nákupní cena elektřiny (Zastaralé)" + }, + "buy_electricity_cheapest_today": { + "name": "Dnešní nejlevnější nákupní cena elektřiny" + }, + "buy_electricity_cheapest_tomorrow": { + "name": "Zítřejší nejlevnější nákupní cena elektřiny" + }, + "buy_electricity_hour_order_today": { + "name": "Dnešní pořadí hodin nákupních cen elektřiny" + }, + "buy_electricity_hour_order_tomorrow": { + "name": "Pořadí zítřejších hodin nákupních cen elektřiny" + }, + "buy_electricity_most_expensive_today": { + "name": "Dnešní nejdražší nákupní cena elektřiny" + }, + "buy_electricity_most_expensive_tomorrow": { + "name": "Zítřejší nejdražší nákupní cena elektřiny" + }, + "current_buy_gas_price": { + "name": "Aktuální nákupní cena plynu" + }, + "current_spot_gas_buy_price": { + "name": "Aktuální nákupní cena plynu (Zastaralé)" + }, + "tomorrow_buy_gas_price": { + "name": "Zítřejší nákupní cena plynu" + }, + + + + "current_sell_electricity_price": { + "name": "Aktuální prodejní cena elektřiny" + }, + "current_spot_electricity_sell_price": { + "name": "Aktuální prodejní cena elektřiny (Zastaralé)" + }, + "sell_electricity_cheapest_today": { + "name": "Dnešní nejlevnější prodejní cena elektřiny" + }, + "sell_electricity_cheapest_tomorrow": { + "name": "Zítřejší nejlevnější prodejní cena elektřiny" + }, + "sell_electricity_hour_order_today": { + "name": "Dnešní pořadí hodin prodejních cen elektřiny" + }, + "sell_electricity_hour_order_tomorrow": { + "name": "Pořadí zítřejších hodin prodejních cen elektřiny" + }, + "sell_electricity_most_expensive_today": { + "name": "Dnešní nejdražší prodejní cena elektřiny" + }, + "sell_electricity_most_expensive_tomorrow": { + "name": "Zítřejší nejdražší prodejní cena elektřiny" } } } diff --git a/custom_components/cz_energy_spot_prices/translations/en.json b/custom_components/cz_energy_spot_prices/translations/en.json index 8799276..37cfde1 100644 --- a/custom_components/cz_energy_spot_prices/translations/en.json +++ b/custom_components/cz_energy_spot_prices/translations/en.json @@ -20,76 +20,142 @@ "additional_costs_buy_gas": "Gas cost when buying" }, "data_description": { - "additional_costs_buy_electricity": "Template to calculate actual costs with additional fees. Use `value` to get current spot price. For example to add 21 percent VAT to the price use `'{{ value * 1.21 }}`", - "additional_costs_sell_electricity": "Template to calculate actual costs with additional fees. Use `value` to get current spot price. For example to fixed 0.25 operator fee to the price use `'{{ value - 0.25 }}`", - "additional_costs_buy_gas": "Template to calculate actual costs with additional fees. Use `value` to get current spot price." + "additional_costs_buy_electricity": "Template to calculate actual costs with additional fees. Use `value` to get current price, for example, to add 21 percent VAT to the price use `'{{ value * 1.21 }}`. Use `hour` to calculate the price for a specific hour if the rate varies by hour, such as high and low tariffs. The `hour` value is in UTC. If you need the local time, use `as_local(hour)`. If you do not enter a template, the sensor will not be created.", + "additional_costs_sell_electricity": "Template to calculate actual costs with additional fees. Use `value` to get current price, for example, to subtract fixed 0.25 operator fee use `'{{ value - 0.25 }}`. Use `hour` to calculate the price for a specific hour if the rate varies by hour, such as high and low tariffs. The `hour` value is in UTC. If you need the local time, use `as_local(hour)`. If you do not enter a template, the sensor will not be created.", + "additional_costs_buy_gas": "Template to calculate actual costs with additional fees. Use `value` to get current spot price. You can use `day` in UTC for spot prices. If you do not enter a template, the sensor will not be created." } } } }, "entity": { "binary_sensor": { - "current_spot_electricity_is_cheapest": { - "name": "Current Spot Electricity Is Cheapest" + "spot_electricity_has_tomorrow_data": { + "name": "Spot Electricity has Tomorrow Data" }, - "current_spot_electricity_is_cheapest_hours_block": { - "name": "Current Spot Electricity Is Cheapest {hours} Hours Block" + "spot_electricity_is_cheapest": { + "name": "Current Spot Electricity is Cheapest" }, - "tomorrow_spot_electricity_has_data": { - "name": "Tomorrow Spot Electricity Has Data" + "spot_electricity_is_cheapest_hours_block": { + "name": "Current Spot Electricity is Cheapest {hours} Hours Block" }, - "tomorrow_spot_gas_has_data": { - "name": "Tomorrow Spot Gas Has Data" + "spot_gas_has_tomorrow_data": { + "name": "Spot Gas has Tomorrow Data" + }, + "buy_electricity_is_cheapest": { + "name": "Current Buy Electricity is Cheapest" + }, + "buy_electricity_is_cheapest_hours_block": { + "name": "Current Buy Electricity is Cheapest {hours} Hours Block" + }, + "sell_electricity_is_cheapest": { + "name": "Current Sell Electricity is Cheapest" + }, + "sell_electricity_is_cheapest_hours_block": { + "name": "Current Sell Electricity is Cheapest {hours} Hours Block" } }, "sensor": { "current_spot_electricity_price": { "name": "Current Spot Electricity Price" }, - "current_spot_electricity_buy_price": { - "name": "Current Spot Electricity Buy Price" - }, - "current_spot_electricity_sell_price": { - "name": "Current Spot Electricity Sell Price" + "spot_electricity_cheapest_today": { + "name": "Today Cheapest Spot Electricity" }, - "current_spot_electricity_hour_order": { - "name": "Current Spot Electricity Hour Order" + "spot_electricity_cheapest_tomorrow": { + "name": "Tomorrow Cheapest Spot Electricity" }, - "current_spot_electricity_is_cheapest": { - "name": "Current Spot Electricity Is Cheapest (Deprecated)" + "spot_electricity_has_tomorrow_data": { + "name": "Spot Electricity has Tomorrow Data (Deprecated)" }, - "current_spot_electricity_is_cheapest_hours_block": { - "name": "Current Spot Electricity Is Cheapest {hours} Hours Block (Deprecated)" + "spot_electricity_is_cheapest": { + "name": "Current Spot Electricity is Cheapest (Deprecated)" }, - "today_spot_electricity_cheapest": { - "name": "Today Spot Cheapest Electricity" + "spot_electricity_is_cheapest_hours_block": { + "name": "Current Spot Electricity is Cheapest {hours} Hours Block (Deprecated)" }, - "today_spot_electricity_most_expensive": { - "name": "Today Spot Most Expensive Electricity" + "spot_electricity_hour_order_today": { + "name": "Today Spot Electricity Hour Order" }, - "tomorrow_spot_electricity_cheapest": { - "name": "Tomorrow Spot Cheapest Electricity" + "spot_electricity_hour_order_tomorrow": { + "name": "Tomorrow Spot Electricity Hour Order" }, - "tomorrow_spot_electricity_most_expensive": { - "name": "Tomorrow Spot Most Expensive Electricity" + "spot_electricity_most_expensive_today": { + "name": "Today Most Expensive Spot Electricity" }, - "tomorrow_spot_electricity_has_data": { - "name": "Tomorrow Spot Electricity Has Data (Deprecated)" + "spot_electricity_most_expensive_tomorrow": { + "name": "Tomorrow Most Expensive Spot Electricity" }, - "tomorrow_spot_electricity_hour_order": { - "name": "Tomorrow Spot Electricity Hour Order" + "spot_gas_has_tomorrow_data": { + "name": "Spot Gas has Tomorrow Data (Deprecated)" }, "current_spot_gas_price": { - "name": "Current Spot Gas Price" - }, - "current_spot_gas_buy_price": { - "name": "Current Spot Gas Buy Price" + "name": "Today Spot Gas Price" }, "tomorrow_spot_gas_price": { "name": "Tomorrow Spot Gas Price" }, - "tomorrow_spot_gas_has_data": { - "name": "Tomorrow Spot Gas Has Data (Deprecated)" + + + + "current_buy_electricity_price": { + "name": "Current Buy Electricity Price" + }, + "current_spot_electricity_buy_price": { + "name": "Current Buy Electricity Price (Deprecated)" + }, + "buy_electricity_cheapest_today": { + "name": "Today Cheapest Buy Electricity Price" + }, + "buy_electricity_cheapest_tomorrow": { + "name": "Tomorrow Cheapest Buy Electricity Price" + }, + "buy_electricity_hour_order_today": { + "name": "Today Buy Electricity Hour Order" + }, + "buy_electricity_hour_order_tomorrow": { + "name": "Tomorrow Buy Electricity Hour Order" + }, + "buy_electricity_most_expensive_today": { + "name": "Today Most Expensive Buy Electricity" + }, + "buy_electricity_most_expensive_tomorrow": { + "name": "Tomorrow Most Expensive Buy Electricity" + }, + "current_buy_gas_price": { + "name": "Today Buy Gas Price" + }, + "current_spot_gas_buy_price": { + "name": "Today Buy Gas Price (Deprecated)" + }, + "tomorrow_buy_gas_price": { + "name": "Tomorrow Buy Gas Price" + }, + + + + "current_sell_electricity_price": { + "name": "Current Sell Electricity Price" + }, + "current_spot_electricity_sell_price": { + "name": "Current Sell Electricity Price (Deprecated)" + }, + "sell_electricity_cheapest_today": { + "name": "Today Cheapest Sell Electricity Price" + }, + "sell_electricity_cheapest_tomorrow": { + "name": "Tomorrow Cheapest Sell Electricity Price" + }, + "sell_electricity_hour_order_today": { + "name": "Today Sell Electricity Hour Order" + }, + "sell_electricity_hour_order_tomorrow": { + "name": "Tomorrow Sell Electricity Hour Order" + }, + "sell_electricity_most_expensive_today": { + "name": "Today Most Expensive Sell Electricity" + }, + "sell_electricity_most_expensive_tomorrow": { + "name": "Tomorrow Most Expensive Sell Electricity" } } } diff --git a/custom_components/cz_energy_spot_prices/translations/sk.json b/custom_components/cz_energy_spot_prices/translations/sk.json index c659e3c..83a6a5a 100644 --- a/custom_components/cz_energy_spot_prices/translations/sk.json +++ b/custom_components/cz_energy_spot_prices/translations/sk.json @@ -20,76 +20,142 @@ "additional_costs_buy_gas": "Cena plynu pri nákupe" }, "data_description": { - "additional_costs_buy_electricity": "Šablóna pre výpočet konečnej ceny po zahrnutí dodatočných nákladov. Použite `value` pre získanie aktualnej spotovej ceny. Napríklad pre pridanie 20 percent DPH použite `'{{ value * 1.20 }}`.", - "additional_costs_sell_electricity": "Šablóna pre výpočet konečnej ceny po zahrnutí dodatočných nákladov. Použite `value` pre získanie aktualnej spotovej ceny. Napríklad pre pridanie fixného poplatku operátora vo výške 0.25 použite `'{{ value - 0.25 }}`.", - "additional_costs_buy_gas": "Šablóna pre výpočet konečnej ceny po zahrnutí dodatočných nákladov. Použite `value` pre získanie aktuálnej spotovej ceny." + "additional_costs_buy_electricity": "Šablóna pre výpočet konečnej ceny po zahrnutí dodatočných nákladov. Použite `value` pre získanie aktualnej ceny, napríklad pre pridanie 21 percent DPH použite `'{{ value * 1.21 }}`. Použite `hour` na výpočet ceny v danej hodine, ak sa sadzba v jednotlivých hodinách líši, napríklad pre vysoký a nízky tarif. Hodnota `hour` je v UTC. Ak potrebujete lokálny čas, použite `as_local(hour)`. Ak nezadáte žiadnu šablónu, senzor nebude vytvorený.", + "additional_costs_sell_electricity": "Šablóna pre výpočet konečnej ceny po zahrnutí dodatočných nákladov. Použite `value` pre získanie aktualnej ceny, napríklad pre odpočítanie fixného poplatku operátora vo výške 0.25 použite `'{{ value - 0.25 }}`. Použite `hour` na výpočet ceny v danej hodine, ak sa sadzba v jednotlivých hodinách líši, napríklad pre vysoký a nízky tarif. Hodnota `hour` je v UTC. Ak potrebujete lokálny čas, použite `as_local(hour)`. Ak nezadáte žiadnu šablónu, senzor nebude vytvorený.", + "additional_costs_buy_gas": "Šablóna pre výpočet konečnej ceny po zahrnutí dodatočných nákladov. Použite `value` pre získanie aktuálnej ceny. Môžete použiť `day` v UTC pre spotové ceny. Ak nezadáte žiadnu šablónu, senzor nebude vytvorený." } } } }, "entity": { "binary_sensor": { - "current_spot_electricity_is_cheapest": { + "spot_electricity_has_tomorrow_data": { + "name": "K dispozícii zajtrajšie spotové ceny elektriny" + }, + "spot_electricity_is_cheapest": { "name": "Aktuálna spotová cena elektriny je najlacnejšia" }, - "current_spot_electricity_is_cheapest_hours_block": { + "spot_electricity_is_cheapest_hours_block": { "name": "Aktuálny blok {hours} hodín spotových cien elektriny je najlacnejší" }, - "tomorrow_spot_electricity_has_data": { - "name": "K dispozícii zajtrajšie spotové ceny elektriny" + "spot_gas_has_tomorrow_data": { + "name": "K dispozícii zajtrajšie spotové ceny plynu" + }, + "buy_electricity_is_cheapest": { + "name": "Aktuálna nákupná cena elektriny je najlacnejšia" + }, + "buy_electricity_is_cheapest_hours_block": { + "name": "Aktuálny blok {hours} hodín nákupných cien elektriny je najlacnejší" }, - "tomorrow_spot_gas_has_data": { - "name": "K dispozícii zajtrajšie spotové ceny plynu" + "sell_electricity_is_cheapest": { + "name": "Aktuálna predajná cena elektriny je najlacnejšia" + }, + "sell_electricity_is_cheapest_hours_block": { + "name": "Aktuálny blok {hours} hodín predajných cien elektriny je najlacnejší" } }, "sensor": { "current_spot_electricity_price": { "name": "Aktuálna spotová cena elektriny" }, - "current_spot_electricity_buy_price": { - "name": "Aktuálna nákupná spotová cena elektriny" + "spot_electricity_cheapest_today": { + "name": "Dnešná najlacnejšia spotová cena elektriny" }, - "current_spot_electricity_sell_price": { - "name": "Aktuálna predajná spotová cena elektriny" + "spot_electricity_cheapest_tomorrow": { + "name": "Zajtrajšia najlacnejšia spotová cena elektriny" }, - "current_spot_electricity_hour_order": { - "name": "Poradie aktuálnych hodín spotových cien elektriny" + "spot_electricity_has_tomorrow_data": { + "name": "K dispozícii zajtrajšie spotové ceny elektriny (Zastaralé)" }, - "current_spot_electricity_is_cheapest": { - "name": "Aktuálna spotová cena elektriny je najlacnejšia (Zastaralé)" + "spot_electricity_is_cheapest": { + "name": "Aktuálna nákupná cena elektriny je najlacnejšia (Zastaralé)" }, - "current_spot_electricity_is_cheapest_hours_block": { - "name": "Aktuálny blok {hours} hodín spotových cien elektriny je najlacnejší" + "spot_electricity_is_cheapest_hours_block": { + "name": "Aktuálny blok {hours} hodín spotových cien elektriny je najlacnejší (Zastaralé)" }, - "today_spot_electricity_cheapest": { - "name": "Dnešná najlacnejšia spotová cena elektriny" + "spot_electricity_hour_order_today": { + "name": "Poradie dnešných hodín spotových cien elektriny" }, - "today_spot_electricity_most_expensive": { - "name": "Dnešná najdrahšia spotová cena elektriny" + "spot_electricity_hour_order_tomorrow": { + "name": "Poradie zajtrajších hodín spotových cien elektriny" }, - "tomorrow_spot_electricity_cheapest": { - "name": "Zajtrajšia najlacnejšia spotová cena elektriny" + "spot_electricity_most_expensive_today": { + "name": "Dnešná najdrahšia spotová cena elektriny" }, - "tomorrow_spot_electricity_most_expensive": { + "spot_electricity_most_expensive_tomorrow": { "name": "Zajtrajšia najdrahšia spotová cena elektriny" }, - "tomorrow_spot_electricity_has_data": { - "name": "K dispozícii zajtrajšie spotové ceny elektriny (Zastaralé)" - }, - "tomorrow_spot_electricity_hour_order": { - "name": "Poradie zajtrajších hodín spotových cien elektriny" + "spot_gas_has_tomorrow_data": { + "name": "K dispozícii zajtrajšie spotové ceny plynu (Zastaralé)" }, "current_spot_gas_price": { - "name": "Aktuálna spotová cena plynu" - }, - "current_spot_gas_buy_price": { - "name": "Aktuálna nákupná spotová cena plynu" + "name": "Dnešná spotová cena plynu" }, "tomorrow_spot_gas_price": { "name": "Zajtrajšia spotová cena plynu" }, - "tomorrow_spot_gas_has_data": { - "name": "K dispozícii zajtrajšie spotové ceny plynu" + + + + "current_buy_electricity_price": { + "name": "Aktuálna nákupná cena elektriny" + }, + "current_spot_electricity_buy_price": { + "name": "Aktuálna nákupná cena elektriny (Zastaralé)" + }, + "buy_electricity_cheapest_today": { + "name": "Dnešná najlacnejšia nákupná cena elektriny" + }, + "buy_electricity_cheapest_tomorrow": { + "name": "Zajtrajšia najlacnejšia nákupná cena elektriny" + }, + "buy_electricity_hour_order_today": { + "name": "Poradie dnešných nákupných cien elektriny" + }, + "buy_electricity_hour_order_tomorrow": { + "name": "Poradie zajtrajších nákupných cien elektriny" + }, + "buy_electricity_most_expensive_today": { + "name": "Dnešná najdrahšia nákupná cena elektriny" + }, + "buy_electricity_most_expensive_tomorrow": { + "name": "Zajtrajšia najdrahšia nákupná cena elektriny" + }, + "current_buy_gas_price": { + "name": "Dnešná nákupná cena plynu" + }, + "current_spot_gas_buy_price": { + "name": "Dnešná nákupná cena plynu (Deprecated)" + }, + "tomorrow_buy_gas_price": { + "name": "Zajtrajšia nákupná cena plynu" + }, + + + + "current_sell_electricity_price": { + "name": "Aktuálna predajná cena elektriny" + }, + "current_spot_electricity_sell_price": { + "name": "Aktuálna predajná cena elektriny (Zastaralé)" + }, + "sell_electricity_cheapest_today": { + "name": "Dnešná najlacnejšia predajná cena elektriny" + }, + "sell_electricity_cheapest_tomorrow": { + "name": "Zajtrajšia najlacnejšia predajná cena elektriny" + }, + "sell_electricity_hour_order_today": { + "name": "Poradie dnešných hodín predajných cien elektriny" + }, + "sell_electricity_hour_order_tomorrow": { + "name": "Poradie zajtrajších hodín predajných cien elektriny" + }, + "sell_electricity_most_expensive_today": { + "name": "Dnešná najdrahšia predajná cena elektriny" + }, + "sell_electricity_most_expensive_tomorrow": { + "name": "Zajtrajšia najdrahšia predajná cena elektriny" } } }