EMHASS: An Energy Management for Home Assistant

Different question now. When I don’t get much EV charging during the day I can see the p_def0 forecast generate blocks of charging in the ‘off peak’ energy price time. This is good. However each time I hit the “leading edge” of one of these blocks of night time charging, the MPC optimiser run changes p_def0 from 13.5kW to -900W and essentially these night time blocks of charging never happen. Example picture below.

Here is my MPC call

post_mpc_optim: 'curl -i -H "Content-Type: application/json" -X POST -d ''{
"load_power_forecast":{{state_attr(''sensor.p_load_forecast_custom_model'', ''forecasts'') | map(attribute=''p_load_forecast_custom_model'') | map(''int'') | list}}, 
"load_cost_forecast":{{(state_attr(''input_text.load_cost_tariff'', ''rates''))}}, 
"pv_power_forecast":{{[states(''sensor.apf_generation_entity'')|int(0)] + state_attr(''sensor.solcast_forecast_today'', ''detailedForecast'')|selectattr(''period_start'',''gt'',utcnow()) | map(attribute=''pv_estimate'')|map(''multiply'',2000)|map(''int'')|list  + state_attr(''sensor.solcast_forecast_tomorrow'', ''detailedForecast'')|selectattr(''period_start'',''gt'',utcnow()) | map(attribute=''pv_estimate'')|map(''multiply'',2000)|map(''int'')|list}}, "prediction_horizon":48, "alpha":1, "beta":0, 
"soc_init":{{states(''sensor.powerwall_charge'')|float(0)/100}}, 
"soc_final":0.05, 
"def_total_hours":[{{states(''sensor.def_total_hours_ev'')}}]}'' http://localhost:5000/action/naive-mpc-optim'

Is it because the pv_power_forecast is 0 in the night time?

Is there a hard-coded max horizon for naive-mpc-optim?

Quick question,
I have a 5 year old sonnen battery that doesn’t go below about 10% usable charge (16% actual charge). I assume this is battery degradation due to age.
Should soc_final in the MPC call be set to 0.1? Currently set to 0.05!
Also, should I use the usable battery state or the actual battery state in EMHASS?

"soc_init":{{(states('sensor.sonnenbatterie_XXXXX_state_charge_user')|float(0))/100
        }},"soc_final":0.05,"def_total_hours":[2]}

Thanks

You can specify

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

It shouldn’t have anything to do your your PV =0 overnight.

What I suspect is occurring is as the 30 minute timeslot starts, another one appears 24 hours in the future (especially if the prices in 24 hours are lower) so it defers starting. I would recommend you add maybe one or two additional hours to your def_hours which should force the charging to start on the off-peak window.

You should probably set the minimum SOC in the configuration menu:

soc_final really just effects the last 90 minutes or so, I set it low so the optimisation doesn’t try to charge madly, so probably just set it to your minimum SOC.

usable battery or actually battery state, I haven’t come across. I would suspect as long as you are consistent it should work either way.

1 Like

Mark, I think you are definitely on to something there. Have upped the def_hours and will report back.

Long time ago we talked about my pool coming on line. That is finally happening in 4 weeks. Can you remind me how you set your filtration pumps and heat pump up?

Can somebody help me why I’m getting this error:

shell_command:
trigger_nordpool_mpc: “curl -i -H “Content-Type: application/json” -X POST -d ‘{“load_cost_forecast”:{{((state_attr(‘sensor.nordpool_kwh_nl_eur_3_09_0’, ‘raw_today’) | map(attribute=‘value’) | list + state_attr(‘sensor.nordpool_kwh_nl_eur_3_09_0’, ‘raw_tomorrow’) | map(attribute=‘value’) | list))[now().hour:][:24] }},“prod_price_forecast”:{{((state_attr(‘sensor.nordpool_kwh_nl_eur_3_09_0’, ‘raw_today’) | map(attribute=‘value’) | list + state_attr(‘sensor.nordpool_kwh_nl_eur_3_09_0’, ‘raw_tomorrow’) | map(attribute=‘value’) | list))[now().hour:][:24]}}, “prediction_horizon”:6, “def_total_hours”:[2,4]}’ http://localhost:5000/action/naive-mpc-optim

Logging EMHASS:
2023-07-25 18:57:33,935 - web_server - INFO - Setting up needed data
2023-07-25 18:57:33,959 - web_server - INFO - Retrieve hass get data method initiated…
2023-07-25 18:57:34,236 - web_server - ERROR - The retrieved JSON is empty, check that correct day or variable names are passed
2023-07-25 18:57:34,236 - web_server - ERROR - Either the names of the passed variables are not correct or days_to_retrieve is larger than the recorded history of your sensor (check your recorder settings)
2023-07-25 18:57:34,263 - web_server - ERROR - The retrieved JSON is empty, check that correct day or variable names are passed
2023-07-25 18:57:34,263 - web_server - ERROR - Either the names of the passed variables are not correct or days_to_retrieve is larger than the recorded history of your sensor (check your recorder settings)
2023-07-25 18:57:34,269 - web_server - ERROR - Exception on /action/naive-mpc-optim [POST]
Traceback (most recent call last):
File “/usr/local/lib/python3.9/dist-packages/flask/app.py”, line 2190, in wsgi_app
response = self.full_dispatch_request()
File “/usr/local/lib/python3.9/dist-packages/flask/app.py”, line 1486, in full_dispatch_request
rv = self.handle_user_exception(e)
File “/usr/local/lib/python3.9/dist-packages/flask/app.py”, line 1484, in full_dispatch_request
rv = self.dispatch_request()
File “/usr/local/lib/python3.9/dist-packages/flask/app.py”, line 1469, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
File “/usr/local/lib/python3.9/dist-packages/emhass/web_server.py”, line 174, in action_call
input_data_dict = set_input_data_dict(config_path, str(data_path), costfun,
File “/usr/local/lib/python3.9/dist-packages/emhass/command_line.py”, line 112, in set_input_data_dict
rh.prepare_data(retrieve_hass_conf[‘var_load’], load_negative = retrieve_hass_conf[‘load_negative’],
File “/usr/local/lib/python3.9/dist-packages/emhass/retrieve_hass.py”, line 208, in prepare_data
self.df_final[new_var_replace_zero] = self.df_final[new_var_replace_zero].fillna(0.0)
File “/usr/local/lib/python3.9/dist-packages/pandas/core/frame.py”, line 3511, in getitem
indexer = self.columns._get_indexer_strict(key, “columns”)[1]
File “/usr/local/lib/python3.9/dist-packages/pandas/core/indexes/base.py”, line 5782, in _get_indexer_strict
self._raise_if_missing(keyarr, indexer, axis_name)
File “/usr/local/lib/python3.9/dist-packages/pandas/core/indexes/base.py”, line 5842, in _raise_if_missing
raise KeyError(f"None of [{key}] are in the [{axis_name}]")
KeyError: “None of [Index([‘sensor.solaredge_ac_power_output’], dtype=‘object’)] are in the [columns]”

Configuration:
hass_url: empty
long_lived_token: empty
costfun: profit
logging_level: DEBUG
optimization_time_step: 60
historic_days_to_retrieve: 2
method_ts_round: first
set_total_pv_sell: false
lp_solver: COIN_CMD
lp_solver_path: /usr/bin/cbc
set_nocharge_from_grid: false
set_nodischarge_to_grid: false
set_battery_dynamic: false
battery_dynamic_max: 0.9
battery_dynamic_min: -0.9
load_forecast_method: naive
sensor_power_photovoltaics: sensor.solaredge_ac_power_output
sensor_power_load_no_var_loads: sensor.house_usage_in_watt
number_of_deferrable_loads: 2
list_nominal_power_of_deferrable_loads:

  • nominal_power_of_deferrable_loads: 1200
  • nominal_power_of_deferrable_loads: 10800
    list_operating_hours_of_each_deferrable_load:
  • operating_hours_of_each_deferrable_load: 2
  • operating_hours_of_each_deferrable_load: 4
    list_peak_hours_periods_start_hours:
  • peak_hours_periods_start_hours: “02:54”
  • peak_hours_periods_start_hours: “17:24”
    list_peak_hours_periods_end_hours:
  • peak_hours_periods_end_hours: “15:24”
  • peak_hours_periods_end_hours: “20:24”
    list_treat_deferrable_load_as_semi_cont:
  • treat_deferrable_load_as_semi_cont: false
  • treat_deferrable_load_as_semi_cont: false
    load_peak_hours_cost: 0.1907
    load_offpeak_hours_cost: 0.1419
    photovoltaic_production_sell_price: 0.065
    maximum_power_from_grid: 17250
    list_pv_module_model:
  • pv_module_model: Jinko_Solar_Co___Ltd_JKM410M_72HL
    list_pv_inverter_model:
  • pv_inverter_model: SolarEdge_Technologies_Ltd___SE9K__208V_
    list_surface_tilt:
  • surface_tilt: 45
    list_surface_azimuth:
  • surface_azimuth: 210
    list_modules_per_string:
  • modules_per_string: 26
    list_strings_per_inverter:
  • strings_per_inverter: 1
    set_use_battery: true
    battery_discharge_power_max: 3300
    battery_charge_power_max: 3300
    battery_discharge_efficiency: 0.95
    battery_charge_efficiency: 0.95
    battery_nominal_energy_capacity: 15000
    battery_minimum_state_of_charge: 0.3
    battery_maximum_state_of_charge: 0.8
    battery_target_state_of_charge: 0.8

Many thanks in advance

I need som help with mlforecast. Emhass addon gives error about “All arrays must be of the same length” when I run dayahead-optim when I use load forecast method “mlforecaster”.

2023-07-24 22:07:59,185 - web_server - INFO - The data path is: /share
2023-07-24 22:07:59,186 - web_server - INFO - Using core emhass version: 0.4.14
waitress   INFO  Serving on http://0.0.0.0:5000
2023-07-24 22:08:03,444 - web_server - INFO - Setting up needed data
2023-07-24 22:08:03,471 - web_server - INFO - Retrieving weather forecast data using method = scrapper
2023-07-24 22:08:05,384 - web_server - INFO - Retrieving data from hass for load forecast using method = mlforecaster
2023-07-24 22:08:05,385 - web_server - INFO - Retrieve hass get data method initiated...
2023-07-24 22:08:07,717 - web_server - ERROR - Exception on /action/dayahead-optim [POST]
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/dist-packages/flask/app.py", line 2190, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/local/lib/python3.9/dist-packages/flask/app.py", line 1486, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/usr/local/lib/python3.9/dist-packages/flask/app.py", line 1484, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python3.9/dist-packages/flask/app.py", line 1469, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
  File "/usr/local/lib/python3.9/dist-packages/emhass/web_server.py", line 174, in action_call
    input_data_dict = set_input_data_dict(config_path, str(data_path), costfun,
  File "/usr/local/lib/python3.9/dist-packages/emhass/command_line.py", line 91, in set_input_data_dict
    P_load_forecast = fcst.get_load_forecast(method=optim_conf['load_forecast_method'])
  File "/usr/local/lib/python3.9/dist-packages/emhass/forecast.py", line 620, in get_load_forecast
    data = pd.DataFrame.from_dict(data_dict)
  File "/usr/local/lib/python3.9/dist-packages/pandas/core/frame.py", line 1677, in from_dict
    return cls(data, index=index, columns=columns, dtype=dtype)
  File "/usr/local/lib/python3.9/dist-packages/pandas/core/frame.py", line 636, in __init__
    mgr = dict_to_mgr(data, index, columns, dtype=dtype, copy=copy, typ=manager)
  File "/usr/local/lib/python3.9/dist-packages/pandas/core/internals/construction.py", line 502, in dict_to_mgr
    return arrays_to_mgr(arrays, columns, index, dtype=dtype, typ=typ, consolidate=copy)
  File "/usr/local/lib/python3.9/dist-packages/pandas/core/internals/construction.py", line 120, in arrays_to_mgr
    index = _extract_index(arrays)
  File "/usr/local/lib/python3.9/dist-packages/pandas/core/internals/construction.py", line 674, in _extract_index
    raise ValueError("All arrays must be of the same length")
ValueError: All arrays must be of the same length

When I use “naive” as load forecast method I do not have any errors:

s6-rc: info: service s6rc-oneshot-runner: starting
s6-rc: info: service s6rc-oneshot-runner successfully started
s6-rc: info: service fix-attrs: starting
s6-rc: info: service fix-attrs successfully started
s6-rc: info: service legacy-cont-init: starting
s6-rc: info: service legacy-cont-init successfully started
s6-rc: info: service legacy-services: starting
services-up: info: copying legacy longrun emhass (no readiness notification)
s6-rc: info: service legacy-services successfully started
2023-07-24 22:10:12,784 - web_server - INFO - Launching the emhass webserver at: http://0.0.0.0:5000
2023-07-24 22:10:12,784 - web_server - INFO - Home Assistant data fetch will be performed using url: http://supervisor/core/api
2023-07-24 22:10:12,784 - web_server - INFO - The data path is: /share
2023-07-24 22:10:12,785 - web_server - INFO - Using core emhass version: 0.4.14
waitress   INFO  Serving on http://0.0.0.0:5000
2023-07-24 22:10:16,701 - web_server - INFO - Setting up needed data
2023-07-24 22:10:16,722 - web_server - INFO - Retrieving weather forecast data using method = scrapper
2023-07-24 22:10:18,520 - web_server - INFO - Retrieving data from hass for load forecast using method = naive
2023-07-24 22:10:18,521 - web_server - INFO - Retrieve hass get data method initiated...
2023-07-24 22:10:20,967 - web_server - INFO -  >> Performing dayahead optimization...
2023-07-24 22:10:20,967 - web_server - INFO - Performing day-ahead forecast optimization
2023-07-24 22:10:20,976 - web_server - INFO - Perform optimization for the day-ahead
2023-07-24 22:10:21,073 - web_server - INFO - Status: Optimal
2023-07-24 22:10:21,073 - web_server - INFO - Total value of the Cost function = -63.34

I use nordpool as source for “load_cost_forecast” and “prod_price_forecast”. Nordpool integration publish 24 hour price data (price for every hour).

I use this shell_command for setting up mlforecast with num_lags: 24 because the time step is 1 hour:

# I run this first. It gives no errors. Using default mlforecast config.
shell_command:
  ml_forecast_fit: "curl -i -H \"Content-Type:application/json\" -X POST -d '{\"num_lags\": 24}' http://localhost:5000/action/forecast-model-fit"

# Then I run this after. It gives no errors.
  ml_forecast_tune: "curl -i -H \"Content-Type:application/json\" -X POST -d '{\"num_lags\": 24}' http://localhost:5000/action/forecast-model-tune"

I run dayahead-optim each day at 13:55. Nordpool publish prices every day at 13:15

shell_command:
  trigger_nordpool_forecast: "curl -i -H \"Content-Type: application/json\" -X POST -d '{
    \"load_cost_forecast\":{{((state_attr('sensor.nordpool', 'raw_today') | map(attribute='value') | list  + state_attr('sensor.nordpool', 'raw_tomorrow') | map(attribute='value') | list))[now().hour:][:24] }},
    \"prod_price_forecast\":{{((state_attr('sensor.nordpool_uten_avgifter', 'raw_today') | map(attribute='value') | list  + state_attr('sensor.nordpool_uten_avgifter', 'raw_tomorrow') | map(attribute='value') | list))[now().hour:][:24]}},
    \"def_total_hours\":{{states('sensor.list_operating_hours_of_each_deferrable_load')}}
    }' http://localhost:5000/action/dayahead-optim"

Here is my emhass config:

root@5b918bf2-emhass:/data# cat options.json
{
  "hass_url": "empty",
  "long_lived_token": "empty",
  "costfun": "profit",
  "logging_level": "INFO",
  "optimization_time_step": 60,
  "historic_days_to_retrieve": 2,
  "method_ts_round": "nearest",
  "set_total_pv_sell": false,
  "lp_solver": "COIN_CMD",
  "lp_solver_path": "/usr/bin/cbc",
  "set_nocharge_from_grid": false,
  "set_nodischarge_to_grid": false,
  "set_battery_dynamic": false,
  "battery_dynamic_max": 0.9,
  "battery_dynamic_min": -0.9,
  "load_forecast_method": "naive",      # I change this setting to "mlforecaster" when I try to use mlforecast
  "sensor_power_photovoltaics": "sensor.ecu_current_power",
  "sensor_power_load_no_var_loads": "sensor.power_load_no_var_loads",
  "number_of_deferrable_loads": 7,
  "list_nominal_power_of_deferrable_loads": [
    {
      "nominal_power_of_deferrable_loads": 1948
    },
    {
      "nominal_power_of_deferrable_loads": 7230
    },
    {
      "nominal_power_of_deferrable_loads": 1408
    },
    {
      "nominal_power_of_deferrable_loads": 640
    },
    {
      "nominal_power_of_deferrable_loads": 900
    },
    {
      "nominal_power_of_deferrable_loads": 895
    },
    {
      "nominal_power_of_deferrable_loads": 5517
    }
  ],
  "list_operating_hours_of_each_deferrable_load": [
    {
      "operating_hours_of_each_deferrable_load": 5
    },
    {
      "operating_hours_of_each_deferrable_load": 4
    },
    {
      "operating_hours_of_each_deferrable_load": 4
    },
    {
      "operating_hours_of_each_deferrable_load": 4
    },
    {
      "operating_hours_of_each_deferrable_load": 4
    },
    {
      "operating_hours_of_each_deferrable_load": 4
    },
    {
      "operating_hours_of_each_deferrable_load": 6
    }
  ],
  "list_peak_hours_periods_start_hours": [
    {
      "peak_hours_periods_start_hours": "06:00"
    }
  ],
  "list_peak_hours_periods_end_hours": [
    {
      "peak_hours_periods_end_hours": "22:00"
    }
  ],
  "list_treat_deferrable_load_as_semi_cont": [
    {
      "treat_deferrable_load_as_semi_cont": true
    },
    {
      "treat_deferrable_load_as_semi_cont": true
    },
    {
      "treat_deferrable_load_as_semi_cont": true
    },
    {
      "treat_deferrable_load_as_semi_cont": true
    },
    {
      "treat_deferrable_load_as_semi_cont": true
    },
    {
      "treat_deferrable_load_as_semi_cont": true
    },
    {
      "treat_deferrable_load_as_semi_cont": true
    }
  ],
  "load_peak_hours_cost": 0.1907,
  "load_offpeak_hours_cost": 0.1419,
  "photovoltaic_production_sell_price": 0.065,
  "maximum_power_from_grid": 5310,
  "list_pv_module_model": [
    {
      "pv_module_model": "REC_Solar_REC295TP2"
    },
    {
      "pv_module_model": "REC_Solar_REC295TP2"
    },
    {
      "pv_module_model": "REC_Solar_REC295TP2"
    },
    {
      "pv_module_model": "REC_Solar_REC295TP2"
    },
    {
      "pv_module_model": "REC_Solar_REC295TP2"
    },
    {
      "pv_module_model": "REC_Solar_REC295TP2"
    },
    {
      "pv_module_model": "REC_Solar_REC295TP2"
    },
    {
      "pv_module_model": "REC_Solar_REC295TP2"
    },
    {
      "pv_module_model": "REC_Solar_REC295TP2"
    },
    {
      "pv_module_model": "REC_Solar_REC295TP2"
    },
    {
      "pv_module_model": "REC_Solar_REC295TP2"
    },
    {
      "pv_module_model": "REC_Solar_REC295TP2"
    },
    {
      "pv_module_model": "REC_Solar_REC295TP2"
    },
    {
      "pv_module_model": "REC_Solar_REC295TP2"
    },
    {
      "pv_module_model": "REC_Solar_REC295TP2"
    },
    {
      "pv_module_model": "REC_Solar_REC295TP2"
    },
    {
      "pv_module_model": "REC_Solar_REC295TP2"
    },
    {
      "pv_module_model": "REC_Solar_REC295TP2"
    }
  ],
  "list_pv_inverter_model": [
    {
      "pv_inverter_model": "Altenergy_Power_System_Inc___QS1__240V_"
    },
    {
      "pv_inverter_model": "Altenergy_Power_System_Inc___QS1__240V_"
    },
    {
      "pv_inverter_model": "Altenergy_Power_System_Inc___QS1__240V_"
    },
    {
      "pv_inverter_model": "Altenergy_Power_System_Inc___QS1__240V_"
    },
    {
      "pv_inverter_model": "Altenergy_Power_System_Inc___QS1__240V_"
    },
    {
      "pv_inverter_model": "Altenergy_Power_System_Inc___QS1__240V_"
    },
    {
      "pv_inverter_model": "Altenergy_Power_System_Inc___QS1__240V_"
    },
    {
      "pv_inverter_model": "Altenergy_Power_System_Inc___QS1__240V_"
    },
    {
      "pv_inverter_model": "Altenergy_Power_System_Inc___QS1__240V_"
    },
    {
      "pv_inverter_model": "Altenergy_Power_System_Inc___QS1__240V_"
    },
    {
      "pv_inverter_model": "Altenergy_Power_System_Inc___QS1__240V_"
    },
    {
      "pv_inverter_model": "Altenergy_Power_System_Inc___QS1__240V_"
    },
    {
      "pv_inverter_model": "Altenergy_Power_System_Inc___QS1__240V_"
    },
    {
      "pv_inverter_model": "Altenergy_Power_System_Inc___QS1__240V_"
    },
    {
      "pv_inverter_model": "Altenergy_Power_System_Inc___QS1__240V_"
    },
    {
      "pv_inverter_model": "Altenergy_Power_System_Inc___QS1__240V_"
    },
    {
      "pv_inverter_model": "Altenergy_Power_System_Inc___QS1__240V_"
    },
    {
      "pv_inverter_model": "Altenergy_Power_System_Inc___YC600__240V_"
    }
  ],
  "list_surface_tilt": [
    {
      "surface_tilt": 38
    },
    {
      "surface_tilt": 38
    },
    {
      "surface_tilt": 38
    },
    {
      "surface_tilt": 38
    },
    {
      "surface_tilt": 38
    },
    {
      "surface_tilt": 38
    },
    {
      "surface_tilt": 38
    },
    {
      "surface_tilt": 38
    },
    {
      "surface_tilt": 38
    },
    {
      "surface_tilt": 38
    },
    {
      "surface_tilt": 38
    },
    {
      "surface_tilt": 38
    },
    {
      "surface_tilt": 41
    },
    {
      "surface_tilt": 41
    },
    {
      "surface_tilt": 41
    },
    {
      "surface_tilt": 41
    },
    {
      "surface_tilt": 41
    },
    {
      "surface_tilt": 41
    }
  ],
  "list_surface_azimuth": [
    {
      "surface_azimuth": 225
    },
    {
      "surface_azimuth": 225
    },
    {
      "surface_azimuth": 225
    },
    {
      "surface_azimuth": 225
    },
    {
      "surface_azimuth": 225
    },
    {
      "surface_azimuth": 225
    },
    {
      "surface_azimuth": 225
    },
    {
      "surface_azimuth": 225
    },
    {
      "surface_azimuth": 225
    },
    {
      "surface_azimuth": 225
    },
    {
      "surface_azimuth": 225
    },
    {
      "surface_azimuth": 225
    },
    {
      "surface_azimuth": 225
    },
    {
      "surface_azimuth": 225
    },
    {
      "surface_azimuth": 225
    },
    {
      "surface_azimuth": 225
    },
    {
      "surface_azimuth": 225
    },
    {
      "surface_azimuth": 225
    }
  ],
  "list_modules_per_string": [
    {
      "modules_per_string": 1
    },
    {
      "modules_per_string": 1
    },
    {
      "modules_per_string": 1
    },
    {
      "modules_per_string": 1
    },
    {
      "modules_per_string": 1
    },
    {
      "modules_per_string": 1
    },
    {
      "modules_per_string": 1
    },
    {
      "modules_per_string": 1
    },
    {
      "modules_per_string": 1
    },
    {
      "modules_per_string": 1
    },
    {
      "modules_per_string": 1
    },
    {
      "modules_per_string": 1
    },
    {
      "modules_per_string": 1
    },
    {
      "modules_per_string": 1
    },
    {
      "modules_per_string": 1
    },
    {
      "modules_per_string": 1
    },
    {
      "modules_per_string": 1
    },
    {
      "modules_per_string": 1
    }
  ],
  "list_strings_per_inverter": [
    {
      "strings_per_inverter": 1
    },
    {
      "strings_per_inverter": 1
    },
    {
      "strings_per_inverter": 1
    },
    {
      "strings_per_inverter": 1
    },
    {
      "strings_per_inverter": 1
    },
    {
      "strings_per_inverter": 1
    },
    {
      "strings_per_inverter": 1
    },
    {
      "strings_per_inverter": 1
    },
    {
      "strings_per_inverter": 1
    },
    {
      "strings_per_inverter": 1
    },
    {
      "strings_per_inverter": 1
    },
    {
      "strings_per_inverter": 1
    },
    {
      "strings_per_inverter": 1
    },
    {
      "strings_per_inverter": 1
    },
    {
      "strings_per_inverter": 1
    },
    {
      "strings_per_inverter": 1
    },
    {
      "strings_per_inverter": 1
    },
    {
      "strings_per_inverter": 1
    }
  ],
  "set_use_battery": 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

I decided to setup Emhass - my setup:

  • 15kwh / 8kva battery
  • dynamic pricing (nordpool)
  • 1 deferable load (EV)
  • 2 arrays of solar panels, 4700wp east / south east; 2400 wp south / south west

Decided to start with optimizing the battery, would prefer to not use any deferable load to keep things simple and for the time being would also like to keep the PV out of the config. Is that possible? Specifically working without deferable loads and only optimize the battery for profit?

Leaves me with 3 (stupid?) questions:

  • where can I find the config files which are referenced? I run HA OS with the add on
  • when I submit the nordpool data I get an error in Emhass which to me does not make much sense as it suggest the list needs to have 24 items and indicates the list has 24 items (I changed the time step to 60 minutes as that would seem sufficient with hourly prices):
2023-07-25 22:02:50,798 - web_server - ERROR - ERROR: The passed data is either not a list or the length is not correct, length should be 24
2023-07-25 22:02:50,798 - web_server - ERROR - Passed type is <class 'list'> and length is 24
  • the household load, is it sufficient to just template the consumption sensor -/- the deferable load or should I also deduct the production sensor (positive when returning to grid)? Eg. should load be negative when feeding the grid or 0?

Take your shell_command and past it into the template editor in developer tools in Home Assistant. Then revers engineer the output and make sure the number of elements in the arrays correlate or are not longer than the [:24] array length. Extract each section and review them separatly. Or there are missing elements like solar forecast list.
That’s my guess.

shell_command:
trigger_nordpool_mpc: “curl -i -H “Content-Type: application/json” -X POST -d ‘

{“load_cost_forecast”:

{{((state_attr(‘sensor.nordpool_kwh_nl_eur_3_09_0’, ‘raw_today’) | map(attribute=‘value’) | list + state_attr(‘sensor.nordpool_kwh_nl_eur_3_09_0’, ‘raw_tomorrow’) | map(attribute=‘value’) | list))[now().hour:][:24] }},

“prod_price_forecast”:

{{((state_attr(‘sensor.nordpool_kwh_nl_eur_3_09_0’, ‘raw_today’) | map(attribute=‘value’) | list + state_attr(‘sensor.nordpool_kwh_nl_eur_3_09_0’, ‘raw_tomorrow’) | map(attribute=‘value’) | list))[now().hour:][:24]}}, 

“prediction_horizon”:6, “def_total_hours”:[2,4]}

’ http://localhost:5000/action/naive-mpc-optim”

you should see something like this:

If you past the result from the template editor back into this forum somebody that understands Jinja2 and nordpool data better than me might be able to help.

Also you need to past any code or logs in Preformatted Text format in this forum. Use the </> icon above and past test in between the ``` marks like this:

Logs and code here

Just makes it easier to read.

1 Like

I have an outdoor Deta 10A double socket that run my filter/ chlorinator pump and my heat pump flow pump, which I use with localtuya for both switching and power consumption monitoring.

My three phase heat pump draws about 4 kW and my filter pump draws about 1.4 kW, so I have these setup as separate deferrable loads in EMHASS. I have heater def_hours setup to match the number of extremly_low (<5 c/ kWh) times during the day. I have my filter pump def_hours setup to match the solar production, so it runs longer in summer and shorter in winter.

Ideally you would get a heat pump with a DRED interface which would allow you to control the power consumption, but despite a lot of talk I haven’t been able to identify any.

My filter pump needs to run as high speed as it also runs my pool vacuum, which means the power consumption is quite high. If you only need to run filtration you can get a multi speed pump that can do the bulk of the heavy lifting at low speed/ power.

Mark, thanks for the info. I don’t see the pool temp in the calculation of def_hours for the heat pump. Is this because you don’t have a temp sensor in HA?

The emhass referenced file is the options.json file in the emhass addon data directory. You only need to gain access to the emhass Docker container and change directory to /data:

  1. Install community “SSH & Web Terminal” addon (not the official “Terminal & SSH” addon!) and configure your credentials. Note: the addon will fail to start if you use an insecure password so it’s better to configure it with public key authentication.
  2. Disable “Protection mode” in the addon’s configuration.
  3. At the shell, log into the main Home Assistant Docker container like this:
docker exec -it addon_5b918bf2_emhass bash

You need to know either the container id or name of the addon. You can use this docker command for getting the name or id:

docker ps -a

Change directory to data and read the options.json file with the command cat more:

root@5b918bf2-emhass:/data# cd data/
root@5b918bf2-emhass:/data# more options.json
or 
root@5b918bf2-emhass:/data# cat options.json
1 Like

When you use the nordpool intergration you need to use time step 60 minutes because nordpool have 24 hour prices publised.
image
You can look at my config here: EMHASS: An Energy Management for Home Assistant - #1017 by haraldov

But you get this error also when you have less than 2 days recorded sensor.power_load_no_var_loads data:
image
The minimum recorded data is two days:
image

Here is my template for sensor.power_load_no_var_loads:

template:
  - sensor:
      - name: "Power load no var loads"
        unique_id: fbfeef21-1aa3-4a54-b781-426f46fef597
        unit_of_measurement: W
        device_class: power
        state: >
          {% set powerload = states('sensor.power_adresse') | float(default=0) %}
          {% set ecupower = states('sensor.ecu_current_power') | float(default=0) %}
          {% set vkbad1etg = states('sensor.varmekabel_bad1etg_electric_consumption_w') | float(default=0) %}
          {% set vkbad2etg = states('sensor.varmekabel_bad2etg_electric_consumption_w') | float(default=0) %}
          {% set vkgang = states('sensor.varmekabel_gang_electric_consumption_w') | float(default=0) %}
          {% set vkgmlstue = states('sensor.varmekabel_gmlstue_electric_consumption_w') | float(default=0) %}
          {% set vknystue = states('sensor.varmekabel_nystue_electric_consumption_w') | float(default=0) %}
          {% set vkkjokken = states('sensor.varmekabel_kjokken_electric_consumption_w') | float(default=0) %}
          {% set vvb = states('sensor.bryter_varmvannsbereder_electric_consumption_w') | float(default=0) %}
          {% set varmepumpe = states('sensor.strombryter_varmepumpe_electric_consumption_w') | float(default=0) %}
          {% set easee = states('sensor.easee_home_number_power') | float(default=0) %}
          {% set value = ((powerload + ecupower)- vkbad1etg - vkbad2etg - vkgang - vkgmlstue - vknystue - vkkjokken - vvb - varmepumpe - easee) | round(1,default=0) %}
          {% if value < 0.0  %}
            {{ 0.0 }}
          {% else %}
            {{ value }}
          {% endif %} 
1 Like

You should template consumption sensor in Watt minus the deferable load in Watt https://emhass.readthedocs.io/en/latest/intro.html#passing-your-own-data.

In my template I add the pv production (ecupower) plus the grid import sensor (powerload) and substract the deferable load in my house. I now sure this is the correct way to do it, but it works.

{% set value = ((powerload + ecupower)- vkbad1etg - vkbad2etg - vkgang - vkgmlstue - vknystue - vkkjokken - vvb - varmepumpe - easee) | round(1,default=0) %}
          {% if value < 0.0  %}
1 Like

Thanks, I set the resolution to 60minutes, but indeed my template was created yesterday evening. Will wait 2 days!

1 Like

These are great instructions for debugging and going inside the docker container to see what is going on and like you said retrieve the options.json file if you want to check whats inside it.

However if you are using the add-on there is no need to do all this, just set your parameters to configure your system in the add-on configuration pane and that’s all. The add-on will internally create that options.json file and use it to run the calculations. As a user you can just stay with the web UI on the add-on a it should work fine with no need to use the SSH and Web Terminal (which is great) and to meddle with the Docker containers.

1 Like

EMHASS config for sonnen users

3 Likes

Anybody understand what these errors mean?

2023-07-28 16:42:20,021 - web_server - INFO - Retrieve hass get data method initiated...
2023-07-28 16:42:20,654 - web_server - ERROR - Exception on /action/naive-mpc-optim [POST]
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/dist-packages/flask/app.py", line 2190, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/local/lib/python3.9/dist-packages/flask/app.py", line 1486, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/usr/local/lib/python3.9/dist-packages/flask/app.py", line 1484, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python3.9/dist-packages/flask/app.py", line 1469, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
  File "/usr/local/lib/python3.9/dist-packages/emhass/web_server.py", line 174, in action_call
    input_data_dict = set_input_data_dict(config_path, str(data_path), costfun,
  File "/usr/local/lib/python3.9/dist-packages/emhass/command_line.py", line 110, in set_input_data_dict
    rh.get_data(days_list, var_list,
  File "/usr/local/lib/python3.9/dist-packages/emhass/retrieve_hass.py", line 140, in get_data
    df_tp = df_raw.copy()[['state']].replace(
  File "/usr/local/lib/python3.9/dist-packages/pandas/core/generic.py", line 5920, in astype
    new_data = self._mgr.astype(dtype=dtype, copy=copy, errors=errors)
  File "/usr/local/lib/python3.9/dist-packages/pandas/core/internals/managers.py", line 419, in astype
    return self.apply("astype", dtype=dtype, copy=copy, errors=errors)
  File "/usr/local/lib/python3.9/dist-packages/pandas/core/internals/managers.py", line 304, in apply
    applied = getattr(b, f)(**kwargs)
  File "/usr/local/lib/python3.9/dist-packages/pandas/core/internals/blocks.py", line 580, in astype
    new_values = astype_array_safe(values, dtype, copy=copy, errors=errors)
  File "/usr/local/lib/python3.9/dist-packages/pandas/core/dtypes/cast.py", line 1292, in astype_array_safe
    new_values = astype_array(values, dtype, copy=copy)
  File "/usr/local/lib/python3.9/dist-packages/pandas/core/dtypes/cast.py", line 1237, in astype_array
    values = astype_nansafe(values, dtype, copy=copy)
  File "/usr/local/lib/python3.9/dist-packages/pandas/core/dtypes/cast.py", line 1098, in astype_nansafe
    result = astype_nansafe(flat, dtype, copy=copy, skipna=skipna)
  File "/usr/local/lib/python3.9/dist-packages/pandas/core/dtypes/cast.py", line 1181, in astype_nansafe
    return arr.astype(dtype, copy=True)
ValueError: could not convert string to float: 'NOTRUN'
2023-07-28 16:42:20,687 - web_server - INFO - Setting up needed data
2023-07-28 16:42:20,690 - web_server - INFO -  >> Publishing data...
2023-07-28 16:42:20,690 - web_server - INFO - Publishing data to HASS instance
2023-07-28 16:42:20,705 - web_server - INFO - Successfully posted to sensor.p_pv_forecast = 17.0
2023-07-28 16:42:20,716 - web_server - INFO - Successfully posted to sensor.p_load_forecast = 2587.03
2023-07-28 16:42:20,727 - web_server - INFO - Successfully posted to sensor.p_deferrable0 = 0.0
2023-07-28 16:42:20,740 - web_server - INFO - Successfully posted to sensor.p_batt_forecast = 2054.05
2023-07-28 16:42:20,751 - web_server - INFO - Successfully posted to sensor.soc_batt_forecast = 88.38
2023-07-28 16:42:20,762 - web_server - INFO - Successfully posted to sensor.p_grid_forecast = 515.98
2023-07-28 16:42:20,774 - web_server - INFO - Successfully posted to sensor.total_cost_fun_value = 0.61
2023-07-28 16:42:20,785 - web_server - INFO - Successfully posted to sensor.unit_load_cost = 0.55
2023-07-28 16:42:20,798 - web_server - INFO - Successfully posted to sensor.unit_prod_price = 0.45

I restarted HA and now I’m getting these errors with each MPC POST? Didn’t change anything relating to EMHASS.

{"load_cost_forecast":{{(
        ([states('sensor.cecil_st_general_price')|float(0)] +
        state_attr('sensor.cecil_st_general_forecast', 'forecasts') |map(attribute='per_kwh')|list)[:48])
        }}, 


        "prod_price_forecast":{{(
        ([states('sensor.cecil_st_feed_in_price')|float(0)] +
        state_attr('sensor.cecil_st_feed_in_forecast', 'forecasts')|map(attribute='per_kwh')|list)[:48]) 
        }},



        "pv_power_forecast":{{([states('sensor.sonnenbatterie_84324_production_w')|int(0)] +
        state_attr('sensor.forecast_today', 'detailedForecast')|selectattr('period_start','gt',utcnow()) | map(attribute='pv_estimate')|map('multiply',2000)|map('int')|list +
        state_attr('sensor.forecast_tomorrow', 'detailedForecast')|selectattr('period_start','gt',utcnow()) | map(attribute='pv_estimate')|map('multiply',2000)|map('int')|list
        )| tojson
        }},

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

        "soc_init":{{(states('sensor.sonnenbatterie_84324_state_charge_user')|float(0))/100
        }},
{"load_cost_forecast":[0.56, 0.52, 0.58, 0.68, 0.69, 0.64, 0.62, 0.4, 0.29, 0.34, 0.31, 0.43, 0.43, 0.26, 0.26, 0.31, 0.27, 0.26, 0.26, 0.26, 0.23, 0.21, 0.2, 0.2, 0.17, 0.2, 0.2, 0.2, 0.23, 0.2, 0.18, 0.16, 0.13, 0.13, 0.13, 0.13, 0.07, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.36, 0.39, 0.39, 0.3, 0.32], 


        "prod_price_forecast":[0.46, 0.42, 0.48, 0.56, 0.57, 0.53, 0.51, 0.28, 0.18, 0.23, 0.2, 0.31, 0.31, 0.15, 0.15, 0.2, 0.16, 0.15, 0.15, 0.15, 0.13, 0.1, 0.1, 0.09, 0.07, 0.09, 0.09, 0.1, 0.13, 0.1, 0.08, 0.06, 0.04, 0.04, 0.04, 0.02, -0.04, -0.06, -0.06, -0.07, -0.07, -0.06, -0.06, 0.27, 0.3, 0.3, 0.22, 0.24],



        "pv_power_forecast":[30, 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, 0, 0, 0, 93, 414, 876, 1278, 1634, 1964, 2156, 2142, 2110, 2071, 1981, 1818, 1693, 1608, 1451, 1207, 929, 666, 256, 66, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],

        "prediction_horizon":48,

        "soc_init":0.94,

        "soc_final":0.05,"def_total_hours":[2]}}

Thanks
Rob