592 lines
28 KiB
YAML
592 lines
28 KiB
YAML
- automation emhass:
|
|
- id: emhass_naive_mpc_optim_forecast
|
|
alias: EMHASS - naive mpc optim forecast
|
|
description: EMHASS - naive mpc optimization - upto 48 hours forecast.
|
|
triggers:
|
|
- trigger: time_pattern
|
|
minutes: /1
|
|
actions:
|
|
- metadata: {}
|
|
data: {}
|
|
enabled: true
|
|
continue_on_error: false
|
|
response_variable: rest_response
|
|
action: rest_command.emhass_naive_mpc_optim_forecast
|
|
- if:
|
|
- condition: template
|
|
value_template: '{{ rest_response[''status''] < 400 }}'
|
|
then:
|
|
- data:
|
|
prefix: all
|
|
enabled: true
|
|
continue_on_error: true
|
|
response_variable: rest_response
|
|
action: rest_command.emhass_publish_data
|
|
else:
|
|
- metadata: {}
|
|
data:
|
|
level: warning
|
|
message: '{{ rest_response[''content''] }}'
|
|
logger: EMHASS.MINUTE
|
|
action: system_log.write
|
|
mode: single
|
|
template:
|
|
- trigger:
|
|
- platform: time_pattern
|
|
minutes: /1
|
|
action:
|
|
- variables:
|
|
t: '{{ now().isoformat() }}'
|
|
var: '{% from ''032-hems.jinja'' import globalVariables %} {{ globalVariables()|from_json
|
|
}}'
|
|
grid_active_power_forecast: '{{ states(var.grid_active_power_forecast)|float(0)
|
|
}}'
|
|
house_power_forecast: '{{ states(var.house_power_forecast)|float(0) }}'
|
|
inv_rated_power: '{{ states(var.inv_rated_power)|float(0) }}'
|
|
inv_max_active_power: '{{ states(var.inv_max_active_power)|float(0) }}'
|
|
inv_in_power: '{{ states(var.inv_in_power)|float(0) }}'
|
|
inv_active_power_forecast: '{{ states(var.inv_active_power_forecast)|float(0)
|
|
}}'
|
|
prediction_status: '{{ states(var.prediction_status) }}'
|
|
epexspot_quantile: '{{ states(var.epexspot_quantile)|float(0) }}'
|
|
house_in_forecast: '{{ states(var.house_in_forecast)|float(0) }}'
|
|
house_in_forecast_solar_noon: '{{ state_attr(var.house_in_forecast, ''solar_noon_energy'')|float(0)
|
|
}}'
|
|
house_in_forecast_prediction_end: '{{ state_attr(var.house_in_forecast, ''prediction_end_energy'')|float(0)
|
|
}}'
|
|
house_in_forecast_pv_excess_start: '{{ state_attr(var.house_in_forecast, ''pv_excess_start_energy'')|float(0)
|
|
}}'
|
|
house_in_forecast_pv_excess_end: '{{ state_attr(var.house_in_forecast, ''pv_excess_end_energy'')|float(0)
|
|
}}'
|
|
inv_in_solar_forecast: '{{ states(var.inv_in_solar_forecast)|float(0) }}'
|
|
solar_noon_time: '{{ state_attr(var.solar_noon_time, ''today'')|as_datetime|as_local
|
|
}}'
|
|
inv_in_solar_forecast_solar_noon: '{{ state_attr(var.inv_in_solar_forecast,
|
|
''solar_noon_energy'')|float(0) }}'
|
|
inv_in_solar_forecast_prediction_end: '{{ state_attr(var.inv_in_solar_forecast,
|
|
''prediction_end_energy'')|float(0) }}'
|
|
inv_in_solar_forecast_pv_excess_start: '{{ state_attr(var.inv_in_solar_forecast,
|
|
''pv_excess_start_energy'')|float(0) }}'
|
|
inv_in_solar_forecast_pv_excess_end: '{{ state_attr(var.inv_in_solar_forecast,
|
|
''pv_excess_end_energy'')|float(0) }}'
|
|
bat_rated_charge_power: '{{ states(var.bat_rated_charge_power)|float(5000)
|
|
}}'
|
|
bat_rated_discharge_power: '{{ states(var.bat_rated_discharge_power)|float(5000)
|
|
}}'
|
|
bat_soc: '{{ states(var.bat_soc)|float(0) }}'
|
|
bat_eoc: '{{ states(var.bat_eoc)|float(0) }}'
|
|
bat_charge_energy_forecast: '{{ inv_in_solar_forecast - house_in_forecast
|
|
}}'
|
|
bat_charge_energy_forecast_solar_noon: '{{ inv_in_solar_forecast_solar_noon
|
|
- house_in_forecast_solar_noon }}'
|
|
bat_charge_energy_forecast_prediction_end: '{{ inv_in_solar_forecast_prediction_end
|
|
- house_in_forecast_prediction_end }}'
|
|
bat_charge_energy_forecast_pv_excess_start: '{{ inv_in_solar_forecast_pv_excess_start
|
|
- house_in_forecast_pv_excess_start }}'
|
|
bat_charge_energy_forecast_pv_excess_end: '{{ inv_in_solar_forecast_pv_excess_end
|
|
- house_in_forecast_pv_excess_end }}'
|
|
bat_soc_setpoint_low: '{{ states(var.bat_soc_setpoint_low)|float(0) }}'
|
|
bat_soc_setpoint_neutral: '{{ states(var.bat_soc_setpoint_neutral)|float(0)
|
|
}}'
|
|
bat_soc_setpoint_high: '{{ states(var.bat_soc_setpoint_high)|float(0) }}'
|
|
bat_soc_setpoint_forcible_charge: '{{ states(var.bat_soc_setpoint_forcible_charge)|float(0)
|
|
}}'
|
|
epexspot_quantile_setpoint_low: '{{ states(var.epexspot_quantile_setpoint_low)|float(0)
|
|
}}'
|
|
epexspot_quantile_setpoint_neutral: '{{ states(var.epexspot_quantile_setpoint_neutral)|float(0)
|
|
}}'
|
|
epexspot_quantile_setpoint_high: '{{ states(var.epexspot_quantile_setpoint_high)|float(0)
|
|
}}'
|
|
binary_sensor:
|
|
- name: HEMS Batteries Charge from grid control
|
|
unique_id: batteries_charge_from_grid
|
|
icon: mdi:battery-charging-50
|
|
state: "{{ house_power_forecast > 0\n and grid_active_power_forecast > 0\n\
|
|
\ and inv_active_power_forecast < 0\n and epexspot_quantile <= epexspot_quantile_setpoint_low\n\
|
|
\ and prediction_status == 'Optimal' }}"
|
|
attributes:
|
|
epexspot_quantile: '{{ epexspot_quantile|float(0)|round(4) }}'
|
|
epexspot_quantile_setpoint_low: '{{ epexspot_quantile_setpoint_low }}'
|
|
last_updated: '{{ t }}'
|
|
- name: HEMS Batteries Maximum charging power control
|
|
unique_id: batteries_maximum_charging_power
|
|
icon: mdi:battery-charging-50
|
|
state: '{{ bat_soc == 100 or bat_charge_energy_forecast_solar_noon <= bat_eoc
|
|
}}'
|
|
attributes:
|
|
maximum_charging_power: "{% set charge_time = ((solar_noon_time|as_timestamp\
|
|
\ - now().timestamp()) / 3600)|float(0) %}\n{% if charge_time > 0 %}\n \
|
|
\ {% set charge_power = (bat_eoc / charge_time * 1000)|float(0)|round(0)\
|
|
\ %}\n{% else %}\n {% set charge_power = bat_rated_charge_power %}\n{%\
|
|
\ endif %}\n{% if bat_soc_setpoint_neutral < bat_soc < 100\n and bat_charge_energy_forecast_solar_noon\
|
|
\ > bat_eoc\n and (inv_in_power - inv_max_active_power) > charge_power\
|
|
\ %}\n {{ inv_in_power - inv_rated_power }}\n{% elif bat_soc_setpoint_neutral\
|
|
\ < bat_soc < 100\n and bat_charge_energy_forecast_solar_noon > bat_eoc\n\
|
|
\ and charge_power < bat_rated_charge_power %}\n {{ charge_power }}\n\
|
|
{% else %}\n {{ bat_rated_charge_power }}\n{% endif %}"
|
|
charge_end_time_expected: '{{ solar_noon_time }}'
|
|
charge_energy_remaining: '{{ bat_eoc|float(0)|round(3) }}'
|
|
charge_energy_forecast_solar_noon: '{{ bat_charge_energy_forecast_solar_noon|float(0)|round(3)
|
|
}}'
|
|
charge_energy_forecast_prediction_end: '{{ bat_charge_energy_forecast_prediction_end|float(0)|round(3)
|
|
}}'
|
|
charge_energy_forecast_pv_excess_start: '{{ bat_charge_energy_forecast_pv_excess_start|float(0)|round(3)
|
|
}}'
|
|
charge_energy_forecast_pv_excess_end: '{{ bat_charge_energy_forecast_pv_excess_end|float(0)|round(3)
|
|
}}'
|
|
last_updated: '{{ t }}'
|
|
- name: HEMS Batteries Maximum discharging power control
|
|
unique_id: batteries_maximum_discharging_power
|
|
icon: mdi:battery-charging-50
|
|
state: "{% if epexspot_quantile <= epexspot_quantile_setpoint_low and bat_soc\
|
|
\ <= bat_soc_setpoint_low %}\n {{ 'off' }}\n{% else %}\n {{ 'on' }}\n{%\
|
|
\ endif %}"
|
|
attributes:
|
|
maximum_discharging_power: "{% if epexspot_quantile <= epexspot_quantile_setpoint_low\
|
|
\ and bat_soc <= bat_soc_setpoint_low %}\n {{ 0 }}\n{% else %}\n {{ bat_rated_discharge_power\
|
|
\ }}\n{% endif %}"
|
|
soc_setpoint_low: '{{ bat_soc_setpoint_low }}'
|
|
epexspot_quantile_setpoint_low: '{{ epexspot_quantile_setpoint_low }}'
|
|
last_updated: '{{ t }}'
|
|
- name: HEMS Batteries Forcible charge control
|
|
unique_id: batteries_forcible_charge
|
|
icon: mdi:battery-charging-50
|
|
state: "{{ inv_in_solar_forecast > 0.0\n and epexspot_quantile <= epexspot_quantile_setpoint_neutral\n\
|
|
\ and bat_charge_energy_forecast_prediction_end <= bat_eoc }}"
|
|
attributes:
|
|
bat_charge_energy_forecast_prediction_end: '{{ bat_charge_energy_forecast_prediction_end|float(0)|round(3)
|
|
}}'
|
|
bat_eoc: '{{ bat_eoc|float(0)|round(3) }}'
|
|
bat_target_soc: '{{ bat_soc_setpoint_forcible_charge }}'
|
|
epexspot_quantile: '{{ epexspot_quantile|float(0)|round(4) }}'
|
|
epexspot_quantile_setpoint_neutral: '{{ epexspot_quantile_setpoint_neutral|float(0)|round(4)
|
|
}}'
|
|
last_updated: '{{ t }}'
|
|
- trigger:
|
|
- platform: time_pattern
|
|
minutes: /1
|
|
action:
|
|
- variables:
|
|
t: '{{ now().isoformat() }}'
|
|
var: '{% from ''032-hems.jinja'' import globalVariables %} {{ globalVariables()|from_json
|
|
}}'
|
|
solar_noon_time_today: '{{ state_attr(var.solar_noon_time, ''today'')|as_datetime|as_local
|
|
}}'
|
|
prediction_end_time_today: '{{ state_attr(var.prediction_end_time, ''today'')|as_datetime|as_local
|
|
}}'
|
|
prediction_end_time_tomorrow: '{{ state_attr(var.prediction_end_time, ''tomorrow'')|as_datetime|as_local
|
|
}}'
|
|
prediction_horizon: '{{ ((prediction_end_time_tomorrow|as_timestamp - now()|as_timestamp)/60/30)|int(0)
|
|
+ 1 }}'
|
|
pv_excess_start_time_today: '{{ state_attr(var.pv_excess_start_time, ''today'')|as_datetime|as_local
|
|
}}'
|
|
pv_excess_end_time_today: '{{ state_attr(var.pv_excess_end_time, ''today'')|as_datetime|as_local
|
|
}}'
|
|
house_power_forecast: '{{ state_attr(var.house_power_forecast, ''forecasts'')
|
|
}}'
|
|
solcast: '{% from ''032-emhass.jinja'' import convertDate %} {{ convertDate(state_attr(var.solcast_forecast_today,
|
|
''detailedForecast''), ''period_start'')|from_json }}
|
|
|
|
'
|
|
sensor:
|
|
- name: emhass_prediction_horizon
|
|
unique_id: emhass_prediction_horizon
|
|
state: '{{ prediction_horizon }}'
|
|
attributes:
|
|
prediction_end_time_today: '{{ prediction_end_time_today }}'
|
|
prediction_end_time_tomorrow: '{{ prediction_end_time_tomorrow }}'
|
|
prediction_time_step: 30
|
|
last_updated: '{{ t }}'
|
|
- name: load_forecast_remaining_today_every_minute
|
|
unique_id: load_forecast_remaining_today_every_minute
|
|
state_class: total
|
|
device_class: energy
|
|
unit_of_measurement: kWh
|
|
icon: mdi:home-lightning-bolt-outline
|
|
state: '{%- set ts_end_time = ((as_timestamp(today_at("00:00:00") + timedelta(
|
|
days = 1))/1800)|round(0,''floor'')|int * 1800) %}
|
|
|
|
{% from ''032-emhass.jinja'' import forecastPeriod %} {{ forecastPeriod(house_power_forecast,
|
|
''date'', ''p_load_forecast'', 1000, ts_end_time)|float(0) }}'
|
|
attributes:
|
|
solar_noon_time: '{{ solar_noon_time_today }}'
|
|
solar_noon_energy: '{%- set ts_end_time = solar_noon_time_today|as_timestamp
|
|
%}
|
|
|
|
{% from ''032-emhass.jinja'' import forecastPeriod %} {{ forecastPeriod(house_power_forecast,
|
|
''date'', ''p_load_forecast'', 1000, ts_end_time)|float(0) }}'
|
|
prediction_end_time: '{{ prediction_end_time_today }}'
|
|
prediction_end_energy: '{%- set ts_end_time = prediction_end_time_today|as_timestamp
|
|
%}
|
|
|
|
{% from ''032-emhass.jinja'' import forecastPeriod %} {{ forecastPeriod(house_power_forecast,
|
|
''date'', ''p_load_forecast'', 1000, ts_end_time)|float(0) }}'
|
|
pv_excess_start_time: '{{ pv_excess_start_time_today }}'
|
|
pv_excess_start_energy: '{%- set ts_end_time = pv_excess_start_time_today|as_timestamp
|
|
%}
|
|
|
|
{% from ''032-emhass.jinja'' import forecastPeriod %} {{ forecastPeriod(house_power_forecast,
|
|
''date'', ''p_load_forecast'', 1000, ts_end_time)|float(0) }}'
|
|
pv_excess_end_time: '{{ pv_excess_end_time_today }}'
|
|
pv_excess_end_energy: '{%- set ts_end_time = pv_excess_end_time_today|as_timestamp
|
|
%}
|
|
|
|
{% from ''032-emhass.jinja'' import forecastPeriod %} {{ forecastPeriod(house_power_forecast,
|
|
''date'', ''p_load_forecast'', 1000, ts_end_time)|float(0) }}'
|
|
last_updated: '{{ t }}'
|
|
- name: solcast_forecast_remaining_today_every_minute
|
|
unique_id: solcast_forecast_remaining_today_every_minute
|
|
state_class: total
|
|
device_class: energy
|
|
unit_of_measurement: kWh
|
|
icon: mdi:solar-power
|
|
state: '{%- set ts_end_time = ((as_timestamp(today_at("00:00:00") + timedelta(
|
|
days = 1))/1800)|round(0,''floor'')|int * 1800) %} {% from ''032-emhass.jinja''
|
|
import forecastPeriod %} {{ forecastPeriod(solcast, ''period_start'', ''pv_estimate'',
|
|
1, ts_end_time)|float(0) }}'
|
|
attributes:
|
|
solar_noon_time: '{{ solar_noon_time_today }}'
|
|
solar_noon_energy: '{% set ts_end_time = solar_noon_time_today|as_timestamp
|
|
%} {% from ''032-emhass.jinja'' import forecastPeriod %} {{ forecastPeriod(solcast,
|
|
''period_start'', ''pv_estimate'', 1, ts_end_time)|float(0) }}'
|
|
prediction_end_time: '{{ prediction_end_time_today }}'
|
|
prediction_end_energy: '{% set ts_end_time = prediction_end_time_today|as_timestamp
|
|
%} {% from ''032-emhass.jinja'' import forecastPeriod %} {{ forecastPeriod(solcast,
|
|
''period_start'', ''pv_estimate'', 1, ts_end_time)|float(0) }}'
|
|
pv_excess_start_time: '{{ pv_excess_start_time_today }}'
|
|
pv_excess_start_energy: '{% set ts_end_time = pv_excess_start_time_today|as_timestamp
|
|
%} {% from ''032-emhass.jinja'' import forecastPeriod %} {{ forecastPeriod(solcast,
|
|
''period_start'', ''pv_estimate'', 1, ts_end_time)|float(0) }}'
|
|
pv_excess_end_time: '{{ pv_excess_end_time_today }}'
|
|
pv_excess_end_energy: '{% set ts_end_time = pv_excess_end_time_today|as_timestamp
|
|
%} {% from ''032-emhass.jinja'' import forecastPeriod %} {{ forecastPeriod(solcast,
|
|
''period_start'', ''pv_estimate'', 1, ts_end_time)|float(0) }}'
|
|
last_updated: '{{ now() }}'
|
|
- trigger:
|
|
- platform: time_pattern
|
|
minutes: /1
|
|
action:
|
|
- variables:
|
|
t: '{{ now().isoformat() }}'
|
|
var: '{% from ''032-hems.jinja'' import globalVariables %} {{ globalVariables()|from_json
|
|
}}'
|
|
epexspot_net_price: '{{ states(var.epexspot_net_price)|float(0) / 100 }}'
|
|
net_price: '{% from ''032-emhass.jinja'' import forecastEPEXSpot %} {{ forecastEPEXSpot(state_attr(var.epexspot_net_price,
|
|
''data''))|from_json }}'
|
|
ts_start_time: '{{ (now().replace(second=0).replace(microsecond=0) - timedelta(minutes=(now().minute)))|as_timestamp
|
|
}}'
|
|
stat: '{% from ''032-emhass.jinja'' import priceStatistics %} {{ priceStatistics(net_price,
|
|
''start_time'', ''price_ct_per_kwh'', ts_start_time)|from_json }}'
|
|
solcast: '{% from ''032-emhass.jinja'' import convertDate %} {%- set today
|
|
= convertDate(state_attr(var.solcast_forecast_today, ''detailedForecast''),
|
|
''period_start'')|from_json %} {%- set tomorrow = convertDate(state_attr(var.solcast_forecast_tomorrow,
|
|
''detailedForecast''), ''period_start'')|from_json %} {{ today + tomorrow
|
|
}}'
|
|
sensor:
|
|
- name: emhass_forecast_data
|
|
unique_id: emhass_forecast_data
|
|
state_class: measurement
|
|
unit_of_measurement: EUR/kWh
|
|
icon: mdi:eye
|
|
state: '{{ epexspot_net_price|round(5) }}'
|
|
attributes:
|
|
data: "{%- set var = namespace(result = []) %}\n{# Construct new array putting\
|
|
\ everthing together #} {%- for record in net_price if record.start_time|as_timestamp\
|
|
\ >= ts_start_time %}\n {# Split into 30 min interval #}\n {# Solar Forecast\
|
|
\ is already in in 30 min interval #}\n\n {# - 1. half hour #}\n {# -\
|
|
\ if clause is only necessary for the first iteration to deceide starting\
|
|
\ the var.result array with 0 or 30 min interval #}\n {% if record.start_time|as_timestamp\
|
|
\ >= (t|as_timestamp - 1800) %}\n {%- set end_time = (record.end_time|as_timestamp\
|
|
\ - 1800)|timestamp_local %}\n\n {% from '032-emhass.jinja' import forecastArray\
|
|
\ %}\n {%- set var.result = forecastArray(var.result, solcast, record.start_time,\
|
|
\ end_time, record.price_ct_per_kwh)|from_json %}\n {% endif %}\n\n {#\
|
|
\ - 2. half hour #}\n {%- set start_time = (record.start_time|as_timestamp\
|
|
\ + 1800)|timestamp_local %}\n\n {% from '032-emhass.jinja' import forecastArray\
|
|
\ %}\n {%- set var.result = forecastArray(var.result, solcast, start_time,\
|
|
\ record.end_time, record.price_ct_per_kwh)|from_json %}\n{%- endfor %}\
|
|
\ {{ var.result }}"
|
|
epexspot_max_price: '{{ stat.max_price|round(5) }}'
|
|
epexspot_min_price: '{{ stat.min_price|round(5) }}'
|
|
epexspot_avg_price: '{{ stat.avg_price|round(5) }}'
|
|
epexspot_price_range: '{{ stat.price_range|round(5) }}'
|
|
last_updated: '{{ t }}'
|
|
input_number:
|
|
batteries_soc_setpoint_low:
|
|
name: batteries_soc_setpoint_low
|
|
min: 0
|
|
max: 100
|
|
step: 1
|
|
unit_of_measurement: '%'
|
|
mode: box
|
|
batteries_soc_setpoint_neutral:
|
|
name: batteries_soc_setpoint_neutral
|
|
min: 0
|
|
max: 100
|
|
step: 1
|
|
unit_of_measurement: '%'
|
|
mode: box
|
|
batteries_soc_setpoint_high:
|
|
name: batteries_soc_setpoint_high
|
|
min: 0
|
|
max: 100
|
|
step: 1
|
|
unit_of_measurement: '%'
|
|
mode: box
|
|
batteries_soc_setpoint_forcible_charge:
|
|
name: batteries_soc_setpoint_forcible_charge
|
|
min: 0
|
|
max: 100
|
|
step: 1
|
|
unit_of_measurement: '%'
|
|
mode: box
|
|
epexspot_quantile_setpoint_low:
|
|
name: epexspot_quantile_setpoint_low
|
|
min: 0
|
|
max: 1
|
|
step: 0.01
|
|
mode: box
|
|
epexspot_quantile_setpoint_neutral:
|
|
name: epexspot_quantile_setpoint_neutral
|
|
min: 0
|
|
max: 1
|
|
step: 0.01
|
|
mode: box
|
|
epexspot_quantile_setpoint_high:
|
|
name: epexspot_quantile_setpoint_high
|
|
min: 0
|
|
max: 1
|
|
step: 0.01
|
|
mode: box
|
|
rest_command:
|
|
emhass_publish_data:
|
|
url: http://localhost:5000/action/publish-data
|
|
method: POST
|
|
content_type: application/json
|
|
timeout: 30
|
|
payload: '{}'
|
|
emhass_perfect_optim:
|
|
url: http://localhost:5000/action/perfect-optim
|
|
method: POST
|
|
content_type: application/json
|
|
timeout: 30
|
|
payload: '{}'
|
|
emhass_dayahead_optim_forecast:
|
|
url: http://localhost:5000/action/dayahead-optim
|
|
method: POST
|
|
content_type: application/json
|
|
timeout: 30
|
|
payload: "{% set prediction_horizon = states('sensor.emhass_prediction_horizon')|int(0)\
|
|
\ %} {\n \"pv_power_forecast\": {{\n ([states('sensor.inverter_input_power')|float(0)]\
|
|
\ +\n (state_attr('sensor.emhass_forecast_data', 'data')|map(attribute='p_pv_forecast')|list)[1:48]\n\
|
|
\ )| tojson\n }},\n \"load_cost_forecast\": {{\n ([states('sensor.epex_spot_data_net_price')|float(0)|round(2)/100]\
|
|
\ +\n (state_attr('sensor.emhass_forecast_data', 'data')|map(attribute='epexspot_price_eur_per_kwh')|list)[1:48]\
|
|
\ \n )| tojson \n }},\n \"prediction_horizon\": {{prediction_horizon}},\n\
|
|
\ \"soc_init\": {{states('sensor.batteries_state_of_capacity')|float(0)/100}},\n\
|
|
\ \"soc_final\": 1.0,\n \"def_total_hours\": [0,0],\n \"alpha\": 1,\n \
|
|
\ \"beta\": 0\n}"
|
|
emhass_naive_mpc_optim_forecast:
|
|
url: http://localhost:5000/action/naive-mpc-optim
|
|
method: POST
|
|
content_type: application/json
|
|
timeout: 30
|
|
payload: "{% set prediction_horizon = states('sensor.emhass_prediction_horizon')|int(0)\
|
|
\ %} {\n \"pv_power_forecast\": {{\n ([states('sensor.inverter_input_power')|float(0)]\
|
|
\ +\n (state_attr('sensor.emhass_forecast_data', 'data')|map(attribute='p_pv_forecast')|list)[1:-1]\n\
|
|
\ )|tojson\n }},\n \"load_cost_forecast\": {{\n ([states('sensor.epex_spot_data_net_price')|float(0)|round(2)/100]\
|
|
\ +\n (state_attr('sensor.emhass_forecast_data', 'data')|map(attribute='epexspot_price_eur_per_kwh')|list)[1:-1]\
|
|
\ \n )|tojson \n }},\n \"prediction_horizon\": {{prediction_horizon}},\n\
|
|
\ \"soc_init\": {{states('sensor.batteries_state_of_capacity')|float(0)/100}},\n\
|
|
\ \"soc_final\": 1.0,\n \"def_total_hours\": [0,0],\n \"alpha\": 1,\n \
|
|
\ \"beta\": 0,\n \"continual_publish\":false\n}"
|
|
emhass_ml_load_forecast_model_fit:
|
|
url: http://localhost:5000/action/forecast-model-fit
|
|
method: POST
|
|
content_type: application/json
|
|
timeout: 30
|
|
payload: "{\n \"days_to_retrieve\": 7,\n \"model_type\":\"load_forecast\"\
|
|
,\n \"var_model\":\"sensor.house_consumption_power\",\n \"num_lags\": 96,\n\
|
|
\ \"split_date_delta\": \"48h\",\n \"perform_backtest\": true\n}"
|
|
emhass_ml_load_forecast_model_predict:
|
|
url: http://localhost:5000/action/forecast-model-predict
|
|
method: POST
|
|
content_type: application/json
|
|
timeout: 30
|
|
payload: "{\n \"model_predict_publish\": true,\n \"model_predict_entity_id\"\
|
|
: \"sensor.p_load_forecast\",\n \"model_predict_unit_of_measurement\": \"\
|
|
W\",\n}"
|
|
emhass_ml_load_forecast_model_tune:
|
|
url: http://localhost:5000/action/forecast-model-tune
|
|
method: POST
|
|
content_type: application/json
|
|
timeout: 30
|
|
payload: "{\n \"var_model\":\"sensor.house_consumption_power\"\n}"
|
|
- automation epexspot:
|
|
- id: epex_spot_fetch_data
|
|
alias: EPEX Spot - Fetch data
|
|
description: 'EPEX Spot: Fetch data from all services or a specific service.'
|
|
variables:
|
|
state: '{{ states(''binary_sensor.epex_spot_data_update'') }}'
|
|
next_poll_time: '{{ state_attr(''binary_sensor.epex_spot_data_update'', ''next_poll_time'')
|
|
}}'
|
|
triggers:
|
|
- trigger: time_pattern
|
|
minutes: /3
|
|
conditions:
|
|
- condition: template
|
|
value_template: '{{ now() >= next_poll_time|as_datetime|as_local and state ==
|
|
''off'' }}'
|
|
actions:
|
|
- delay:
|
|
seconds: '{{ range(7, 67)|random|int }}'
|
|
- data: {}
|
|
action: epex_spot.fetch_data
|
|
mode: single
|
|
template:
|
|
- trigger:
|
|
- platform: time_pattern
|
|
minutes: /1
|
|
action:
|
|
- variables:
|
|
var: '{% from ''032-hems.jinja'' import globalVariables %} {{ globalVariables()|from_json
|
|
}}'
|
|
data_update: '{{ states(var.epexspot_data_update) }}'
|
|
last_update: '{{ state_attr(var.epexspot_data_update, ''last_update'') }}'
|
|
next_poll_time: '{{ state_attr(var.epexspot_data_update, ''next_poll_time'')
|
|
}}'
|
|
data: '{{ state_attr(var.epexspot_net_price, ''data'') }}'
|
|
APIUpdate: '{% from ''032-epexspot.jinja'' import APIUpdate %} {{ APIUpdate(data_update,
|
|
last_update, next_poll_time, data)|from_json }}'
|
|
binary_sensor:
|
|
- name: epex_spot_data_update
|
|
unique_id: epex_spot_data_update
|
|
icon: mdi:clock
|
|
state: '{{ APIUpdate.tomorrow_data_available }}'
|
|
attributes:
|
|
last_data: '{{ APIUpdate.last_data }}'
|
|
last_api_update: '{{ APIUpdate.last_update }}'
|
|
next_poll_time: '{{ APIUpdate.next_poll_time }}'
|
|
last_updated: '{{ now().isoformat() }}'
|
|
- trigger:
|
|
- platform: state
|
|
entity_id:
|
|
- sensor.epex_spot_data_price_1
|
|
- sensor.epex_spot_data_price_2
|
|
- sensor.epex_spot_data_price_3
|
|
action:
|
|
- variables:
|
|
var: '{% from ''032-hems.jinja'' import globalVariables %} {{ globalVariables()|from_json
|
|
}}'
|
|
sensor_list: '{{ [var.epexspot_price_1, var.epexspot_price_2, var.epexspot_price_3]
|
|
}}'
|
|
sensor_active: '{% from ''032-epexspot.jinja'' import redundantSensor %} {{
|
|
redundantSensor(sensor_list) }}'
|
|
sensor:
|
|
- name: epex_spot_data_price
|
|
unique_id: epex_spot_data_price
|
|
state_class: measurement
|
|
unit_of_measurement: EUR/MWh
|
|
icon: mdi:currency-eur
|
|
state: '{{ states(sensor_active)|float(0) }}'
|
|
attributes:
|
|
data: '{{ state_attr(sensor_active, ''data'') }}'
|
|
price_ct_per_kwh: '{{ state_attr(sensor_active, ''price_ct_per_kwh'') }}'
|
|
sensor_active: '{{ sensor_active }}'
|
|
last_updated: '{{ now().isoformat() }}'
|
|
- trigger:
|
|
- platform: state
|
|
entity_id:
|
|
- sensor.epex_spot_data_net_price_1
|
|
- sensor.epex_spot_data_net_price_2
|
|
- sensor.epex_spot_data_net_price_3
|
|
action:
|
|
- variables:
|
|
var: '{% from ''032-hems.jinja'' import globalVariables %} {{ globalVariables()|from_json
|
|
}}'
|
|
sensor_list: '{{ [var.epexspot_net_price_1, var.epexspot_net_price_2, var.epexspot_net_price_3]
|
|
}}'
|
|
sensor_active: '{% from ''032-epexspot.jinja'' import redundantSensor %} {{
|
|
redundantSensor(sensor_list) }}'
|
|
sensor:
|
|
- name: epex_spot_data_net_price
|
|
unique_id: epex_spot_data_net_price
|
|
state_class: measurement
|
|
unit_of_measurement: ct/kWh
|
|
icon: mdi:currency-eur
|
|
state: '{{ states(sensor_active)|float(0) }}'
|
|
attributes:
|
|
data: '{{ state_attr(sensor_active, ''data'') }}'
|
|
sensor_active: '{{ sensor_active }}'
|
|
last_updated: '{{ now().isoformat() }}'
|
|
- trigger:
|
|
- platform: state
|
|
entity_id:
|
|
- sensor.epex_spot_data_quantile_1
|
|
- sensor.epex_spot_data_quantile_2
|
|
- sensor.epex_spot_data_quantile_3
|
|
action:
|
|
- variables:
|
|
var: '{% from ''032-hems.jinja'' import globalVariables %} {{ globalVariables()|from_json
|
|
}}'
|
|
sensor_list: '{{ [var.epexspot_quantile_1, var.epexspot_quantile_2, var.epexspot_quantile_3]
|
|
}}'
|
|
sensor_active: '{% from ''032-epexspot.jinja'' import redundantSensor %} {{
|
|
redundantSensor(sensor_list) }}'
|
|
sensor:
|
|
- name: epex_spot_data_quantile
|
|
unique_id: epex_spot_data_quantile
|
|
state_class: measurement
|
|
state: '{{ states(sensor_active)|float(0) }}'
|
|
attributes:
|
|
data: '{{ state_attr(sensor_active, ''data'') }}'
|
|
sensor_active: '{{ sensor_active }}'
|
|
last_updated: '{{ now().isoformat() }}'
|
|
- automation solcast:
|
|
- id: solcast_pv_forecast_api_update
|
|
alias: SolCast PV Forecast - API Update
|
|
description: Update the SolCast PV Forecast data during sunrise and sunset.
|
|
variables:
|
|
next_poll_time: '{{ states(''sensor.solcast_pv_forecast_api_update'') }}'
|
|
triggers:
|
|
- trigger: time_pattern
|
|
minutes: /3
|
|
conditions:
|
|
- condition: template
|
|
value_template: '{{ now() >= next_poll_time|as_datetime|as_local }}'
|
|
actions:
|
|
- delay:
|
|
seconds: '{{ range(7, 67)|random|int }}'
|
|
- data: {}
|
|
action: solcast_solar.update_forecasts
|
|
mode: single
|
|
template:
|
|
- trigger:
|
|
- platform: time_pattern
|
|
minutes: /1
|
|
action:
|
|
- variables:
|
|
t: '{{ now().isoformat() }}'
|
|
var: '{% from ''032-hems.jinja'' import globalVariables %} {{ globalVariables()|from_json
|
|
}}'
|
|
sunrise: '{{ state_attr(var.rising_time,''today'')|as_datetime|as_local }}'
|
|
sunrise_tomorrow: '{{ state_attr(var.rising_time,''tomorrow'')|as_datetime|as_local
|
|
}}'
|
|
sunset: '{{ state_attr(var.setting_time,''today'')|as_datetime|as_local }}'
|
|
last_poll_time: '{{ states(var.solcast_last_poll_time)|as_datetime|as_local
|
|
}}'
|
|
api_request_limit: '{{ states(var.solcast_api_request_limit)|int(0) }}'
|
|
api_request_used: '{{ states(var.solcast_api_request_used)|int(0) }}'
|
|
api_request_free: '{{ (api_request_limit - api_request_used)|int(0) }}'
|
|
next_poll_time: "{% if last_poll_time < sunrise %}\n {{ sunrise }}\n{%\
|
|
\ elif api_request_free >= 1 %}\n {% set ts_difference = (sunset|as_timestamp\
|
|
\ - last_poll_time|as_timestamp)|float(0) %}\n {% set ts_interval = (ts_difference\
|
|
\ / api_request_free)|float(0) %}\n {{ (last_poll_time|as_timestamp +\
|
|
\ ts_interval)|as_datetime|as_local }}\n{% else %}\n {{ sunrise_tomorrow\
|
|
\ }}\n{% endif %}"
|
|
sensor:
|
|
- name: solcast_pv_forecast_api_update
|
|
unique_id: solcast_pv_forecast_api_update
|
|
device_class: timestamp
|
|
state: '{{ next_poll_time }}'
|
|
attributes:
|
|
last_updated: '{{ t }}'
|