Hello! I’m trying to implement the new thermal_battery model for my house with underfloor heating and a heat pump. Figuring out the parameters I need was a bit difficult, but I think I have a good base line to tune once I start using it.
However, there are two things that I can’t really get working. Both have to do with heat pumps preferring longer runs instead of multiple shorter runs.
The first thing is that I can’t get the startup penalty working. For example, I just tested my configuration and I got this forecast:
The run from 2:30 to 5:30 is a great choice considering the prices, but the stop in the middle at 3:30 does not make sense. 3:30 is the most expensive period, but the price difference to the second most expensive period is 0,001 euro. I have configured a startup penalty for this load, which probably would’ve fixed this run, but it seems that that just gets ignored. Is that a bug or by design? If by design, is there any alternative for getting longer runs?
The other thing is that I can’t set the nominal power of my heat pump to the true value. If I set it too high, EMHASS will give me multiple super short runs, instead of one long run. Even though it still has a lot of room before hitting the max temperatures. I have settled on 1000W for now, which gives me reasonable schedules, even though my heat pump can actually ramp up to 2500W if necessary. Is there any way I could fix this?
This behaviour might be fixed by using startup penalties, but from my example above, I think that doesn’t work with thermal_battery.
Is there someone that has a working thermal_battery configuration with reasonable schedules? Are there any tips you could give me for getting this to work?
These are my thermal_battery parameters (thermal_battery config at the bottom):
rest_command:
emhass_npc_optim_with_pv_15m_with_def_heat_pump:
url: http://localhost:5000/action/naive-mpc-optim
method: post
timeout: 300
payload: >
{% set horizon = min(144, state_attr('sensor.entsoe_prices_forecast_30', 'prices_36h_15min') | length | int) %}
{% set charging_on_or_planned = is_state('switch.ev_smart_charging_ev_connected', 'on') and (is_state('sensor.ev_smart_charging_charging', 'on') or is_state_attr('sensor.ev_smart_charging_charging', 'charging_is_planned', true)) %}
{% set charging_load = (state_attr('sensor.ev_smart_charging_charging', 'charging_number_of_hours') | float(0) / 0.25) | int if charging_on_or_planned else 0 %}
{% set charging_on_or_planned_2 = is_state('switch.ev_smart_charging_ev_connected_2', 'on') and (is_state('sensor.ev_smart_charging_charging_2', 'on') or is_state_attr('sensor.ev_smart_charging_charging_2', 'charging_is_planned', true)) %}
{% set charging_load_2 = (state_attr('sensor.ev_smart_charging_charging_2', 'charging_number_of_hours') | float(0) / 0.25) | int if charging_on_or_planned_2 else 0 %}
{% set dhw_load =
6 if is_state('binary_sensor.mitsubishi_next_dhw_run_is_legionella_run', 'on') else
2 if states('sensor.mitsubishi_tank_water_temperature') | float(0) - states('input_number.dhw_temperature_setpoint') | float(0) < -2 else
0 %}
{% set heat_pump_load =
8 if is_state('sensor.mitsubishi_operating_mode', 'Heating') or is_state('sensor.mitsubishi_operating_mode', 'Cooling') else
0 %}
{% set heat_pump_flow_temp = states('number.mitsubishi_h_c_thermostat_target_temperature') | float(25) %}
{
"load_cost_forecast": {{ state_attr('sensor.entsoe_prices_forecast_30', 'prices_36h_15min') | tojson }},
"prod_price_forecast": {{ state_attr('sensor.entsoe_prices_forecast_30', 'prices_36h_15min_return') | tojson }},
{% if state_attr('sensor.solcast_forecast_data', 'forecasts') != [] %}"pv_power_forecast": {{ state_attr('sensor.solcast_24hrs_forecast_15m', 'forecasts')[:horizon] | tojson }},{% endif %}
"prediction_horizon": {{ horizon | tojson }},
"soc_init": {{ (states('sensor.hyper_2000_electric_level') | float(0) / 100) | round(2) | tojson }},
"soc_final": {{ 0.4 if is_state('sensor.season', ['autumn', 'winter']) else 0.6 }},
"operating_timesteps_of_each_deferrable_load": {{ [
charging_load,
charging_load_2,
dhw_load,
heat_pump_load
] | tojson }},
"def_load_config": [
{},
{},
{},
{
"thermal_battery": {
"supply_temperature": {{ heat_pump_flow_temp | tojson }},
"volume": 22.0,
"start_temperature": 21.5,
"min_temperatures": {{ [21.0] * horizon }},
"max_temperatures": {{ [26.0] * horizon }},
"carnot_efficiency": 0.44,
"u_value": 0.33,
"envelope_area": 258.8,
"ventilation_rate": 0.5,
"heated_volume": 380.7,
"window_area": 22.8,
"shgc": 0.5,
"internal_gains_factor": 0
}
}
]
}
And this is my config (fourth deferrable load is my heat pump):
{
"adjusted_pv_model_max_age": 24,
"adjusted_pv_regression_model": "LassoRegression",
"adjusted_pv_solar_elevation_threshold": 10,
"battery_charge_efficiency": 0.9,
"battery_charge_power_max": 1201,
"battery_discharge_efficiency": 0.89,
"battery_discharge_power_max": 899,
"battery_dynamic_max": 0.9,
"battery_dynamic_min": -0.9,
"battery_maximum_state_of_charge": 1,
"battery_minimum_state_of_charge": 0.2,
"battery_nominal_energy_capacity": 3840,
"battery_stress_cost": 0,
"battery_stress_segments": 10,
"battery_target_state_of_charge": 0.5,
"compute_curtailment": true,
"continual_publish": false,
"costfun": "profit",
"delta_forecast_daily": 2,
"end_timesteps_of_each_deferrable_load": [
0,
0,
0,
0
],
"historic_days_to_retrieve": 2,
"influxdb_database": "homeassistant",
"influxdb_host": "localhost",
"influxdb_measurement": "W",
"influxdb_port": 8086,
"influxdb_retention_policy": "autogen",
"influxdb_use_ssl": false,
"influxdb_verify_ssl": false,
"inverter_ac_input_max": 1200,
"inverter_ac_output_max": 800,
"inverter_efficiency_ac_dc": 1,
"inverter_efficiency_dc_ac": 1,
"inverter_is_hybrid": false,
"inverter_stress_cost": 0,
"inverter_stress_segments": 10,
"load_cost_forecast_method": "hp_hc_periods",
"load_forecast_method": "naive",
"load_negative": false,
"load_offpeak_hours_cost": 0.1419,
"load_peak_hour_periods": {
"period_hp_1": [
{
"start": "02:54"
},
{
"end": "15:24"
}
],
"period_hp_2": [
{
"start": "17:24"
},
{
"end": "20:24"
}
]
},
"load_peak_hours_cost": 0.1907,
"logging_level": "DEBUG",
"lp_solver_timeout": 45,
"maximum_power_from_grid": 17000,
"maximum_power_to_grid": 17000,
"method_ts_round": "nearest",
"minimum_power_of_deferrable_loads": [
0,
0,
0,
0,
0
],
"model_type": "load_forecast",
"modules_per_string": [
8
],
"nominal_power_of_deferrable_loads": [
11000,
7200,
2500,
1000
],
"num_lags": 48,
"num_threads": 0,
"number_of_deferrable_loads": 4,
"open_meteo_cache_max_age": 30,
"operating_hours_of_each_deferrable_load": [
0,
0,
0,
0
],
"optimization_time_step": 15,
"perform_backtest": false,
"photovoltaic_production_sell_price": 0.1419,
"production_price_forecast_method": "constant",
"pv_inverter_model": [
"GoodWe_Technologies_Co___Ltd___GW5000A_MS__240V_"
],
"pv_module_model": [
"JA_Solar_JAM72S01_375_PR"
],
"sensor_linear_interp": [
"sensor.power_load_no_var_loads_filter"
],
"sensor_power_load_no_var_loads": "sensor.power_load_no_var_loads_filter",
"sensor_power_photovoltaics": "sensor.pv_power",
"sensor_power_photovoltaics_forecast": "sensor.p_pv_forecast",
"sensor_replace_zero": [
"sensor.pv_power"
],
"set_battery_dynamic": false,
"set_deferrable_load_single_constant": [
false,
false,
true,
false
],
"set_deferrable_startup_penalty": [
0,
0,
10,
10
],
"set_nocharge_from_grid": false,
"set_nodischarge_to_grid": false,
"set_total_pv_sell": false,
"set_use_adjusted_pv": false,
"set_use_battery": true,
"set_use_pv": true,
"set_zero_min": true,
"sklearn_model": "KNeighborsRegressor",
"split_date_delta": "48h",
"ssl_no_verify": false,
"start_timesteps_of_each_deferrable_load": [
0,
0,
0,
0
],
"strings_per_inverter": [
2
],
"surface_azimuth": [
169
],
"surface_tilt": [
40
],
"treat_deferrable_load_as_semi_cont": [
false,
false,
true,
false
],
"use_influxdb": false,
"use_websocket": true,
"var_model": "sensor.power_load_no_var_loads",
"weather_forecast_method": "open-meteo",
"weight_battery_charge": 0,
"weight_battery_discharge": 0.05
}
Thanks!