rnovacek / homeassistant_cz_energy_spot_prices

Home Assistant integration that provides current Czech electricity spot prices based on OTE.
Apache License 2.0
91 stars 22 forks source link

Add Spot Electricity Is Most Expensive X Hours Block #58

Open DrcCZ opened 4 months ago

DrcCZ commented 4 months ago

Hi. Add additional sensor for most expensive electricity prices, similar to "Spot Electricity Is Cheapest X Hours Block" but looking not on cheapest but most expensive price block. Use floating block of X hours, calculate average price from all hours in that windows and if it is most expensive from all floating blocks during the day then it is the right most expensive price block of X hours. IMHO current cheapest X hours block works differently (incorrectly) as not always is selected the right hours block?

klubalo commented 4 months ago

I using this template for finding block of two most expensive hours:

{% set data = namespace(hour_block_start=-1, max_price_sum=0, prices=[]) %}

{# Gather prices for each hour #}
{% for i in range(0, 24) %}
  {% set time_dt = now() %}
  {% set hour_dt = time_dt.replace(hour=i, minute=0, second=0, microsecond=0).isoformat() %}
  {% set price = state_attr('sensor.current_spot_electricity_price', hour_dt) %}
  {% if price is not none %}
    {% set data.prices = data.prices + [(i, price)] %}
  {% endif %}
{% endfor %}

{# Find the block of 2 consecutive hours with the highest combined price #}
{% for i in range(0, data.prices | length - 1) %}
  {% set price_sum = data.prices[i][1] + data.prices[i + 1][1] %}
  {% if price_sum > data.max_price_sum %}
    {% set data.hour_block_start = data.prices[i][0] %}
    {% set data.max_price_sum = price_sum %}
  {% endif %}
{% endfor %}

{# Determine if the current hour is within the most expensive block #}
{% set current_hour = now().hour %}
{% set is_within_block = (current_hour == data.hour_block_start) or (current_hour == (data.hour_block_start + 1) % 24) %}
{{ is_within_block }}

Here is more universal variant:

{# Define the block size X #}
{% set block_size = 4 %}
{% set data = namespace(hour_block_start=-1, max_price_sum=0, prices=[]) %}

{# Gather prices for each hour #}
{% for i in range(0, 24) %}
  {% set time_dt = now() %}
  {% set hour_dt = time_dt.replace(hour=i, minute=0, second=0, microsecond=0).isoformat() %}
  {% set price = state_attr('sensor.current_spot_electricity_price', hour_dt) %}
  {% if price is not none %}
    {% set data.prices = data.prices + [(i, price)] %}
  {% endif %}
{% endfor %}

{# Find the block of X consecutive hours with the highest combined price #}
{% for i in range(0, data.prices | length - block_size + 1) %}
  {% set price_sum = 0 %}
  {% for j in range(0, block_size) %}
    {% set price_sum = price_sum + data.prices[i + j][1] %}
  {% endfor %}
  {% if price_sum > data.max_price_sum %}
    {% set data.hour_block_start = data.prices[i][0] %}
    {% set data.max_price_sum = price_sum %}
  {% endif %}
{% endfor %}

{# Determine if the current hour is within the most expensive block #}
{% set current_hour = now().hour %}
{% set is_within_block = false %}
{% for j in range(0, block_size) %}
  {% if current_hour == (data.hour_block_start + j) % 24 %}
    {% set is_within_block = true %}
    {% break %}
  {% endif %}
{% endfor %}
{{ is_within_block }}
Paja-git commented 3 weeks ago

Just for those who will re-use the @klubalo 's code, variables used in the for loops have to be specified in the namespace. Like price_sum and etc.