EMHASS: An Energy Management for Home Assistant

Very good. Now yes you should add as many automations as you think necessary to manually treat the boundary cases and those scenarios that pop up as data arrives at (near) real-time.
EMHASS is there just to provide a mean schedule, but it is a good idea to provide additional action to treat those special cases.

1 Like

My prices change every 5 minutes which is my primary driver to run high frequency MPC.

I also include current/ now values for solar production and household load. Running high frequency MPC in this case catches unscheduled loads (like dishwater or washing machine) or unexpected changes in solar production (like occasional clouds).

If your forecasts are stable then you can increase the duration between optimisation runs without penalty.

Give it a go and let us know how it works.

I suspect that as you run the optimisation once a day, it has a plan, but in some cases your battery will charge faster or slower than the plan and so in the next time step it will try and correct the overshoot. As your plan doesn’t update during the day it doesn’t understand these overshoots and tries to stick with the original plan.

If you were to run MPC more frequently, maybe once per hour it could readjust the plan intra-day and reduce the overshoots.

The other consideration is if it wants to charge the battery is that from excess solar or the grid. If your conditions only look at SOC_forecast or p_batt_forecast then it doesn’t understand the difference. For some of my battery automations I also look at the state of p_grid_forecast and only if I’m forecast to consume from the grid do I put the battery into a forced mode. Otherwise (my default action) is to put the battery into self consumption with a -10% buffer.

YAML as requested

alias: p_batt automation - script
description: |-
  Powerwall Automation

  p_batt_forecast < -10000 
    backup: 10 kW (3 * 3.3 kW)
    mode: backup

  p_batt_forecast < -5000
    SOC forecast: 5 kW (3*1.7 kW)

  else
    mode: Self-Powered
trigger:
  - platform: state
    entity_id:
      - sensor.soc_batt_forecast
    to: null
    enabled: false
  - platform: state
    entity_id:
      - sensor.p_batt_forecast
    enabled: true
  - platform: state
    entity_id:
      - sensor.p_grid_forecast
    to: null
    enabled: false
condition: []
action:
  - choose:
      - conditions:
          - condition: numeric_state
            entity_id: sensor.p_batt_forecast
            below: -10000
          - condition: numeric_state
            entity_id: sensor.p_grid_forecast
            above: 1
            enabled: false
        sequence:
          - service: script.fast_charge_from_solar_and_grid_11_kw
            metadata: {}
            data: {}
      - conditions:
          - condition: numeric_state
            entity_id: sensor.p_batt_forecast
            below: -5500
          - condition: numeric_state
            entity_id: sensor.p_grid_forecast
            above: 1
            enabled: false
        sequence:
          - service: script.slow_charging_from_grid_5_kw
            metadata: {}
            data: {}
      - conditions:
          - condition: numeric_state
            entity_id: sensor.p_batt_forecast
            above: 1000
          - condition: numeric_state
            entity_id: sensor.p_grid_forecast
            below: -1000
          - condition: time
            after: "01:00:00"
            before: "00:00:00"
          - condition: numeric_state
            entity_id: sensor.energy_site_battery_power
            below: 10
            enabled: false
        sequence:
          - service: script.fast_export_to_grid
            data: {}
      - conditions:
          - condition: numeric_state
            entity_id: sensor.p_batt_forecast
            above: -5500
          - condition: numeric_state
            entity_id: sensor.p_grid_forecast
            above: 100
        sequence:
          - service: script.preserve
            metadata: {}
            data: {}
    default:
      - service: script.self_consumption_5
        metadata: {}
        data: {}
mode: single

Hi, that sounds like I was thinking about, will you share the yaml file so I can have a closer look how it works?

Thank you for this, I see you are using some scripts, would you care to share them for the complete picture and for me to learn from this and implement my own scripts? It works a lot faster with some examples, later on I can experiment with MPC. I was already doing some tests in the developers tool template.

Like Mark, I call the MPC routine every 60 seconds. The two forecasts that this produces to manage a battery (sensor.p_batt_forecast, sensor.soc_batt_forecast) change constantly depending on the data fed into the MPC calculation.

However neither of them match the power curve of the battery perfectly. The battery has a maximum input/output of 3300W, but this is not constant. It will only output 3300W for an hour or so before it starts to wane. It also wanes in input towards 100% charge and output towards 25% charge and is intermittent from 25% to 15% and dead below 15%. Its was 9kWh usable originally but 6 years old now.
Something like this:

The two forecasts that predict best battery performance look like this today:


The Batt Power forecast value can be applied directly to my battery as a charge or discharge command but it is ignorant of the power curve of the battery and sometimes tries to charge at full rate (3300W) for a long period which ends up dropping down to below 2500W. It then tries to compensate by charging at a high rate towards the 100% charged point to catch up but this is also ignorant of the waning towards 100% so the battery doesn’t reach 100% when it’s supposed to.

The battery SoC forecast, on the other hand, give me a 30 minute target to get the battery to which is a little easier to do. I used this template to calculate what power to apply to meet the target.

{%- set third_row = state_attr('sensor.soc_batt_forecast', 'battery_scheduled_soc')[0] -%}
{%- set soc_value = third_row['soc_batt_forecast']|float(0) -%}
{%- set raw_power = ((states('sensor.sonnenbatterie_84324_state_charge_user')|float(0) - soc_value) / 100 * 9300 / 0.5 / 0.9)|round(0) -%}
{%- set limited_power = min(max(raw_power, -3300), 3300) -%}
{{ limited_power }}

A sample of the data helps to understand the template:

This is applied to the battery as a wattage charge or discharge command every time it changes which can be every 60 seconds as the whole forecast is recalculated by MPC every 60 seconds.

Entire config is here
Hope that helps.

The automations that work well with EMHASS need to be tailored for your specific battery/ devices.

I have Tesla Powerwall which doesn’t give me fine control, so the scripts are a bit of a work around, also without the context the YAML doesn’t make much sense.

For example here is my fast charge from grid automation:

alias: Fast Charge from Grid (11 kW)
sequence:
  - device_id: 9505d4c87598eefde0fd0fadcf2cbbe9
    domain: select
    entity_id: 80d77029cd7cea8978551193563cac94
    type: select_option
    option: backup
  - device_id: 9505d4c87598eefde0fd0fadcf2cbbe9
    domain: select
    entity_id: 5718d6954de1e1c87f52bcc2bcad03ac
    type: select_option
    option: never
  - type: turn_on
    device_id: 9505d4c87598eefde0fd0fadcf2cbbe9
    entity_id: e5dfb6c55a767e0dd793a6661b076ddf
    domain: switch
mode: single
icon: mdi:transmission-tower-export

In my case, I have come quite close to the soc forecast. It’s in a combination of where I add 400W to the discharge and run limited power like @rcruikshank on the charge

1 Like

Thanks for all these examples. Up till now with day-ahead all seems fine (from april 24th 9.00 am). The data before that are all kinds of experiments, running day-ahead twice will not work in this (data before 9.00 am)

Now I want to try MPC for better prediction and see what I run into. I have this set-up:

sensor:
  - platform: template
    sensors:
      electricity_consumption_price_24h_forecast:
        friendly_name: "Electricity consumption price 24h forecast"
        value_template: >-
          {% set data = state_attr('sensor.nordpool', 'raw_today') | map(attribute='value') | list %}
          {% set values = namespace(all=[]) %}
          {% for i in range(now().hour+1,data | length) %}
          {% set v = ((1.1 + (0.1*(data[i] | float(0))*10)*1.06 + 1.582*1.06 + 5.38613 + 0.20417 + 5.03288) | round(4)) %}
          {% set values.all = values.all + [ v ] %}
          {% endfor %}
          {% set data = state_attr('sensor.nordpool', 'raw_tomorrow') | map(attribute='value') | list %}
          {% for i in range(data | length) %}
          {% set v = ((1.1 + (0.1*(data[i] | float(0))*10)*1.06 + 1.582*1.06 + 5.38613 + 0.20417 + 5.03288) | round(4)) %}
          {% set values.all = values.all + [ v ] %}
          {% endfor %} {{ (values.all)[:24] }}
      electricity_production_price_24h_forecast:
        friendly_name: "Electricity production price 24h forecast"
        value_template: >-
          {% set data = state_attr('sensor.nordpool', 'raw_today') | map(attribute='value') | list %}
          {% set values = namespace(all=[]) %}
          {% for i in range(now().hour+1,data | length) %}
          {% set v = ((-0.905 + (0.1*(data[i] | float(0))*10)) | round(4)) %}
          {% set values.all = values.all + [ v ] %}
          {% endfor %}
          {% set data = state_attr('sensor.nordpool', 'raw_tomorrow') | map(attribute='value') | list %}
          {% for i in range(data | length) %}
          {% set v = ((-0.905 + (0.1*(data[i] | float(0))*10)) | round(4)) %}
          {% set values.all = values.all + [ v ] %}
          {% endfor %} {{ (values.all)[:24] }}

And

 post_mpc_optim: "curl -i -H \"Content-Type: application/json\" -X POST -d '{\"load_cost_forecast\":{{
          (states.sensor.electricity_consumption_price_24h_forecast.state)
          }}, \"prod_price_forecast\":{{
          (states.sensor.electricity_production_price_24h_forecast.state) 
          }}, \"prediction_horizon\":{{(states.sensor.electricity_consumption_price_24h_forecast.state)|list|length
          }},\"soc_init\":{{states('sensor.battery_batterijpercentage')|float(0)/100}},\"soc_final\":0.12' http://localhost:5000/action/naive-mpc-optim"

Results in:

post_mpc_optim: "curl -i -H \"Content-Type: application/json\" -X POST -d '{\"load_cost_forecast\":[21.8812, 21.6893, 21.2356, 20.0845, 19.6848, 20.0018, 20.447, 21.1953, 23.151, 24.4008, 26.0989, 25.2583, 23.0832, 21.8525], \"prod_price_forecast\":[7.096, 6.915, 6.487, 5.401, 5.024, 5.323, 5.743, 6.449, 8.294, 9.473, 11.075, 10.282, 8.23, 7.069], \"prediction_horizon\":124,\"soc_init\":0.14,\"soc_final\":0.12' http://localhost:5000/action/naive-mpc-optim"

I want a variable prediction horizon as the number of items in sensor varies through the day with a minimum length of 12 items in the sensor
So I tried a few thing in the developer tools as I am still new to Home Assistant to get some understanding how it works.

{{(states.sensor.electricity_consumption_price_24h_forecast.state)|count}}
{{(states.sensor.electricity_consumption_price_24h_forecast.state)|list}}
{{(states.sensor.electricity_consumption_price_24h_forecast.state)|length}}
{{(states.sensor.electricity_consumption_price_24h_forecast.state)|list|count}}
{{(states.sensor.electricity_consumption_price_24h_forecast.state)|list|length}}

which don’t give what I want (number of items in the column):

133
['[', '2', '3', '.', '1', '6', '3', '8', ',', ' ', '2', '1', '.', '8', '8', '1', '2', ',', ' ', '2', '1', '.', '6', '8', '9', '3', ',', ' ', '2', '1', '.', '2', '3', '5', '6', ',', ' ', '2', '0', '.', '0', '8', '4', '5', ',', ' ', '1', '9', '.', '6', '8', '4', '8', ',', ' ', '2', '0', '.', '0', '0', '1', '8', ',', ' ', '2', '0', '.', '4', '4', '7', ',', ' ', '2', '1', '.', '1', '9', '5', '3', ',', ' ', '2', '3', '.', '1', '5', '1', ',', ' ', '2', '4', '.', '4', '0', '0', '8', ',', ' ', '2', '6', '.', '0', '9', '8', '9', ',', ' ', '2', '5', '.', '2', '5', '8', '3', ',', ' ', '2', '3', '.', '0', '8', '3', '2', ',', ' ', '2', '1', '.', '8', '5', '2', '5', ']']
133
133
133

Maybe someone can help me here to get the number of items in the column.

My MPC prediction horizon looks like this:

  "prediction_horizon": {{ min(48, (state_attr('sensor.cecil_st_feed_in_forecast','forecasts')|map(attribute='per_kwh')|list|length)+1)}}

sensor.cecil_st_feed_in_forecast looks like this:


And there’s up to 48 attribute arrays in this.

If I strip |length off the end of this template:

{{ (state_attr('sensor.cecil_st_feed_in_forecast','forecasts')|map(attribute='per_kwh')|list)}}

it produces this array 48 values long:

[
  0.52,
  0.43,
  0.24,
  0.25,
  0.3,
  0.17,
  0.32,
  0.32,
  0.32,
  0.3,
  0.28,
  0.15,
  0.14,
  0.12,
  0.11,
  0.11,
  0.11,
  0.11,
  0.11,
  0.11,
  0.11,
  0.12,
  0.12,
  0.12,
  0.11,
  0.1,
  0.06,
  0.06,
  0.02,
  0.02,
  0,
  0,
  0,
  -0.02,
  -0.03,
  -0.03,
  -0.04,
  -0.02,
  0.28,
  0.29,
  0.29,
  0.3,
  0.34,
  0.42,
  0.59,
  0.67,
  0.69,
  0.68
]

So what does yours produce?

{{(states.sensor.electricity_consumption_price_24h_forecast.state)|list}}

Without the |length command at the end?

If that’s not the correct array to measure the length of, what is?

Hi,

I tried several things here:

{%- set Z = expand('electricity_consumption_price_24h_forecast')|map(attribute='value')|list %}
{{Z}}
{{(states.sensor.electricity_consumption_price_24h_forecast.state)}}
{{(states.sensor.electricity_consumption_price_24h_forecast.state)|list}}
{{(states.sensor.electricity_consumption_price_24h_forecast.state)|length}}
{{(states.sensor.electricity_consumption_price_24h_forecast.state)|list|count}}
{{(states.sensor.electricity_consumption_price_24h_forecast.state)|list|length}}

With these results:

[]
[20.8572, 20.6865, 20.3293, 20.8116, 20.9505, 21.7232, 22.638, 25.5064, 25.5668, 24.2089, 22.6783, 22.7557]
['[', '2', '0', '.', '8', '5', '7', '2', ',', ' ', '2', '0', '.', '6', '8', '6', '5', ',', ' ', '2', '0', '.', '3', '2', '9', '3', ',', ' ', '2', '0', '.', '8', '1', '1', '6', ',', ' ', '2', '0', '.', '9', '5', '0', '5', ',', ' ', '2', '1', '.', '7', '2', '3', '2', ',', ' ', '2', '2', '.', '6', '3', '8', ',', ' ', '2', '5', '.', '5', '0', '6', '4', ',', ' ', '2', '5', '.', '5', '6', '6', '8', ',', ' ', '2', '4', '.', '2', '0', '8', '9', ',', ' ', '2', '2', '.', '6', '7', '8', '3', ',', ' ', '2', '2', '.', '7', '5', '5', '7', ']']
107
107
107
{{(states.sensor.electricity_consumption_price_24h_forecast.state)}}

at least gives me the listing but it’s in a row not a column, maybe that’s the issue?
So we need to transpose from ‘row’ to ‘column’ maybe.

This is all Jinja foo…

But this seems to work:

{{[20.8572, 20.6865, 20.3293, 20.8116, 20.9505, 21.7232, 22.638, 25.5064, 25.5668, 24.2089, 22.6783, 22.7557]|count}}

{{"[20.8572, 20.6865, 20.3293, 20.8116, 20.9505, 21.7232, 22.638, 25.5064, 25.5668, 24.2089, 22.6783, 22.7557]".split(', ')}}
{{"[20.8572, 20.6865, 20.3293, 20.8116, 20.9505, 21.7232, 22.638, 25.5064, 25.5668, 24.2089, 22.6783, 22.7557]".split(', ')|count}}

{{states('sensor.amberapi_attributes_2')}}
{{states('sensor.amberapi_attributes_2').split(', ')|count}}

{{states.sensor.amberapi_attributes_2.state}}
{{states.sensor.amberapi_attributes_2.state.split(', ')}}
{{states.sensor.amberapi_attributes_2.state.split(', ')|count}}
12

['[20.8572', '20.6865', '20.3293', '20.8116', '20.9505', '21.7232', '22.638', '25.5064', '25.5668', '24.2089', '22.6783', '22.7557]']
12

[16.28971, 12.96539, 30.07253]
3

[16.28971, 12.96539, 30.07253]
['[16.28971', '12.96539', '30.07253]']
3

Having some issues with hot water flapping resulting cold water… anyone knows what I can do to solve this?

This is currently typical of running high frequency MPC, I’m currently running every minute and I often see the Deferrable Load forecast up and down each minute:

image

You need to have some way to dampen this effect:

image

You can either run MPC with less frequency, so it can only change every 5 minutes or every 30 minutes, or you can include some delays in your automations for the specific device so it doesn’t switch on/ off hundreds of times, certainly not good for the switching circuits.

You could also implement a low pass filter:

1 Like

Yes, that works. Thx. Still a lot to learn.

Meanwhile I started to use MPC with prediction horizon of 6h at 10 min intervals

Ok. Thanks will look into this :blush:

Running MPC optimization generates a zero division error, maybe because of negative prices?

2024-04-27 13:30:00,506 - web_server - INFO - Passed runtime parameters: {'load_cost_forecast': [13.4001, 13.4001, 15.2116, 18.5729, 20.8201, 21.9914, 22.0953, 21.3607, 20.7544, 19.9636, 19.3774, 17.9729, 17.5977, 16.278, 15.3569, 15.3865, 14.4516, 13.4107, 13.3927, 13.292, 11.6373, 9.5067, 7.0634, 6.8111], 'prod_price_forecast': [-0.905, -0.905, 0.804, 3.975, 6.095, 7.2, 7.298, 6.605, 6.033, 5.287, 4.734, 3.409, 3.055, 1.81, 0.941, 0.969, 0.087, -0.895, -0.912, -1.007, -2.568, -4.578, -6.883, -7.121], 'prediction_horizon': 6, 'soc_init': 0.43, 'soc_final': 0.9}
2024-04-27 13:30:00,507 - web_server - INFO -  >> Setting input data dict
2024-04-27 13:30:00,508 - web_server - INFO - Setting up needed data
2024-04-27 13:30:00,515 - web_server - INFO - Retrieve hass get data method initiated...
2024-04-27 13:30:00,968 - web_server - INFO - Retrieving weather forecast data using method = scrapper
2024-04-27 13:30:01,647 - web_server - INFO - Retrieving data from hass for load forecast using method = naive
2024-04-27 13:30:01,648 - web_server - INFO - Retrieve hass get data method initiated...
2024-04-27 13:30:02,133 - web_server - ERROR - Exception on /action/naive-mpc-optim [POST]
Traceback (most recent call last):
  File "/usr/local/lib/python3.11/dist-packages/flask/app.py", line 1463, in wsgi_app
    response = self.full_dispatch_request()
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/flask/app.py", line 872, in full_dispatch_request
    rv = self.handle_user_exception(e)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/flask/app.py", line 870, in full_dispatch_request
    rv = self.dispatch_request()
         ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/flask/app.py", line 855, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)  # type: ignore[no-any-return]
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/emhass/web_server.py", line 108, in action_call
    input_data_dict = set_input_data_dict(config_path, str(data_path), costfun,
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/emhass/command_line.py", line 129, in set_input_data_dict
    df_input_data_dayahead = utils.set_df_index_freq(df_input_data_dayahead)
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/emhass/utils.py", line 687, in set_df_index_freq
    df = df.asfreq(sampling)
         ^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/pandas/core/frame.py", line 10971, in asfreq
    return super().asfreq(
           ^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/pandas/core/generic.py", line 8347, in asfreq
    return asfreq(
           ^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/pandas/core/resample.py", line 2232, in asfreq
    dti = date_range(obj.index.min(), obj.index.max(), freq=freq)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/pandas/core/indexes/datetimes.py", line 945, in date_range
    dtarr = DatetimeArray._generate_range(
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/pandas/core/arrays/datetimes.py", line 446, in _generate_range
    i8values = generate_regular_range(start, end, periods, freq, unit=unit)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/pandas/core/arrays/_ranges.py", line 68, in generate_regular_range
    e = b + (iend - b) // stride * stride + stride // 2 + 1
            ~~~~~~~~~^~~~~~~~~~~
ZeroDivisionError: integer division or modulo by zero
2024-04-27 13:30:02,147 - web_server - INFO - Passed runtime parameters: {}
2024-04-27 13:30:02,147 - web_server - INFO -  >> Setting input data dict
2024-04-27 13:30:02,147 - web_server - INFO - Setting up needed data
2024-04-27 13:30:02,148 - web_server - INFO -  >> Publishing data...
2024-04-27 13:30:02,148 - web_server - INFO - Publishing data to HASS instance
2024-04-27 13:30:02,155 - web_server - INFO - Successfully posted to sensor.p_pv_forecast = 2645.33
2024-04-27 13:30:02,158 - web_server - INFO - Successfully posted to sensor.p_load_forecast = 236.19
2024-04-27 13:30:02,162 - web_server - INFO - Successfully posted to sensor.p_deferrable0 = 0.0
2024-04-27 13:30:02,165 - web_server - INFO - Successfully posted to sensor.p_batt_forecast = -2409.14
2024-04-27 13:30:02,168 - web_server - INFO - Successfully posted to sensor.soc_batt_forecast = 67.01
2024-04-27 13:30:02,172 - web_server - INFO - Successfully posted to sensor.p_grid_forecast = 0.0
2024-04-27 13:30:02,175 - web_server - INFO - Successfully posted to sensor.total_cost_fun_value = 17.62
2024-04-27 13:30:02,177 - web_server - INFO - Successfully posted to sensor.optim_status = Optimal
2024-04-27 13:30:02,180 - web_server - INFO - Successfully posted to sensor.unit_load_cost = 13.4001
2024-04-27 13:30:02,183 - web_server - INFO - Successfully posted to sensor.unit_prod_price = -0.905

I run negative prices almost every day, so that isn’t the issue.

Has it been calculating correctly previously and only just started failing?

Your prediction horizon might be a little low, can you increase that?

There might also be some funny values in your load/ pv forecasts which is it pulling by default. I find you can reduce the errors if you can specify them directly as runtime parameters, but that isn’t always easy.

2024-04-28 08:36:00,084 - web_server - INFO - Passed runtime parameters: {'load_cost_forecast': [0.05, 0.02, 0.04, 0.04, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.05, 0.09, 0.11, 0.13, 0.14, 0.29, 0.33, 0.4, 0.46, 0.53, 0.51, 0.39, 0.37, 0.37, 0.34, 0.2, 0.19, 0.2, 0.18, 0.17, 0.17, 0.17, 0.16, 0.17, 0.15, 0.14, 0.14, 0.14, 0.15], 'prod_price_forecast': [-0.03, -0.04, -0.03, -0.03, -0.04, -0.04, -0.04, -0.04, -0.04, -0.04, -0.02, 0.01, 0.04, 0.05, 0.06, 0.06, 0.11, 0.16, 0.22, 0.28, 0.27, 0.16, 0.14, 0.14, 0.11, 0.11, 0.1, 0.11, 0.09, 0.08, 0.08, 0.08, 0.08, 0.08, 0.06, 0.06, 0.06, 0.06, 0.06], 'pv_power_forecast': [5060, 7274, 8348, 9271, 9496, 9267, 9193, 9262, 9063, 8567, 7798, 7006, 6061, 4883, 3542, 1979, 444, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 447, 1419, 2665, 3936, 5159, 6288, 7280, 8082, 8682, 9046, 9176, 9084, 8712, 8321, 7922, 7145, 6017, 4760, 3415, 1901, 449, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 433, 1381, 2663, 3984, 5282, 6520, 7654, 8545, 9274, 9746, 10182, 10335, 10224, 9749, 8912, 7879, 6558, 5182, 3733, 2171, 679, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'load_power_forecast': [4450, 700, 700, 2000, 2600, 2400, 2400, 1900, 2000, 4000, 2400, 1400, 300, 900, 300, 300, 700, 3500, 2400, 600, 700, 600, 600, 500, 2800, 2800, 2800, 500, 300, 300, 300, 300, 300, 400, 300, 300, 400, 300, 700, 900, 1000, 400, 500, 400, 300, 300, 1800, 1900, 3400, 700, 700, 2000, 2600, 2400, 2400, 1900, 2000, 4000, 2400, 1400, 300, 900, 300, 300, 700, 3500, 2400, 600, 700, 600, 600, 500, 2800, 2800, 2800, 500, 300, 300, 300, 300, 300, 400, 300, 300, 400, 300, 700, 900, 1000, 400, 500, 400, 300, 300, 1800, 1900], 'prediction_horizon': 39, 'alpha': 1, 'beta': 0, 'num_def_loads': 6, 'def_total_hours': [0, 5, 1, 0, 6, 2], 'def_end_timestep': [0, 0, 14, 0, 0, 14], 'P_deferrable_nom': [1232, 6333, 11520, 2000, 600, 11520], 'treat_def_as_semi_cont': [1, 1, 0, 0, 1, 0], 'set_def_constant': [0, 0, 0, 0, 0, 0], 'soc_init': 0.01, 'soc_final': 0}
2024-04-28 08:36:00,084 - web_server - INFO -  >> Setting input data dict
2024-04-28 08:36:00,085 - web_server - INFO - Setting up needed data
2024-04-28 08:36:00,090 - web_server - INFO - Retrieve hass get data method initiated...
2024-04-28 08:36:01,085 - web_server - INFO - Retrieving weather forecast data using method = list
2024-04-28 08:36:01,093 - web_server - INFO -  >> Performing naive MPC optimization...
2024-04-28 08:36:01,094 - web_server - INFO - Performing naive MPC optimization
2024-04-28 08:36:01,123 - web_server - INFO - Perform an iteration of a naive MPC controller
2024-04-28 08:36:02,047 - web_server - INFO - Status: Optimal
2024-04-28 08:36:02,048 - web_server - INFO - Total value of the Cost function = 3.67
2024-04-28 08:36:12,854 - web_server - INFO - Passed runtime parameters: {'custom_load_forecast_id': {'entity_id': 'sensor.p_load_forecast', 'unit_of_measurement': 'W', 'friendly_name': 'Load Power Forecast'}}
2024-04-28 08:36:12,855 - web_server - INFO -  >> Setting input data dict
2024-04-28 08:36:12,859 - web_server - INFO - Setting up needed data
2024-04-28 08:36:12,863 - web_server - INFO -  >> Publishing data...
2024-04-28 08:36:12,863 - web_server - INFO - Publishing data to HASS instance
2024-04-28 08:36:12,898 - web_server - INFO - Successfully posted to sensor.p_pv_forecast = 5060
2024-04-28 08:36:12,925 - web_server - INFO - Successfully posted to sensor.p_load_forecast = 4450
2024-04-28 08:36:12,947 - web_server - INFO - Successfully posted to sensor.p_deferrable0 = 0.0
2024-04-28 08:36:12,969 - web_server - INFO - Successfully posted to sensor.p_deferrable1 = 0.0
2024-04-28 08:36:12,992 - web_server - INFO - Successfully posted to sensor.p_deferrable2 = 0.0
2024-04-28 08:36:13,014 - web_server - INFO - Successfully posted to sensor.p_deferrable3 = 0.0
2024-04-28 08:36:13,036 - web_server - INFO - Successfully posted to sensor.p_deferrable4 = 0.0
2024-04-28 08:36:13,061 - web_server - INFO - Successfully posted to sensor.p_deferrable5 = 0.0
2024-04-28 08:36:13,084 - web_server - INFO - Successfully posted to sensor.p_batt_forecast = -8202.76
2024-04-28 08:36:13,107 - web_server - INFO - Successfully posted to sensor.soc_batt_forecast = 9.95
2024-04-28 08:36:13,142 - web_server - INFO - Successfully posted to sensor.p_grid_forecast = 7592.76
2024-04-28 08:36:13,169 - web_server - INFO - Successfully posted to sensor.total_cost_fun_value = 3.67
2024-04-28 08:36:13,191 - web_server - INFO - Successfully posted to sensor.optim_status = Optimal
2024-04-28 08:36:13,222 - web_server - INFO - Successfully posted to sensor.unit_load_cost = 0.05
2024-04-28 08:36:13,256 - web_server - INFO - Successfully posted to sensor.unit_prod_price = -0.03

Number of hours on can change during the day. If i want the heater on 6 hours every 24 hours I need to det allowed operation time from 0 to 24? And if the heater has been on 1 hour I need to change value to 5 and so on until 0? An then reset next day?

Prediction horizon increased to 11, soc_init = 0.12, soc_final = 0.9.

2024-04-28 18:20:00,384 - web_server - INFO - Successfully posted to sensor.p_load_forecast = 778.36
2024-04-28 18:20:00,387 - web_server - INFO - Successfully posted to sensor.p_deferrable0 = 0.0
2024-04-28 18:20:00,389 - web_server - INFO - Successfully posted to sensor.p_batt_forecast = 0.0
2024-04-28 18:20:00,392 - web_server - INFO - Successfully posted to sensor.soc_batt_forecast = 100.0
2024-04-28 18:20:00,395 - web_server - INFO - Successfully posted to sensor.p_grid_forecast = -1397.56
2024-04-28 18:20:00,398 - web_server - INFO - Successfully posted to sensor.total_cost_fun_value = -12.6
2024-04-28 18:20:00,400 - web_server - INFO - Successfully posted to sensor.optim_status = Optimal
2024-04-28 18:20:00,403 - web_server - INFO - Successfully posted to sensor.unit_load_cost = 15.783
2024-04-28 18:20:00,405 - web_server - INFO - Successfully posted to sensor.unit_prod_price = 1.343
2024-04-28 18:30:00,324 - web_server - INFO - Passed runtime parameters: {}
2024-04-28 18:30:00,325 - web_server - INFO -  >> Setting input data dict
2024-04-28 18:30:00,326 - web_server - INFO - Setting up needed data
2024-04-28 18:30:00,333 - web_server - INFO -  >> Publishing data...
2024-04-28 18:30:00,333 - web_server - INFO - Publishing data to HASS instance
2024-04-28 18:30:00,376 - web_server - INFO - Successfully posted to sensor.p_pv_forecast = 1104.25
2024-04-28 18:30:00,381 - web_server - INFO - Successfully posted to sensor.p_load_forecast = 729.69
2024-04-28 18:30:00,384 - web_server - INFO - Successfully posted to sensor.p_deferrable0 = 0.0
2024-04-28 18:30:00,387 - web_server - INFO - Successfully posted to sensor.p_batt_forecast = 0.0
2024-04-28 18:30:00,391 - web_server - INFO - Successfully posted to sensor.soc_batt_forecast = 100.0
2024-04-28 18:30:00,394 - web_server - INFO - Successfully posted to sensor.p_grid_forecast = -374.56
2024-04-28 18:30:00,398 - web_server - INFO - Successfully posted to sensor.total_cost_fun_value = -12.6
2024-04-28 18:30:00,400 - web_server - INFO - Successfully posted to sensor.optim_status = Optimal
2024-04-28 18:30:00,403 - web_server - INFO - Successfully posted to sensor.unit_load_cost = 20.0145
2024-04-28 18:30:00,406 - web_server - INFO - Successfully posted to sensor.unit_prod_price = 5.335
2024-04-28 18:40:00,319 - web_server - INFO - Passed runtime parameters: {}
2024-04-28 18:40:00,320 - web_server - INFO -  >> Setting input data dict
2024-04-28 18:40:00,320 - web_server - INFO - Setting up needed data
2024-04-28 18:40:00,329 - web_server - INFO -  >> Publishing data...
2024-04-28 18:40:00,329 - web_server - INFO - Publishing data to HASS instance
2024-04-28 18:40:00,366 - web_server - INFO - Successfully posted to sensor.p_pv_forecast = 1104.25
2024-04-28 18:40:00,370 - web_server - INFO - Successfully posted to sensor.p_load_forecast = 729.69
2024-04-28 18:40:00,372 - web_server - INFO - Successfully posted to sensor.p_deferrable0 = 0.0
2024-04-28 18:40:00,375 - web_server - INFO - Successfully posted to sensor.p_batt_forecast = 0.0
2024-04-28 18:40:00,377 - web_server - INFO - Successfully posted to sensor.soc_batt_forecast = 100.0
2024-04-28 18:40:00,380 - web_server - INFO - Successfully posted to sensor.p_grid_forecast = -374.56
2024-04-28 18:40:00,383 - web_server - INFO - Successfully posted to sensor.total_cost_fun_value = -12.6
2024-04-28 18:40:00,385 - web_server - INFO - Successfully posted to sensor.optim_status = Optimal
2024-04-28 18:40:00,388 - web_server - INFO - Successfully posted to sensor.unit_load_cost = 20.0145
2024-04-28 18:40:00,390 - web_server - INFO - Successfully posted to sensor.unit_prod_price = 5.335
2024-04-28 18:42:12,542 - web_server - INFO - EMHASS server online, serving index.html...
2024-04-28 18:50:00,330 - web_server - INFO - Passed runtime parameters: {}
2024-04-28 18:50:00,331 - web_server - INFO -  >> Setting input data dict
2024-04-28 18:50:00,331 - web_server - INFO - Setting up needed data
2024-04-28 18:50:00,339 - web_server - INFO -  >> Publishing data...
2024-04-28 18:50:00,339 - web_server - INFO - Publishing data to HASS instance
2024-04-28 18:50:00,371 - web_server - INFO - Successfully posted to sensor.p_pv_forecast = 1104.25
2024-04-28 18:50:00,374 - web_server - INFO - Successfully posted to sensor.p_load_forecast = 729.69
2024-04-28 18:50:00,377 - web_server - INFO - Successfully posted to sensor.p_deferrable0 = 0.0
2024-04-28 18:50:00,379 - web_server - INFO - Successfully posted to sensor.p_batt_forecast = 0.0
2024-04-28 18:50:00,382 - web_server - INFO - Successfully posted to sensor.soc_batt_forecast = 100.0
2024-04-28 18:50:00,384 - web_server - INFO - Successfully posted to sensor.p_grid_forecast = -374.56
2024-04-28 18:50:00,387 - web_server - INFO - Successfully posted to sensor.total_cost_fun_value = -12.6
2024-04-28 18:50:00,389 - web_server - INFO - Successfully posted to sensor.optim_status = Optimal
2024-04-28 18:50:00,392 - web_server - INFO - Successfully posted to sensor.unit_load_cost = 20.0145
2024-04-28 18:50:00,394 - web_server - INFO - Successfully posted to sensor.unit_prod_price = 5.335
2024-04-28 19:00:00,134 - web_server - INFO - Passed runtime parameters: {}
2024-04-28 19:00:00,134 - web_server - INFO -  >> Setting input data dict
2024-04-28 19:00:00,134 - web_server - INFO - Setting up needed data
2024-04-28 19:00:00,140 - web_server - INFO -  >> Publishing data...
2024-04-28 19:00:00,140 - web_server - INFO - Publishing data to HASS instance
2024-04-28 19:00:00,159 - web_server - INFO - Successfully posted to sensor.p_pv_forecast = 1104.25
2024-04-28 19:00:00,162 - web_server - INFO - Successfully posted to sensor.p_load_forecast = 729.69
2024-04-28 19:00:00,164 - web_server - INFO - Successfully posted to sensor.p_deferrable0 = 0.0
2024-04-28 19:00:00,167 - web_server - INFO - Successfully posted to sensor.p_batt_forecast = 0.0
2024-04-28 19:00:00,170 - web_server - INFO - Successfully posted to sensor.soc_batt_forecast = 100.0
2024-04-28 19:00:00,173 - web_server - INFO - Successfully posted to sensor.p_grid_forecast = -374.56
2024-04-28 19:00:00,176 - web_server - INFO - Successfully posted to sensor.total_cost_fun_value = -12.6
2024-04-28 19:00:00,178 - web_server - INFO - Successfully posted to sensor.optim_status = Optimal
2024-04-28 19:00:00,181 - web_server - INFO - Successfully posted to sensor.unit_load_cost = 20.0145
2024-04-28 19:00:00,183 - web_server - INFO - Successfully posted to sensor.unit_prod_price = 5.335
2024-04-28 19:00:00,277 - web_server - INFO - Passed runtime parameters: {}
2024-04-28 19:00:00,278 - web_server - INFO -  >> Setting input data dict
2024-04-28 19:00:00,278 - web_server - INFO - Setting up needed data
2024-04-28 19:00:00,279 - web_server - INFO -  >> Publishing data...
2024-04-28 19:00:00,279 - web_server - INFO - Publishing data to HASS instance
2024-04-28 19:00:00,286 - web_server - INFO - Successfully posted to sensor.p_pv_forecast = 1104.25
2024-04-28 19:00:00,289 - web_server - INFO - Successfully posted to sensor.p_load_forecast = 729.69
2024-04-28 19:00:00,292 - web_server - INFO - Successfully posted to sensor.p_deferrable0 = 0.0
2024-04-28 19:00:00,294 - web_server - INFO - Successfully posted to sensor.p_batt_forecast = 0.0
2024-04-28 19:00:00,297 - web_server - INFO - Successfully posted to sensor.soc_batt_forecast = 100.0
2024-04-28 19:00:00,300 - web_server - INFO - Successfully posted to sensor.p_grid_forecast = -374.56
2024-04-28 19:00:00,302 - web_server - INFO - Successfully posted to sensor.total_cost_fun_value = -12.6
2024-04-28 19:00:00,304 - web_server - INFO - Successfully posted to sensor.optim_status = Optimal
2024-04-28 19:00:00,307 - web_server - INFO - Successfully posted to sensor.unit_load_cost = 20.0145
2024-04-28 19:00:00,309 - web_server - INFO - Successfully posted to sensor.unit_prod_price = 5.335
2024-04-28 19:10:00,282 - web_server - INFO - Passed runtime parameters: {}
2024-04-28 19:10:00,283 - web_server - INFO -  >> Setting input data dict
2024-04-28 19:10:00,283 - web_server - INFO - Setting up needed data
2024-04-28 19:10:00,288 - web_server - INFO -  >> Publishing data...
2024-04-28 19:10:00,288 - web_server - INFO - Publishing data to HASS instance
2024-04-28 19:10:00,305 - web_server - INFO - Successfully posted to sensor.p_pv_forecast = 1104.25
2024-04-28 19:10:00,308 - web_server - INFO - Successfully posted to sensor.p_load_forecast = 729.69
2024-04-28 19:10:00,310 - web_server - INFO - Successfully posted to sensor.p_deferrable0 = 0.0
2024-04-28 19:10:00,313 - web_server - INFO - Successfully posted to sensor.p_batt_forecast = 0.0
2024-04-28 19:10:00,316 - web_server - INFO - Successfully posted to sensor.soc_batt_forecast = 100.0
2024-04-28 19:10:00,319 - web_server - INFO - Successfully posted to sensor.p_grid_forecast = -374.56
2024-04-28 19:10:00,322 - web_server - INFO - Successfully posted to sensor.total_cost_fun_value = -12.6
2024-04-28 19:10:00,324 - web_server - INFO - Successfully posted to sensor.optim_status = Optimal
2024-04-28 19:10:00,326 - web_server - INFO - Successfully posted to sensor.unit_load_cost = 20.0145
2024-04-28 19:10:00,329 - web_server - INFO - Successfully posted to sensor.unit_prod_price = 5.335

The passed runtime parameters remain empty now?
SOC Graph is like here below