EMHASS: An Energy Management for Home Assistant

That was my understanding also

Do you run this as an separate rest command?

This how I did it, not sure if the second rest command is really necessary:

  emhass_mpc_optim_30min_fi_fo_buffer_mpc_prefix_dynamic_deferrable_loads_state_weight_battery_thermal_load:
    url: "http://localhost:5000/action/naive-mpc-optim"
    method: POST
    timeout: 15
    content_type: "application/json"
    payload: >-
      {
       "entity_save": "{{ entity_save }}",
       "publish_prefix": "{{ publish_prefix }}",
       "prediction_horizon": {{ prediction_horizon }},
       "pv_power_forecast": {{ pv_power_forecast | tojson }},
       "num_def_loads": {{ num_def_loads }},
       "nominal_power_of_deferrable_loads": {{ nominal_power_of_deferrable_loads | tojson }},
       "operating_hours_of_each_deferrable_load": {{ operating_hours_of_each_deferrable_load | tojson }},
       "treat_deferrable_load_as_semi_cont": {{ treat_deferrable_load_as_semi_cont | tojson }},
       "set_deferrable_load_single_constant": {{ set_deferrable_load_single_constant | tojson }},
       "start_timesteps_of_each_deferrable_load": {{ start_timesteps_of_each_deferrable_load | tojson }},
       "end_timesteps_of_each_deferrable_load": {{ end_timesteps_of_each_deferrable_load | tojson }},
       "def_current_state": {{ def_current_state | tojson }},
       "soc_init": {{ soc_init }},
       "soc_final": {{ soc_final }},
       "load_cost_forecast": {{ load_cost_forecast | tojson }},
       "prod_price_forecast": {{ prod_price_forecast | tojson }},
       "alpha": {{ alpha }},
       "beta": {{ beta }},
       "load_power_forecast": {{ load_power_forecast | tojson }},
       "weight_battery_charge": {{ weight_battery_charge | tojson }},
       "weight_battery_discharge": {{ weight_battery_discharge | tojson }},
       "def_load_config": {{ def_load_config | tojson }},
       "outdoor_temperature_forecast": {{ outdoor_temperature_forecast | tojson }}
      }
      
  emhass_publish_data_thermal_load:
    url: http://localhost:5000/action/publish-data
    method: POST
    content_type: 'application/json'
    payload: >-
      {"publish_prefix": {{ '"' ~ publish_prefix ~ '"' }},
       "def_load_config": {{ def_load_config | tojson }}      
      }

Here is my full rest command and payload script, there is a lot here to unpack:

My 7 loads are as follows:

load0 is pool filter pump (440 W)
load1 is pool heat pump (5 kW) - thermal load (heating)
load2 is EV1 charger (11 kW) variable
load3 is HVAC (11 kW) - thermal load (cooling)
load4 is Hot Water Heat Pump (600 W) - thermal load (heating)
load5 is EV2 charger (11 kW) variable
load6 is heater (660W) - fixed

sequence:
  - action: rest_command.mpc_servicecall_rest
    metadata: {}
    data:
      payload: |
        {{ payload}}
    enabled: true
  - action: rest_command.publish_data_rest
    enabled: true
    data: {}
alias: EMHASS Payload Script (Thermal)
variables:
  payload: |-
    {
      {% set count = state_attr('sensor.amber_30min_forecasts_feed_in_price','Forecasts')| selectattr('advanced_price_predicted','is_number') |list|count -%}
      {% set countML = state_attr('sensor.price_forecast_custom_model','scheduled_forecast')|list|count -%}
      {% set horizon = min(146,countML) -%}
      
      "prediction_horizon": {{horizon}},

      "prod_price_forecast": {{
        (
        [states('sensor.amber_5min_current_feed_in_price')|float(0)] 
        + (state_attr('sensor.amber_30min_forecasts_feed_in_price','Forecasts')
                    | selectattr('advanced_price_predicted','is_number')
                    | map(attribute='advanced_price_predicted')
                    | map('multiply', -1)
                    |list)
        + (state_attr('sensor.price_forecast_custom_model','scheduled_forecast')
           | map(attribute='price_forecast_custom_model')
           | map('float')|list)[count+1:]
        )        
      }}, 
      "load_cost_forecast": {{
        ([states('sensor.amber_5min_current_general_price')|float(0)]
        + (state_attr('sensor.amber_30min_forecasts_general_price','Forecasts')
                    | selectattr('advanced_price_predicted','is_number')
                    | map(attribute='advanced_price_predicted')
                    |list)
        + (state_attr('sensor.cost_forecast_custom_model','scheduled_forecast')
           | map(attribute='cost_forecast_custom_model')
           | map('float')|list)[count+1:]       
        )
      }},      
        "def_load_config": [{}, 
          {
          
          {%- if is_state('automation.p_deferable1_automation','on') -%}
          "thermal_config": 
            { "heating_rate": 2.0, 
              "sense": "heat",
              "cooling_constant": 0.007, 
              "overshoot_temperature": 33.0, 
              "start_temperature": {{states('sensor.ibs_th2_p01b_08ae_temperature')|float(0)}}, 

              {%- set set = states('sensor.emhass_sun_next_setting_timesteps')|int -%}
              {%- set total_blocks = horizon -%}
              {%- set max_heating_blocks = 6 -%}

              {# Calculate if heating is possible today #}
              {%- set heating_today = max(0, min(max_heating_blocks, set - 6)) -%}
              {%- set first_start = set - 9 -%}

              {# For second day, always schedule 6 blocks #}
              {%- set heating_tomorrow = max_heating_blocks -%}
              {%- set second_start = first_start + 48 -%}

              {# Calculate fill blocks #}
              {%- set before_first = max(0, first_start) -%}
              {%- set between = max(0, second_start - (first_start + heating_today)) -%}
              {%- set remaining = max(0, total_blocks - (second_start + heating_tomorrow)) -%}

              {%- set temps = 
                    [20]*before_first + 
                    [30]*heating_today + 
                    [24]*between + 
                    [30]*heating_tomorrow + 
                    [24]*remaining +
                    [30]*heating_tomorrow + 
                    [24]*remaining                    
              -%}

              "desired_temperatures": {{ (temps)[:horizon] }}

            }
            {%- endif -%}
          },
          {}, 
          {
          {%- if is_state('automation.p_deferrable3_hvac_v2','on') -%}
          "thermal_config": 
            { "heating_rate": -3.0, 
              "sense": "cool",
              "cooling_constant": 0.2, 
              "overshoot_temperature": 20.0, 
              "start_temperature": {{states('sensor.tewantin_temp')|float(0)}}, 
              "desired_temperatures": {{[states('input_number.emhass_deferrable3_set_point')|int(0)]*horizon}}
            }
            {%- endif -%}    
          }, 
          {
          "thermal_config": 
            { "heating_rate": 6.0, 
              "sense": "heat",
              "cooling_constant": 0.007, 
              "overshoot_temperature": 65.0, 
              "start_temperature": {{states('sensor.hws_power_based_sensor')|float(0)}}, 
              
              {%- set set = states('sensor.emhass_sun_next_setting_timesteps')|int -%}
              {%- set total_blocks = horizon -%}
              {%- set max_heating_blocks = 10 -%}

              {# Calculate if heating is possible today #}
              {%- set heating_today = max(0, min(max_heating_blocks, set - 10)) -%}
              {%- set first_start = set - 12 -%}

              {# For second day, always schedule 6 blocks #}
              {%- set heating_tomorrow = max_heating_blocks -%}
              {%- set second_start = first_start + 48 -%}

              {# Calculate fill blocks #}
              {%- set before_first = max(0, first_start) -%}
              {%- set between = max(0, second_start - (first_start + heating_today)) -%}
              {%- set remaining = max(0, total_blocks - (second_start + heating_tomorrow)) -%}

              {%- set temps = 
                    [50]*before_first + 
                    [60]*heating_today + 
                    [50]*between + 
                    [60]*heating_tomorrow + 
                    [50]*remaining +
                    [60]*heating_tomorrow + 
                    [50]*remaining                    
              -%}

              "desired_temperatures": {{ (temps)[:horizon] }}
            }
          }, 
          {}, 
          {}],
        "outdoor_temperature_forecast": {{state_attr('sensor.outdoor_temperature_forecast','forecasts')[:horizon]}}, 
        



      "alpha": 0,
      "beta": 1,
      "num_def_loads": 7,
      "def_total_hours": {{[states('sensor.def_total_hours_pool_filter')|int(0),
                              states('sensor.def_total_hours_pool_heatpump')|int(0),
                              states('sensor.def_total_hours_ev')|int(0),
                              states('sensor.def_total_hours_hvac')|int(0),
                              states('sensor.def_total_hours_hws')|int(0),
                              states('sensor.def_total_hours_ev2')|int(0),
                              40]}},
      "def_current_state": {{[
                        iif(states('sensor.p_deferrable0')|int(0),1,0),
                        iif(states('sensor.p_deferrable1')|int(0),1,0),
                        iif(states('sensor.p_deferrable2')|int(0),1,0),
                        iif(states('sensor.p_deferrable3')|int(0),1,0),
                        iif(states('sensor.p_deferrable4')|int(0),1,0),
                        iif(states('sensor.p_deferrable5')|int(0),1,0),
                        iif(states('sensor.p_deferrable6')|int(0),1,0)
                      ]}},    
       "def_start_timestep": {{
          [0, 
          0, 
          max(0,states('sensor.emhass_deferrable2_start_timesteps')|int(0)), 
          0, 
          0, 
          max(0,states('sensor.emhass_deferrable5_start_timesteps')|int(0)),
          0]
          }},                      
       "def_end_timestep": {{
          [0, 
          0, 
          max(0,states('sensor.emhass_deferrable2_end_timeslots')|int(0)), 
          0, 
          0, 
          max(0,states('sensor.emhass_p_deferable_5_end_timeslots')|int(0)),
          0]
          }},
      "P_deferrable_nom":  [440,
                             5500, 
                            {{ states('sensor.p_nom_ev')}}, 
                           {{ states('input_number.p_nom_hvac')}}, 
                            600, 
                            {{ states('sensor.p_nom_ev2')}},
                            660],
      "treat_def_as_semi_cont": [1, 1, 0, 0, 1, 0, 1],
      "set_def_constant": [0, 0, 0, 0, 0, 0, 0],
      "def_start_penalty": [1, 0, 1, 1, 1, 1, 0],
      "weight_battery_charge": {{states('input_number.weight_battery_charge')}},
      "weight_battery_discharge": {{states('input_number.weight_battery_discharge')}},
      "battery_nominal_energy_capacity": {{ states('input_number.battery_nominal_energy_capacity')|int(0)*1000 }},
      "battery_discharge_power_max": {{ states('input_number.battery_discharge_power_max')|int(0)*1000}},
      "soc_final": {{states('input_number.soc_final')|int(0)/100}},
      "weather_forecast_cache_only": true,
      "optimization_time_step": 30,
      "set_nodischarge_to_grid": 0,

      "soc_init": 
          {% set primary = states('sensor.gateway_teslemetry_percentage_charged') %}
          {% set fallback = states('sensor.powerwall_charge') %}
          {% if primary not in ['unavailable', 'unknown'] %}
            {{ (primary | float/100) | round(2) }}
          {% elif fallback not in ['unavailable', 'unknown'] %}
            {{ (fallback | float /100) | round (2)}}
          {% else %}
            0
          {% endif %}
    }
mode: single
description: ""
2 Likes

Hi there, I am pretty new to Home Assistant and EMHASS as well. I have been using a commercial EMS for some years (energybase here in Germany) which is no longer supported.
I decided to give EMHASS a try and it looks very promising.
For now I am just trying to push the battery load to PV peak hours.
I’ve set up a defferabl load with 0 hours and configured battery as well as a inverter close to mine.
So inverter AC limit is 10KW, battery charge/discharg is around 10KW, battery capacity is 7.7KWh. Battery should be a 5% SOC at end of the forecast window (using day-ahead).
I configured the battery load as 7700 Wh in EMHASS.
Running the optimization gives me this:


Looks like the battery capacity is wrong.
Setting it to 77000Wh in EMHASS it looks more reasonable.

Am I doing something wrong?

I was thinking here, isn’t it possible to attach a temperature sensor to your DHW outlet from the waterpumpboiler? Or maybe your approach is good enough already.

I would check if all P parameters are in W and Wh and take it from there.

Thanks, this is my config:

"adjusted_pv_regression_model": "LassoRegression",
  "adjusted_pv_solar_elevation_threshold": 10,
  "battery_charge_efficiency": 0.98,
  "battery_charge_power_max": 10000,
  "battery_discharge_efficiency": 0.98,
  "battery_discharge_power_max": 10000,
  "battery_dynamic_max": 0.9,
  "battery_dynamic_min": -0.9,
  "battery_maximum_state_of_charge": 0.1,
  "battery_minimum_state_of_charge": 0,
  "battery_nominal_energy_capacity": 7700,
  "battery_target_state_of_charge": 0.05,
  "compute_curtailment": false,
  "continual_publish": false,
  "costfun": "self-consumption",
  "delta_forecast_daily": 1,
  "end_timesteps_of_each_deferrable_load": [
    0

Should be fine I guess.

Checking the optimization forecast re battery discharge, I am getting this:

|index|P_PV|P_Load|P_deferrable0|P_grid_pos|P_grid_neg|P_grid|P_batt|SOC_opt|

|2025-06-05 22:30:00+02:00|0|196|0|0|0|0|196|0.087|
|2025-06-06 02:00:00+02:00|0|281|0|0|0|0|281|0.068|
|2025-06-06 04:30:00+02:00|0|342|0|0|0|0|342|0.046|
|2025-06-06 05:30:00+02:00|0|366|0|0|0|0|366|0.021|
|2025-06-06 06:30:00+02:00|86|390|0|0|0|0|304|0.001|



So from 100 to 1% it is around 700Wh only.
And charging from 72% to 100%
index P_PV P_Load P_deferrable0 P_grid_pos P_grid_neg P_grid P_batt SOC_opt
2025-06-05 18:30:00+02:00 786 327 0 0 -113 -113 -346 0.072
2025-06-05 19:00:00+02:00 760 321 0 0 0 0 -439 0.100

That’s around 200Wh.


Edit, uhm. Problem between screen and chair.
Maximum should be 1 and not 0.1 :-(
Problem solved

Good to hear.

But what about the internal control of your DHW heat pump? You leave the setpoint always at 50 degrees celsius, so no time program.

I am currently working towards this, my shelly relay (which provides the SG ready signal) also has an input for a temperature sensor, so I will attach that to the hot water supply at the top which will enable the optimisation to be more accurate.

Unfortunately my DHW system doesn’t have a timer program.

The set point is 50 deg C normally and 65 deg C when the dry contact (SG ready) signal is set.

1 Like

Hi Mark,

I am working on the Hot water heat pump.

Looking at you setup, start and end timesteps for your def_4 are both 0. EMHASS looks what’s the best window for closing the PV contact on your hot water pump. I tried the same with these results (with 10 heating blocks)

Next I tried set start and end timestep to match the 60 degrees desired temp with these results:

Isn’t this what you are after? I am trying to understand what’s the best way to implement this. For the last optimization I had to lower the heating_rate from 6 to 5, but I don’t know the real value I need. I don’t have the hot waterpump yet. Just simulating and understanding the way the model works.

Can you explain a little more why you choose option 1?

Is you switch on debug you will see which loads are characterised as thermal or non-thermal loads.

I try not to constrain the solution with start/ end timesteps and just allow the optimization based on thermal performance.

In your example 1, the water heater switches on ‘early’ for two reasons:

  1. At the start it is below the desired 50 deg C, so it needs to start heating immediately. (13:00-)
  2. It is also attempting to get to the desired temp of 60 Dec C by 16:00, so it needs to run flat out and doesn’t quite get there.

You can also see it switches off early 18:30 as it has achieved the setpoint > 60 deg C.

In your example 2 your timestep constraints have it not achieving the 50 deg setpoint specified before 15:30 and it doesn’t achieve the required pre-heat to achieve 60 deg C specified for 15:30.

Got it! That makes sense.

A pratical question, for normal deferrable loads I use a countdown timer for the operating hours which decreases every hour by 1 until the def has finished. I feed the declining values to the runtime in my rolling window setup.

For the thermal load this doesn’t work, but I think it’s working automatically when temp increases. If at some timestep the desired temp is reached the def is reduced, but for the second start before the evening it is added as we defined 10 heating blocks. Hope I am correct. Or is there something else what I should do?

Hello,
I have EMHASS: v0.13.3 add-on
i’m trying to change Solar System (PV)
I have enphase solar system.1 micro inverter per panel
I found this:


and put it in te config.


But get this error

> Traceback (most recent call last):
>   File "/app/.venv/lib/python3.12/site-packages/pandas/core/indexes/base.py", line 3805, in get_loc
>     return self._engine.get_loc(casted_key)
>            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>   File "index.pyx", line 167, in pandas._libs.index.IndexEngine.get_loc
>   File "index.pyx", line 196, in pandas._libs.index.IndexEngine.get_loc
>   File "pandas/_libs/hashtable_class_helper.pxi", line 7081, in pandas._libs.hashtable.PyObjectHashTable.get_item
>   File "pandas/_libs/hashtable_class_helper.pxi", line 7089, in pandas._libs.hashtable.PyObjectHashTable.get_item
> KeyError: 'REC_Solar_REC365AA'
> The above exception was the direct cause of the following exception:
> Traceback (most recent call last):
>   File "/app/.venv/lib/python3.12/site-packages/flask/app.py", line 1511, in wsgi_app
>     response = self.full_dispatch_request()
>                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>   File "/app/.venv/lib/python3.12/site-packages/flask/app.py", line 919, in full_dispatch_request
>     rv = self.handle_user_exception(e)
>          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>   File "/app/.venv/lib/python3.12/site-packages/flask/app.py", line 917, in full_dispatch_request
>     rv = self.dispatch_request()
>          ^^^^^^^^^^^^^^^^^^^^^^^
>   File "/app/.venv/lib/python3.12/site-packages/flask/app.py", line 902, in dispatch_request
>     return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)  # type: ignore[no-any-return]
>            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>   File "/app/src/emhass/web_server.py", line 411, in action_call
>     input_data_dict = set_input_data_dict(
>                       ^^^^^^^^^^^^^^^^^^^^
>   File "/app/src/emhass/command_line.py", line 287, in set_input_data_dict
>     P_PV_forecast = fcst.get_power_from_weather(df_weather)
>                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>   File "/app/src/emhass/forecast.py", line 749, in get_power_from_weather
>     module = cec_modules[self.plant_conf["pv_module_model"][i]]
>              ~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>   File "/app/.venv/lib/python3.12/site-packages/pandas/core/frame.py", line 4102, in __getitem__
>     indexer = self.columns.get_loc(key)
>               ^^^^^^^^^^^^^^^^^^^^^^^^^
>   File "/app/.venv/lib/python3.12/site-packages/pandas/core/indexes/base.py", line 3812, in get_loc
>     raise KeyError(key) from err
> KeyError: 'REC_Solar_REC365AA

What went wrong?
REC_Solar_REC365AA is in the PVLib database for EMHASS
I have enphase solar system.1micro inverter per panel
Number of strings per inverter is set to 1
Adding in the yaml file is working
+/- (green arrow is not working)


My yaml file

{
  "optimization_time_step": 30,
  "historic_days_to_retrieve": 2,
  "sensor_power_photovoltaics": "sensor.envoy_122023077603_current_power_production",
  "sensor_power_photovoltaics_forecast": "sensor.p_pv_forecast",
  "sensor_power_load_no_var_loads": "sensor.power_load_no_var_loads",
  "load_negative": false,
  "set_zero_min": true,
  "sensor_replace_zero": [
    "sensor.power_photovoltaics",
    "sensor.p_pv_forecast"
  ],
  "sensor_linear_interp": [
    "sensor.power_photovoltaics",
    "sensor.power_load_no_var_loads"
  ],
  "method_ts_round": "nearest",
  "continual_publish": false,
  "costfun": "profit",
  "logging_level": "INFO",
  "set_use_pv": true,
  "set_use_adjusted_pv": false,
  "adjusted_pv_regression_model": "LassoRegression",
  "adjusted_pv_solar_elevation_threshold": 10,
  "set_use_battery": true,
  "number_of_deferrable_loads": 2,
  "nominal_power_of_deferrable_loads": [
    3000,
    750
  ],
  "minimum_power_of_deferrable_loads": [
    0,
    0
  ],
  "operating_hours_of_each_deferrable_load": [
    4,
    5
  ],
  "treat_deferrable_load_as_semi_cont": [
    true,
    true
  ],
  "set_deferrable_load_single_constant": [
    false,
    false
  ],
  "set_deferrable_startup_penalty": [
    0,
    0
  ],
  "delta_forecast_daily": 1,
  "load_forecast_method": "naive",
  "load_cost_forecast_method": "hp_hc_periods",
  "load_peak_hours_cost": 0.1907,
  "load_offpeak_hours_cost": 0.1419,
  "production_price_forecast_method": "constant",
  "photovoltaic_production_sell_price": 0.1419,
  "set_total_pv_sell": false,
  "lp_solver": "default",
  "lp_solver_path": "empty",
  "lp_solver_timeout": 45,
  "num_threads": 0,
  "set_nocharge_from_grid": false,
  "set_nodischarge_to_grid": true,
  "set_battery_dynamic": false,
  "battery_dynamic_max": 0.9,
  "battery_dynamic_min": -0.9,
  "weight_battery_discharge": 0,
  "weight_battery_charge": 0,
  "weather_forecast_method": "open-meteo",
  "open_meteo_cache_max_age": 30,
  "start_timesteps_of_each_deferrable_load": [
    0,
    0
  ],
  "end_timesteps_of_each_deferrable_load": [
    0,
    0
  ],
  "load_peak_hour_periods": {
    "period_hp_1": [
      {
        "start": "02:54"
      },
      {
        "end": "15:24"
      }
    ],
    "period_hp_2": [
      {
        "start": "17:24"
      },
      {
        "end": "20:24"
      }
    ]
  },
  "maximum_power_from_grid": 9000,
  "maximum_power_to_grid": 9000,
  "pv_module_model": [
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M"
  ],
  "pv_inverter_model": [
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_"
  ],
  "surface_tilt": [
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15
  ],
  "surface_azimuth": [
    220,
    220,
    220,
    220,
    220,
    220,
    220,
    220,
    220,
    220,
    220,
    220,
    220,
    220,
    220,
    220,
    220,
    220,
    220,
    220,
    140,
    140,
    140,
    140,
    140,
    140,
    140,
    140,
    140,
    140,
    140,
    140
  ],
  "modules_per_string": [
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1
  ],
  "strings_per_inverter": [
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1
  ],
  "inverter_is_hybrid": false,
  "compute_curtailment": false,
  "battery_discharge_power_max": 1000,
  "battery_charge_power_max": 1000,
  "battery_discharge_efficiency": 0.95,
  "battery_charge_efficiency": 0.95,
  "battery_nominal_energy_capacity": 5000,
  "battery_minimum_state_of_charge": 0.3,
  "battery_maximum_state_of_charge": 0.9,
  "battery_target_state_of_charge": 0.6
}

Hi,

I want to use ‘operating_timesteps_of_each_deferrable_load’ to pass at runtime. I run 30 min optimization, 1h deferrable = 2 timesteps.

The Optimization runs ‘Optimal’ . Looking at the EMHASS graph I get this:

Is this a bug?

[2025-06-15 13:45:02 +0200] [21] [INFO]  >> Obtaining params: 
[2025-06-15 13:45:02 +0200] [21] [INFO] Passed runtime parameters: {'entity_save': 'True', 'publish_prefix': 'mpc_', 'prediction_horizon': 48, 'pv_power_forecast': [3883, 2094, 2024, 1922, 1807, 1664, 1490, 1315, 1179, 1072, 943, 794, 629, 430, 234, 90, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 77, 207, 403, 656, 983, 1432, 1992, 2636, 3253, 3679, 3931, 4011, 3979, 3870, 3435, 2751, 2334, 2246, 2251, 2253, 2197, 2032, 1782, 1468, 1175, 912, 708, 556, 389, 215, 84, 21, 0, 0, 0, 0], 'num_def_loads': 3, 'nominal_power_of_deferrable_loads': [0, 2000, 0], 'operating_timesteps_of_each_deferrable_load': [0, 1, 0], 'treat_deferrable_load_as_semi_cont': [False, False, False], 'set_deferrable_load_single_constant': [True, True, True], 'start_timesteps_of_each_deferrable_load': [-8, -8, 6], 'end_timesteps_of_each_deferrable_load': [12, 14, 14], 'def_current_state': [False, True, False], 'soc_init': 0.6, 'soc_final': 0.23, 'load_cost_forecast': [0.1451, 0.1458, 0.1458, 0.1489, 0.1489, 0.1511, 0.1511, 0.1914, 0.1914, 0.2374, 0.2374, 0.2546, 0.2546, 0.281, 0.281, 0.2965, 0.2965, 0.2931, 0.2931, 0.2676, 0.2676, 0.2959, 0.2959, 0.2677, 0.2677, 0.2519, 0.2519, 0.2421, 0.2421, 0.2363, 0.2363, 0.2537, 0.2537, 0.2702, 0.2702, 0.282, 0.282, 0.292, 0.292, 0.2691, 0.2691, 0.2096, 0.2096, 0.1666, 0.1666, 0.1548, 0.1548, 0.1535], 'prod_price_forecast': [-0.0147, -0.014, -0.014, -0.0111, -0.0111, -0.0091, -0.0091, 0.029, 0.029, 0.0724, 0.0724, 0.0886, 0.0886, 0.1135, 0.1135, 0.1282, 0.1282, 0.125, 0.125, 0.1008, 0.1008, 0.1276, 0.1276, 0.1009, 0.1009, 0.0861, 0.0861, 0.0769, 0.0769, 0.0714, 0.0714, 0.0878, 0.0878, 0.1034, 0.1034, 0.1144, 0.1144, 0.1239, 0.1239, 0.1023, 0.1023, 0.0462, 0.0462, 0.0056, 0.0056, -0.0055, -0.0055, -0.0067], 'alpha': 0.5, 'beta': 0.466, 'load_power_forecast': [555, 700, 800, 800, 600, 200, 600, 500, 500, 3200, 1300, 1000, 700, 800, 700, 900, 500, 400, 300, 400, 400, 300, 600, 500, 500, 400, 500, 0, 600, 700, 300, 600, 500, 500, 600, 500, 600, 200, 400, 400, 200, 400, 300, 400, 200, 800, 1000, 700], 'weight_battery_charge': 0.041, 'weight_battery_discharge': 0.009}
[2025-06-15 13:45:02 +0200] [21] [INFO]  >> Setting input data dict
[2025-06-15 13:45:02 +0200] [21] [INFO] Setting up needed data
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Initialized Optimization with retrieve_hass_conf: {'optimization_time_step': Timedelta('0 days 00:30:00'), 'historic_days_to_retrieve': 10, 'sensor_power_photovoltaics': 'sensor.inverter_ingangsvermogen', 'sensor_power_photovoltaics_forecast': 'sensor.p_pv_forecast', 'sensor_power_load_no_var_loads': 'sensor.power_load_no_var_loads', 'load_negative': False, 'set_zero_min': True, 'sensor_replace_zero': ['sensor.inverter_ingangsvermogen'], 'sensor_linear_interp': ['sensor.inverter_ingangsvermogen', 'sensor.power_load_no_var_loads'], 'method_ts_round': 'first', 'continual_publish': False, 'hass_url': 'http://supervisor/core/api', 'long_lived_token': '4a653cd73437817aa25835895766b233a4f4fb77ce6eaa1ea5ad42337de7bfd955616ee0c9c95b4e2829ff13d5b6cefe51f1801618726893', 'time_zone': <DstTzInfo 'Europe/Brussels' LMT+0:18:00 STD>, 'Latitude': 50.789456233171535, 'Longitude': 5.592577457427979, 'Altitude': 110}
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Optimization configuration: {'costfun': 'self-consumption', 'logging_level': 'INFO', 'set_use_pv': True, 'set_use_adjusted_pv': False, 'adjusted_pv_regression_model': 'LassoRegression', 'adjusted_pv_solar_elevation_threshold': 10, 'set_use_battery': True, 'number_of_deferrable_loads': 3, 'nominal_power_of_deferrable_loads': [0, 2000, 0], 'minimum_power_of_deferrable_loads': [0, 0, 0, 0], 'operating_hours_of_each_deferrable_load': [2, 2, 2, 2], 'treat_deferrable_load_as_semi_cont': [False, False, False], 'set_deferrable_load_single_constant': [True, True, True], 'set_deferrable_startup_penalty': [3, 5, 5, 0], 'delta_forecast_daily': Timedelta('1 days 00:00:00'), 'load_forecast_method': 'list', 'load_cost_forecast_method': 'list', 'load_peak_hours_cost': 0.1907, 'load_offpeak_hours_cost': 0.1419, 'production_price_forecast_method': 'list', 'photovoltaic_production_sell_price': 0.065, 'set_total_pv_sell': False, 'lp_solver': 'COIN_CMD', 'lp_solver_path': '/usr/bin/cbc', 'lp_solver_timeout': 45, 'num_threads': 0, 'set_nocharge_from_grid': False, 'set_nodischarge_to_grid': False, 'set_battery_dynamic': True, 'battery_dynamic_max': 0.85, 'battery_dynamic_min': -0.5, 'weight_battery_discharge': 0.009, 'weight_battery_charge': 0.041, 'weather_forecast_method': 'list', 'open_meteo_cache_max_age': 30, 'start_timesteps_of_each_deferrable_load': [-8, -8, 6], 'end_timesteps_of_each_deferrable_load': [12, 14, 14], 'load_peak_hour_periods': {'period_hp_1': [{'start': '08:00'}, {'end': '17:00'}], 'period_hp_2': [{'start': '08:00'}, {'end': '17:00'}]}, 'operating_timesteps_of_each_deferrable_load': [0, 1, 0], 'def_current_state': [False, True, False]}
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Plant configuration: {'maximum_power_from_grid': 4000, 'maximum_power_to_grid': 6000, 'pv_module_model': ['JA_Solar_JAM72S01_385_PR', 'JA_Solar_JAM72S01_385_PR', 'JA_Solar_JAM72S01_385_PR'], 'pv_inverter_model': ['Huawei_Technologies_Co___Ltd___SUN2000_9KTL_USL0__240V_', 'Huawei_Technologies_Co___Ltd___SUN2000_9KTL_USL0__240V_', 'Huawei_Technologies_Co___Ltd___SUN2000_9KTL_USL0__240V_'], 'surface_tilt': [35, 35, 15], 'surface_azimuth': [90, 270, 180], 'modules_per_string': [6, 6, 13], 'strings_per_inverter': [1, 1, 1], 'inverter_is_hybrid': True, 'compute_curtailment': True, 'battery_discharge_power_max': 5000, 'battery_charge_power_max': 5000, 'battery_discharge_efficiency': 1, 'battery_charge_efficiency': 0.95, 'battery_nominal_energy_capacity': 15000, 'battery_minimum_state_of_charge': 0.12, 'battery_maximum_state_of_charge': 1, 'battery_target_state_of_charge': 0.12}
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Solver configuration: lp_solver=COIN_CMD, lp_solver_path=/usr/bin/cbc
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Number of threads: 2
[2025-06-15 13:45:02 +0200] [21] [INFO] Retrieving weather forecast data using method = list
[2025-06-15 13:45:02 +0200] [21] [DEBUG] get_weather_forecast returning:
                           yhat
ts                             
2025-06-15 13:30:00+02:00  3883
2025-06-15 14:00:00+02:00  2094
2025-06-15 14:30:00+02:00  2024
2025-06-15 15:00:00+02:00  1922
2025-06-15 15:30:00+02:00  1807
2025-06-15 16:00:00+02:00  1664
2025-06-15 16:30:00+02:00  1490
2025-06-15 17:00:00+02:00  1315
2025-06-15 17:30:00+02:00  1179
2025-06-15 18:00:00+02:00  1072
2025-06-15 18:30:00+02:00   943
2025-06-15 19:00:00+02:00   794
2025-06-15 19:30:00+02:00   629
2025-06-15 20:00:00+02:00   430
2025-06-15 20:30:00+02:00   234
2025-06-15 21:00:00+02:00    90
2025-06-15 21:30:00+02:00    22
2025-06-15 22:00:00+02:00     0
2025-06-15 22:30:00+02:00     0
2025-06-15 23:00:00+02:00     0
2025-06-15 23:30:00+02:00     0
2025-06-16 00:00:00+02:00     0
2025-06-16 00:30:00+02:00     0
2025-06-16 01:00:00+02:00     0
2025-06-16 01:30:00+02:00     0
2025-06-16 02:00:00+02:00     0
2025-06-16 02:30:00+02:00     0
2025-06-16 03:00:00+02:00     0
2025-06-16 03:30:00+02:00     0
2025-06-16 04:00:00+02:00     0
2025-06-16 04:30:00+02:00     0
2025-06-16 05:00:00+02:00     0
2025-06-16 05:30:00+02:00    16
2025-06-16 06:00:00+02:00    77
2025-06-16 06:30:00+02:00   207
2025-06-16 07:00:00+02:00   403
2025-06-16 07:30:00+02:00   656
2025-06-16 08:00:00+02:00   983
2025-06-16 08:30:00+02:00  1432
2025-06-16 09:00:00+02:00  1992
2025-06-16 09:30:00+02:00  2636
2025-06-16 10:00:00+02:00  3253
2025-06-16 10:30:00+02:00  3679
2025-06-16 11:00:00+02:00  3931
2025-06-16 11:30:00+02:00  4011
2025-06-16 12:00:00+02:00  3979
2025-06-16 12:30:00+02:00  3870
2025-06-16 13:00:00+02:00  3435
[2025-06-15 13:45:02 +0200] [21] [DEBUG] get_power_from_weather returning:
ts
2025-06-15 13:30:00+02:00    3883
2025-06-15 14:00:00+02:00    2094
2025-06-15 14:30:00+02:00    2024
2025-06-15 15:00:00+02:00    1922
2025-06-15 15:30:00+02:00    1807
2025-06-15 16:00:00+02:00    1664
2025-06-15 16:30:00+02:00    1490
2025-06-15 17:00:00+02:00    1315
2025-06-15 17:30:00+02:00    1179
2025-06-15 18:00:00+02:00    1072
2025-06-15 18:30:00+02:00     943
2025-06-15 19:00:00+02:00     794
2025-06-15 19:30:00+02:00     629
2025-06-15 20:00:00+02:00     430
2025-06-15 20:30:00+02:00     234
2025-06-15 21:00:00+02:00      90
2025-06-15 21:30:00+02:00      22
2025-06-15 22:00:00+02:00       0
2025-06-15 22:30:00+02:00       0
2025-06-15 23:00:00+02:00       0
2025-06-15 23:30:00+02:00       0
2025-06-16 00:00:00+02:00       0
2025-06-16 00:30:00+02:00       0
2025-06-16 01:00:00+02:00       0
2025-06-16 01:30:00+02:00       0
2025-06-16 02:00:00+02:00       0
2025-06-16 02:30:00+02:00       0
2025-06-16 03:00:00+02:00       0
2025-06-16 03:30:00+02:00       0
2025-06-16 04:00:00+02:00       0
2025-06-16 04:30:00+02:00       0
2025-06-16 05:00:00+02:00       0
2025-06-16 05:30:00+02:00      16
2025-06-16 06:00:00+02:00      77
2025-06-16 06:30:00+02:00     207
2025-06-16 07:00:00+02:00     403
2025-06-16 07:30:00+02:00     656
2025-06-16 08:00:00+02:00     983
2025-06-16 08:30:00+02:00    1432
2025-06-16 09:00:00+02:00    1992
2025-06-16 09:30:00+02:00    2636
2025-06-16 10:00:00+02:00    3253
2025-06-16 10:30:00+02:00    3679
2025-06-16 11:00:00+02:00    3931
2025-06-16 11:30:00+02:00    4011
2025-06-16 12:00:00+02:00    3979
2025-06-16 12:30:00+02:00    3870
2025-06-16 13:00:00+02:00    3435
dtype: int64
[2025-06-15 13:45:02 +0200] [21] [DEBUG] get_load_forecast returning:
2025-06-15 13:30:00+02:00     555
2025-06-15 14:00:00+02:00     700
2025-06-15 14:30:00+02:00     800
2025-06-15 15:00:00+02:00     800
2025-06-15 15:30:00+02:00     600
2025-06-15 16:00:00+02:00     200
2025-06-15 16:30:00+02:00     600
2025-06-15 17:00:00+02:00     500
2025-06-15 17:30:00+02:00     500
2025-06-15 18:00:00+02:00    3200
2025-06-15 18:30:00+02:00    1300
2025-06-15 19:00:00+02:00    1000
2025-06-15 19:30:00+02:00     700
2025-06-15 20:00:00+02:00     800
2025-06-15 20:30:00+02:00     700
2025-06-15 21:00:00+02:00     900
2025-06-15 21:30:00+02:00     500
2025-06-15 22:00:00+02:00     400
2025-06-15 22:30:00+02:00     300
2025-06-15 23:00:00+02:00     400
2025-06-15 23:30:00+02:00     400
2025-06-16 00:00:00+02:00     300
2025-06-16 00:30:00+02:00     600
2025-06-16 01:00:00+02:00     500
2025-06-16 01:30:00+02:00     500
2025-06-16 02:00:00+02:00     400
2025-06-16 02:30:00+02:00     500
2025-06-16 03:00:00+02:00       0
2025-06-16 03:30:00+02:00     600
2025-06-16 04:00:00+02:00     700
2025-06-16 04:30:00+02:00     300
2025-06-16 05:00:00+02:00     600
2025-06-16 05:30:00+02:00     500
2025-06-16 06:00:00+02:00     500
2025-06-16 06:30:00+02:00     600
2025-06-16 07:00:00+02:00     500
2025-06-16 07:30:00+02:00     600
2025-06-16 08:00:00+02:00     200
2025-06-16 08:30:00+02:00     400
2025-06-16 09:00:00+02:00     400
2025-06-16 09:30:00+02:00     200
2025-06-16 10:00:00+02:00     400
2025-06-16 10:30:00+02:00     300
2025-06-16 11:00:00+02:00     400
2025-06-16 11:30:00+02:00     200
2025-06-16 12:00:00+02:00     800
2025-06-16 12:30:00+02:00    1000
2025-06-16 13:00:00+02:00     700
Name: yhat, dtype: int64
[2025-06-15 13:45:02 +0200] [21] [INFO]  >> Performing naive MPC optimization...
[2025-06-15 13:45:02 +0200] [21] [INFO] Performing naive MPC optimization
[2025-06-15 13:45:02 +0200] [21] [DEBUG] get_load_cost_forecast returning:
                           P_PV_forecast  P_load_forecast  unit_load_cost
2025-06-15 13:30:00+02:00           3883              555          0.1451
2025-06-15 14:00:00+02:00           2094              700          0.1458
2025-06-15 14:30:00+02:00           2024              800          0.1458
2025-06-15 15:00:00+02:00           1922              800          0.1489
2025-06-15 15:30:00+02:00           1807              600          0.1489
2025-06-15 16:00:00+02:00           1664              200          0.1511
2025-06-15 16:30:00+02:00           1490              600          0.1511
2025-06-15 17:00:00+02:00           1315              500          0.1914
2025-06-15 17:30:00+02:00           1179              500          0.1914
2025-06-15 18:00:00+02:00           1072             3200          0.2374
2025-06-15 18:30:00+02:00            943             1300          0.2374
2025-06-15 19:00:00+02:00            794             1000          0.2546
2025-06-15 19:30:00+02:00            629              700          0.2546
2025-06-15 20:00:00+02:00            430              800          0.2810
2025-06-15 20:30:00+02:00            234              700          0.2810
2025-06-15 21:00:00+02:00             90              900          0.2965
2025-06-15 21:30:00+02:00             22              500          0.2965
2025-06-15 22:00:00+02:00              0              400          0.2931
2025-06-15 22:30:00+02:00              0              300          0.2931
2025-06-15 23:00:00+02:00              0              400          0.2676
2025-06-15 23:30:00+02:00              0              400          0.2676
2025-06-16 00:00:00+02:00              0              300          0.2959
2025-06-16 00:30:00+02:00              0              600          0.2959
2025-06-16 01:00:00+02:00              0              500          0.2677
2025-06-16 01:30:00+02:00              0              500          0.2677
2025-06-16 02:00:00+02:00              0              400          0.2519
2025-06-16 02:30:00+02:00              0              500          0.2519
2025-06-16 03:00:00+02:00              0                0          0.2421
2025-06-16 03:30:00+02:00              0              600          0.2421
2025-06-16 04:00:00+02:00              0              700          0.2363
2025-06-16 04:30:00+02:00              0              300          0.2363
2025-06-16 05:00:00+02:00              0              600          0.2537
2025-06-16 05:30:00+02:00             16              500          0.2537
2025-06-16 06:00:00+02:00             77              500          0.2702
2025-06-16 06:30:00+02:00            207              600          0.2702
2025-06-16 07:00:00+02:00            403              500          0.2820
2025-06-16 07:30:00+02:00            656              600          0.2820
2025-06-16 08:00:00+02:00            983              200          0.2920
2025-06-16 08:30:00+02:00           1432              400          0.2920
2025-06-16 09:00:00+02:00           1992              400          0.2691
2025-06-16 09:30:00+02:00           2636              200          0.2691
2025-06-16 10:00:00+02:00           3253              400          0.2096
2025-06-16 10:30:00+02:00           3679              300          0.2096
2025-06-16 11:00:00+02:00           3931              400          0.1666
2025-06-16 11:30:00+02:00           4011              200          0.1666
2025-06-16 12:00:00+02:00           3979              800          0.1548
2025-06-16 12:30:00+02:00           3870             1000          0.1548
2025-06-16 13:00:00+02:00           3435              700          0.1535
[2025-06-15 13:45:02 +0200] [21] [DEBUG] get_prod_price_forecast returning:
                           P_PV_forecast  ...  unit_prod_price
2025-06-15 13:30:00+02:00           3883  ...          -0.0147
2025-06-15 14:00:00+02:00           2094  ...          -0.0140
2025-06-15 14:30:00+02:00           2024  ...          -0.0140
2025-06-15 15:00:00+02:00           1922  ...          -0.0111
2025-06-15 15:30:00+02:00           1807  ...          -0.0111
2025-06-15 16:00:00+02:00           1664  ...          -0.0091
2025-06-15 16:30:00+02:00           1490  ...          -0.0091
2025-06-15 17:00:00+02:00           1315  ...           0.0290
2025-06-15 17:30:00+02:00           1179  ...           0.0290
2025-06-15 18:00:00+02:00           1072  ...           0.0724
2025-06-15 18:30:00+02:00            943  ...           0.0724
2025-06-15 19:00:00+02:00            794  ...           0.0886
2025-06-15 19:30:00+02:00            629  ...           0.0886
2025-06-15 20:00:00+02:00            430  ...           0.1135
2025-06-15 20:30:00+02:00            234  ...           0.1135
2025-06-15 21:00:00+02:00             90  ...           0.1282
2025-06-15 21:30:00+02:00             22  ...           0.1282
2025-06-15 22:00:00+02:00              0  ...           0.1250
2025-06-15 22:30:00+02:00              0  ...           0.1250
2025-06-15 23:00:00+02:00              0  ...           0.1008
2025-06-15 23:30:00+02:00              0  ...           0.1008
2025-06-16 00:00:00+02:00              0  ...           0.1276
2025-06-16 00:30:00+02:00              0  ...           0.1276
2025-06-16 01:00:00+02:00              0  ...           0.1009
2025-06-16 01:30:00+02:00              0  ...           0.1009
2025-06-16 02:00:00+02:00              0  ...           0.0861
2025-06-16 02:30:00+02:00              0  ...           0.0861
2025-06-16 03:00:00+02:00              0  ...           0.0769
2025-06-16 03:30:00+02:00              0  ...           0.0769
2025-06-16 04:00:00+02:00              0  ...           0.0714
2025-06-16 04:30:00+02:00              0  ...           0.0714
2025-06-16 05:00:00+02:00              0  ...           0.0878
2025-06-16 05:30:00+02:00             16  ...           0.0878
2025-06-16 06:00:00+02:00             77  ...           0.1034
2025-06-16 06:30:00+02:00            207  ...           0.1034
2025-06-16 07:00:00+02:00            403  ...           0.1144
2025-06-16 07:30:00+02:00            656  ...           0.1144
2025-06-16 08:00:00+02:00            983  ...           0.1239
2025-06-16 08:30:00+02:00           1432  ...           0.1239
2025-06-16 09:00:00+02:00           1992  ...           0.1023
2025-06-16 09:30:00+02:00           2636  ...           0.1023
2025-06-16 10:00:00+02:00           3253  ...           0.0462
2025-06-16 10:30:00+02:00           3679  ...           0.0462
2025-06-16 11:00:00+02:00           3931  ...           0.0056
2025-06-16 11:30:00+02:00           4011  ...           0.0056
2025-06-16 12:00:00+02:00           3979  ...          -0.0055
2025-06-16 12:30:00+02:00           3870  ...          -0.0055
2025-06-16 13:00:00+02:00           3435  ...          -0.0067
[48 rows x 4 columns]
[2025-06-15 13:45:02 +0200] [21] [INFO] Perform an iteration of a naive MPC controller
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Battery usage enabled. Initial SOC: 0.6, Final SOC: 0.23
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Processing deferrable load 0
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Deferrable load 0: Proposed optimization window: -8 --> 12
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Deferrable load 0: Validated optimization window: 0 --> 12
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Processing deferrable load 1
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Load 1 is standard/non-thermal.
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Load 1: Using total timesteps constraint: 1
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Load 1: Standard load constraints set.
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Deferrable load 1: Proposed optimization window: -8 --> 14
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Deferrable load 1: Validated optimization window: 0 --> 14
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Processing deferrable load 2
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Deferrable load 2: Proposed optimization window: 6 --> 14
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Deferrable load 2: Validated optimization window: 6 --> 14
[2025-06-15 13:45:02 +0200] [21] [INFO] Status: Optimal
[2025-06-15 13:45:02 +0200] [21] [INFO] Total value of the Cost function = 0.06
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Battery usage enabled. Initial SOC: 0.6, Final SOC: 0.23
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Deferrable load operating hours: [0, 0, 0, 0]
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Deferrable load timesteps: [0, 1, 0]
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Deferrable load start timesteps: [-8, -8, 6]
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Deferrable load end timesteps: [12, 14, 14]
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Selected cost function type: self-consumption
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Solver selected: COIN_CMD
[2025-06-15 13:45:02 +0200] [21] [INFO] Optimization status: Optimal
[2025-06-15 13:45:02 +0200] [21] [INFO] Publishing data to HASS instance
[2025-06-15 13:45:02 +0200] [21] [INFO] Successfully posted to sensor.mpc_p_pv_forecast = 3883
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Saved sensor.mpc_p_pv_forecast to json file
[2025-06-15 13:45:02 +0200] [21] [INFO] Successfully posted to sensor.mpc_p_load_forecast = 555
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Saved sensor.mpc_p_load_forecast to json file
[2025-06-15 13:45:02 +0200] [21] [INFO] Successfully posted to sensor.mpc_p_pv_curtailment = 0.0
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Saved sensor.mpc_p_pv_curtailment to json file
[2025-06-15 13:45:02 +0200] [21] [INFO] Successfully posted to sensor.mpc_p_hybrid_inverter = 2552.0
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Saved sensor.mpc_p_hybrid_inverter to json file
[2025-06-15 13:45:02 +0200] [21] [INFO] Successfully posted to sensor.mpc_p_deferrable0 = 0.0
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Saved sensor.mpc_p_deferrable0 to json file
[2025-06-15 13:45:02 +0200] [21] [INFO] Successfully posted to sensor.mpc_p_deferrable1 = 1997.0
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Saved sensor.mpc_p_deferrable1 to json file
[2025-06-15 13:45:02 +0200] [21] [INFO] Successfully posted to sensor.mpc_p_deferrable2 = 0.0
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Saved sensor.mpc_p_deferrable2 to json file
[2025-06-15 13:45:02 +0200] [21] [INFO] Successfully posted to sensor.mpc_p_batt_forecast = -1331.0
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Saved sensor.mpc_p_batt_forecast to json file
[2025-06-15 13:45:02 +0200] [21] [INFO] Successfully posted to sensor.mpc_soc_batt_forecast = 64.21
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Saved sensor.mpc_soc_batt_forecast to json file
[2025-06-15 13:45:02 +0200] [21] [INFO] Successfully posted to sensor.mpc_p_grid_forecast = 0.0
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Saved sensor.mpc_p_grid_forecast to json file
[2025-06-15 13:45:02 +0200] [21] [INFO] Successfully posted to sensor.mpc_total_cost_fun_value = 1.16
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Saved sensor.mpc_total_cost_fun_value to json file
[2025-06-15 13:45:02 +0200] [21] [INFO] Successfully posted to sensor.mpc_optim_status = Optimal
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Saved sensor.mpc_optim_status to json file
[2025-06-15 13:45:02 +0200] [21] [INFO] Successfully posted to sensor.mpc_unit_load_cost = 0.1451
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Saved sensor.mpc_unit_load_cost to json file
[2025-06-15 13:45:02 +0200] [21] [INFO] Successfully posted to sensor.mpc_unit_prod_price = -0.0147
[2025-06-15 13:45:02 +0200] [21] [DEBUG] Saved sensor.mpc_unit_prod_price to json file
[2025-06-15 13:45:03 +0200] [21] [INFO]  >> Obtaining params: 
[2025-06-15 13:45:03 +0200] [21] [INFO] Passed runtime parameters: {'publish_prefix': 'mpc_'}
[2025-06-15 13:45:03 +0200] [21] [INFO]  >> Setting input data dict
[2025-06-15 13:45:03 +0200] [21] [INFO] Setting up needed data
[2025-06-15 13:45:03 +0200] [21] [DEBUG] Initialized Optimization with retrieve_hass_conf: {'optimization_time_step': Timedelta('0 days 00:30:00'), 'historic_days_to_retrieve': 10, 'sensor_power_photovoltaics': 'sensor.inverter_ingangsvermogen', 'sensor_power_photovoltaics_forecast': 'sensor.p_pv_forecast', 'sensor_power_load_no_var_loads': 'sensor.power_load_no_var_loads', 'load_negative': False, 'set_zero_min': True, 'sensor_replace_zero': ['sensor.inverter_ingangsvermogen'], 'sensor_linear_interp': ['sensor.inverter_ingangsvermogen', 'sensor.power_load_no_var_loads'], 'method_ts_round': 'first', 'continual_publish': False, 'hass_url': 'http://supervisor/core/api', 'long_lived_token': '4a653cd73437817aa25835895766b233a4f4fb77ce6eaa1ea5ad42337de7bfd955616ee0c9c95b4e2829ff13d5b6cefe51f1801618726893', 'time_zone': <DstTzInfo 'Europe/Brussels' LMT+0:18:00 STD>, 'Latitude': 50.789456233171535, 'Longitude': 5.592577457427979, 'Altitude': 110}
[2025-06-15 13:45:03 +0200] [21] [DEBUG] Optimization configuration: {'costfun': 'self-consumption', 'logging_level': 'INFO', 'set_use_pv': True, 'set_use_adjusted_pv': False, 'adjusted_pv_regression_model': 'LassoRegression', 'adjusted_pv_solar_elevation_threshold': 10, 'set_use_battery': True, 'number_of_deferrable_loads': 4, 'nominal_power_of_deferrable_loads': [2150, 2000, 3000, 3000], 'minimum_power_of_deferrable_loads': [0, 0, 0, 0], 'operating_hours_of_each_deferrable_load': [2, 2, 2, 2], 'treat_deferrable_load_as_semi_cont': [False, False, False, False], 'set_deferrable_load_single_constant': [False, False, False, False], 'set_deferrable_startup_penalty': [3, 5, 5, 0], 'delta_forecast_daily': Timedelta('1 days 00:00:00'), 'load_forecast_method': 'naive', 'load_cost_forecast_method': 'hp_hc_periods', 'load_peak_hours_cost': 0.1907, 'load_offpeak_hours_cost': 0.1419, 'production_price_forecast_method': 'constant', 'photovoltaic_production_sell_price': 0.065, 'set_total_pv_sell': False, 'lp_solver': 'COIN_CMD', 'lp_solver_path': '/usr/bin/cbc', 'lp_solver_timeout': 45, 'num_threads': 0, 'set_nocharge_from_grid': False, 'set_nodischarge_to_grid': False, 'set_battery_dynamic': True, 'battery_dynamic_max': 0.85, 'battery_dynamic_min': -0.5, 'weight_battery_discharge': 0.05, 'weight_battery_charge': 0.01, 'weather_forecast_method': 'open-meteo', 'open_meteo_cache_max_age': 30, 'start_timesteps_of_each_deferrable_load': [0, 0, 0, 0], 'end_timesteps_of_each_deferrable_load': [0, 0, 0, 0], 'load_peak_hour_periods': {'period_hp_1': [{'start': '08:00'}, {'end': '17:00'}], 'period_hp_2': [{'start': '08:00'}, {'end': '17:00'}]}}
[2025-06-15 13:45:03 +0200] [21] [DEBUG] Plant configuration: {'maximum_power_from_grid': 4000, 'maximum_power_to_grid': 6000, 'pv_module_model': ['JA_Solar_JAM72S01_385_PR', 'JA_Solar_JAM72S01_385_PR', 'JA_Solar_JAM72S01_385_PR'], 'pv_inverter_model': ['Huawei_Technologies_Co___Ltd___SUN2000_9KTL_USL0__240V_', 'Huawei_Technologies_Co___Ltd___SUN2000_9KTL_USL0__240V_', 'Huawei_Technologies_Co___Ltd___SUN2000_9KTL_USL0__240V_'], 'surface_tilt': [35, 35, 15], 'surface_azimuth': [90, 270, 180], 'modules_per_string': [6, 6, 13], 'strings_per_inverter': [1, 1, 1], 'inverter_is_hybrid': True, 'compute_curtailment': True, 'battery_discharge_power_max': 5000, 'battery_charge_power_max': 5000, 'battery_discharge_efficiency': 1, 'battery_charge_efficiency': 0.95, 'battery_nominal_energy_capacity': 15000, 'battery_minimum_state_of_charge': 0.12, 'battery_maximum_state_of_charge': 1, 'battery_target_state_of_charge': 0.12}
[2025-06-15 13:45:03 +0200] [21] [DEBUG] Solver configuration: lp_solver=COIN_CMD, lp_solver_path=/usr/bin/cbc
[2025-06-15 13:45:03 +0200] [21] [DEBUG] Number of threads: 2
[2025-06-15 13:45:03 +0200] [21] [INFO]  >> Publishing data...
[2025-06-15 13:45:03 +0200] [21] [INFO] Publishing data to HASS instance
[2025-06-15 13:45:03 +0200] [21] [INFO] Successfully posted to sensor.mpc_optim_status = Optimal
[2025-06-15 13:45:03 +0200] [21] [INFO] Successfully posted to sensor.mpc_p_deferrable2 = 0
[2025-06-15 13:45:03 +0200] [21] [INFO] Successfully posted to sensor.mpc_unit_load_cost = 0.1451
[2025-06-15 13:45:03 +0200] [21] [INFO] Successfully posted to sensor.mpc_soc_batt_forecast = 64.21
[2025-06-15 13:45:03 +0200] [21] [INFO] Successfully posted to sensor.mpc_p_grid_forecast = 0.0
[2025-06-15 13:45:03 +0200] [21] [INFO] Successfully posted to sensor.mpc_total_cost_fun_value = 1.16
[2025-06-15 13:45:03 +0200] [21] [INFO] Successfully posted to sensor.mpc_p_batt_forecast = -1331.0
[2025-06-15 13:45:03 +0200] [21] [INFO] Successfully posted to sensor.mpc_p_load_forecast = 555
[2025-06-15 13:45:03 +0200] [21] [INFO] Successfully posted to sensor.mpc_p_deferrable3 = 0
[2025-06-15 13:45:03 +0200] [21] [INFO] Successfully posted to sensor.mpc_p_pv_curtailment = 0.0
[2025-06-15 13:45:03 +0200] [21] [INFO] Successfully posted to sensor.mpc_p_hybrid_inverter = 2552.0
[2025-06-15 13:45:03 +0200] [21] [INFO] Successfully posted to sensor.mpc_temp_predicted3 = 36.67
[2025-06-15 13:45:03 +0200] [21] [INFO] Successfully posted to sensor.mpc_p_deferrable0 = 0
[2025-06-15 13:45:03 +0200] [21] [INFO] Successfully posted to sensor.mpc_unit_prod_price = -0.0147
[2025-06-15 13:45:03 +0200] [21] [INFO] Successfully posted to sensor.mpc_p_deferrable1 = 1997
[2025-06-15 13:45:03 +0200] [21] [INFO] Successfully posted to sensor.mpc_p_pv_forecast = 3883
[2025-06-15 13:46:48 +0200] [21] [INFO] EMHASS server online, serving index.html...

Would someone be able to assist me on this. I have no idea where to start looking but esentially the p_load forecast values are out of sync with current time.

The parameters being passed are as follows:

Blockquote
ml_forecast_model_fit:
url: http://localhost:5050/action/forecast-model-fit
method: POST
content_type: ‘application/json’
payload: >-
{
“days_to_retrieve”: 9,
“model_type”: “load_forecast”,
“var_model”: “sensor.power_load_no_var”,
“sklearn_model”: “KNeighborsRegressor”,
“num_lags”: 48,
“split_date_delta”: “48h”,
“perform_backtest”: “True”
}

My power_load_no_var_loads looks something like this.

Seems like a timezone issue but I’ve set it in the EMHASS config

Running HA supervisor & its set to the same zone…

There is a TZ issue with the forecasts, please include some comments here:

Thanks, is there a workaround you’re implementing at the moment. Im thinking of just loading the sensor with previous days values?