# Start pack for Spot Price control.
# Version 0.1.11 lampopumput.info unofficial edit
#
# This is a copy-paste approach in order to get Finnish Electricity Spot Prices to Home Assistant.
# Initial implementation by Temez but feel free to further develop this.
# Special thanks to Mikki who has created the API where data is fetched. For more information see https://spot-hinta.fi/
# This is just a loader for the data which is stored in sensor attributes. Template sensors present actual data.
sensor:
- platform: rest
resource: https://api.spot-hinta.fi/TodayAndDayForward?HomeAssistant=true
name: SHF Electricity price
unique_id: shf_electricity_price
scan_interval: 604800 # 7 days, update logic is in the automation
value_template: 'OK' # static value as sensor is not updated regularly
json_attributes:
- "data"
- platform: statistics
name: "SHF Average Price 7 Days"
entity_id: sensor.shf_electricity_price_now
state_characteristic: mean
unique_id: shf_average_7days
precision: 4
max_age:
days: 7
template:
- sensor:
- name: SHF Idx # Helper for other sensors to get correct price/rank from array
unique_id: shf_helper_idx
state: '{{ 0 if state_attr("sensor.shf_electricity_price_now", "data")[0]["DateTime"][8:10] | int == now().day else 24 }}'
- sensor:
- name: SHF Rank now
unique_id: shf_electricity_rank_now
unit_of_measurement: Rank
state: '{{ state_attr("sensor.shf_electricity_price_now", "data")[states("sensor.shf_idx")|int+now().hour]["Rank"] }}'
- sensor:
- name: SHF Electricity price now
unique_id: shf_electricity_price_now
unit_of_measurement: "€/kWh"
device_class: monetary
state: '{{ state_attr("sensor.shf_electricity_price_now", "today_prices")[now().hour] | default(none) }}'
attributes:
data: '{{ state_attr("sensor.shf_electricity_price", "data") if state_attr("sensor.shf_electricity_price", "data") else state_attr("sensor.shf_electricity_price_now", "data") }}'
all_prices: >
{% set output = namespace(value=[]) %}
{% for value in (state_attr("sensor.shf_electricity_price_now", "data")) | map(attribute="PriceWithTax") | list %}
{% if ((loop.index - 1) % 24) >= state_attr("input_datetime.shf_price2_start", "hour") and ((loop.index - 1) % 24) < state_attr("input_datetime.shf_price2_stop", "hour") %}
{% set output.value = output.value + [ value + states('input_number.shf_price2_slider') | float] %}
{% else %}
{% set output.value = output.value + [ value + states('input_number.shf_price1_slider') | float] %}
{% endif %}
{% endfor %}
{{ output.value if output.value | length > 0 else state_attr("sensor.shf_electricity_price_now", "all_prices") }}
today_prices: '{{ (state_attr("sensor.shf_electricity_price_now", "all_prices"))[states("sensor.shf_idx")|int:states("sensor.shf_idx")|int+24] | list }}'
tomorrow_prices: '{{ (state_attr("sensor.shf_electricity_price_now", "all_prices"))[states("sensor.shf_idx")|int+24:] | list }}'
today_min: '{{ state_attr("sensor.shf_electricity_price_now", "today_prices") | min }}'
today_avg: '{{ state_attr("sensor.shf_electricity_price_now", "today_prices") | average | round(4) }}'
today_max: '{{ state_attr("sensor.shf_electricity_price_now", "today_prices") | max }}'
tomorrow_min: '{{ state_attr("sensor.shf_electricity_price_now", "tomorrow_prices") | min | default("unknown") }}'
tomorrow_avg: '{{ state_attr("sensor.shf_electricity_price_now", "tomorrow_prices") | average("unknown") }}'
tomorrow_max: '{{ state_attr("sensor.shf_electricity_price_now", "tomorrow_prices") | max | default("unknown") }}'
- sensor:
- name: SHF Average price today
unique_id: shf_average_electricity_price
unit_of_measurement: "€/kWh"
device_class: monetary
state: '{{ state_attr("sensor.shf_electricity_price_now", "today_avg") }}'
- sensor:
- name: SHF Average price next hours
unique_id: shf_average_electricity_price_next_hours
unit_of_measurement: "€/kWh"
device_class: monetary
state: >
{% set idx = states("sensor.shf_idx")|int + now().hour + 1 %}
{{ (state_attr("sensor.shf_electricity_price_now", "all_prices"))[idx:idx+states("input_number.shf_price_avg_slider")|int] | average | round(3) }}
- sensor:
- name: SHF Cheapest period start helper
unique_id: shf_cheapest_period_start_helper
state: >
{% set output = namespace(value=[]) %}
{% set data = state_attr("sensor.shf_electricity_price_now", "all_prices")[15:39] %}
{% set hours = states("input_number.shf_cheapest_period_slider") | int%}
{%- for inval in data[:min(-hours+1, -1)] -%}
{% set temp = namespace(value=[]) %}
{%- set j = loop.index -1 -%}
{%- for i in range(hours) %}
{%- set temp.value = temp.value + [data[j+i]] -%}
{%- endfor -%}
{%- set output.value = output.value + [temp.value | average] -%}
{%- endfor -%}
{% set data2 = state_attr("sensor.shf_electricity_price_now", "data")[15:39] %}
{{ data2[output.value.index(output.value|min)]["DateTime"] }}
- sensor:
- name: SHF Control Factor 0-1
unique_id: shf_control_factor_0-1
unit_of_measurement: factor
icon: mdi:gauge
state: '{{ (states("sensor.shf_control_factor_1") | float /2 + 0.5) | default(none) }}'
attributes:
today_values: >
{% set output = namespace(value=[]) %}
{% for value in state_attr("sensor.shf_control_factor_1", "today_values") %}
{% set output.value = output.value + [ value | float /2 + 0.5 ] %}
{% endfor %}
{{ output.value }}
- sensor:
- name: SHF Control Factor +-1
unique_id: shf_control_factor_+-1
unit_of_measurement: factor
icon: mdi:gauge
state: '{{ state_attr("sensor.shf_control_factor_1", "today_values")[now().hour] | default(none) }}'
attributes:
today_values: >
{% set output = namespace(value=[]) %}
{% for pnow in state_attr("sensor.shf_electricity_price_now", "today_prices") %}
{% set pmin = state_attr("sensor.shf_electricity_price_now", "today_min") | float %}
{% set pmax = state_attr("sensor.shf_electricity_price_now", "today_max") | float %}
{% set value = max(min((2*(pmax - pnow) / (pmax - pmin)-1) * states('input_number.shf_control_function_factor') | float,1),-1) %}
{% if states("input_select.shf_control_function" ) == "Linear" %}
{% set output.value = output.value + [value | round(2)] %}
{% else %}
{% set output.value = output.value + [sin(value*pi/2) | round(2)] %}
{% endif %}
{% endfor %}
{{ output.value }}
- binary_sensor:
- name: "SHF Rank acceptable"
unique_id: shf_rank_acceptable
device_class: power
state: >
{% set value = state_attr("sensor.shf_electricity_price_now", "data")[states("sensor.shf_idx")|int+now().hour] %}
{{ value["Rank"] <= states("input_number.shf_rank_slider") | int }}
- binary_sensor:
- name: "SHF Price acceptable"
unique_id: shf_price_acceptable
device_class: power
state: >
{% set value = state_attr("sensor.shf_electricity_price_now", "today_prices")[ now().hour ] %}
{{ value <= states("input_number.shf_price_slider") | float }}
- binary_sensor:
- name: "SHF Price or Rank acceptable"
unique_id: shf_price_or_rank_acceptable
device_class: power
state: '{{ is_state("binary_sensor.shf_rank_acceptable", "on") or is_state("binary_sensor.shf_price_acceptable", "on") }}'
input_select:
shf_control_function:
name: SHF Control Function
options:
- Linear
- Sinusoidal
icon: mdi:gauge
input_number:
shf_control_function_factor:
name: SHF Control Function Factor
min: 1
max: 3
step: 0.01
icon: mdi:gauge
mode: box
shf_rank_slider:
name: SHF Max Rank allowed
min: 1
max: 24
step: 1
shf_price_slider:
name: SHF Max Price allowed
min: 0
max: 4
step: 0.01
unit_of_measurement: €/kWh
icon: mdi:cash-lock
mode: box
shf_price_avg_slider:
name: SHF Average price hours
min: 1
max: 24
step: 1
unit_of_measurement: h
icon: mdi:cash-clock
shf_cheapest_period_slider:
name: SHF Cheapest period hours
min: 1
max: 24
step: 1
unit_of_measurement: h
icon: mdi:cash-clock
shf_control_factor:
name: SHF Control Factor
min: 0
max: 1000
mode: box
shf_price1_slider:
name: SHF Price1
min: 0
max: 1000
step: 0.0001
unit_of_measurement: €
icon: mdi:cash-lock
mode: box
shf_price2_slider:
name: SHF Price2
min: 0
max: 1000
step: 0.0001
unit_of_measurement: €
icon: mdi:cash-lock
mode: box
input_datetime:
shf_cheapest_period_start:
name: SHF Cheapest period start
has_date: true
has_time: true
shf_price2_start:
name: SHF Price2 start
has_date: false
has_time: true
shf_price2_stop:
name: SHF Price2 stop
has_date: false
has_time: true
#Automation for automatic updating of the sensor. Tries to reduce API load.
automation:
- id: '1669453089221'
alias: Intelligent update of electricity price sensor
description: 'Tries to fetch new data every 15mins after 14 oclock local time. Condition stops unnecessary requests. Random delay disperses API calls.'
trigger:
- platform: time_pattern
minutes: /15
alias: Trigger every 15mins
condition:
- condition: template
value_template: '{{ is_state("sensor.shf_electricity_price", "unavailable") or is_state("sensor.shf_idx", "unavailable") or (now().hour >= 14 and (states("sensor.shf_idx") | int > 0 or state_attr("sensor.shf_electricity_price", "data") | length <= 24)) }}'
alias: Check if there isn't data for tomorrow and time is after 14 o'clock
action:
- delay: '{{ range(60, 600)|random }}'
alias: Random delay in order to reduce API congestion
- service: homeassistant.update_entity
alias: Trigger the update of the sensor
target:
entity_id: sensor.shf_electricity_price
mode: single
- id: '1669453089222'
alias: "Copy cheapest period to datetime sensor"
description: "Copies cheapest period start from helper to datetime sensor for easier automations."
mode: single
trigger:
- platform: state
entity_id:
- sensor.shf_cheapest_period_start_helper
condition: []
action:
- service: input_datetime.set_datetime
data:
datetime: '{{ states("sensor.shf_cheapest_period_start_helper")[:19] | replace("T", " ") }}'
target:
entity_id: input_datetime.shf_cheapest_period_start