EMHASS: An Energy Management for Home Assistant

I had this issue after messing around after a restore after sd-card replacement, both day-ahead and mpc was not working anymore. So I tried upgrading (from 0.10.6 to 0.11.1) without difference. (Addon)

Finally tried passing some dummy load_power_forecast data and all seems working fine.

I looked deeper into my sensor_power_load_no_var_loads template sensor, downloaded its history as .csv (it has just more than 2 days), and found that it has a few entries with “unknown” and “unavailable”. Can this be the cause of the log below? If so, I thought these non-numbers were to be caught and zeroed/interpolated?

INFO - web_server - EMHASS server online, serving index.html...
INFO - web_server - serving configuration.html...
INFO - web_server - Obtaining parameters from config.json:
INFO - web_server - Saved parameters from webserver
INFO - web_server - Passed runtime parameters: {'load_cost_forecast': [0.813, 0.803, 0.786, 0.778, 0.782, 0.779, 0.778, 0.782, 0.798, 0.806, 0.894, 1.139, 0.986, 0.892, 0.89, 0.916, 0.93, 0.927, 0.887, 1.204, 1.312, 1.028, 1.049, 1.041], 'prod_price_forecast': [0.6584, 0.6504, 0.6368, 0.6304, 0.6336, 0.6312, 0.6304, 0.6336, 0.6464, 0.6528, 0.7232, 0.9192, 0.7968, 0.7216, 0.72, 0.7408, 0.752, 0.7496, 0.7176, 0.9712, 1.0576, 0.8304, 0.8472, 0.8408]}
INFO - web_server -  >> Setting input data dict
INFO - web_server - Setting up needed data
INFO - web_server - Retrieving weather forecast data using method = scrapper
INFO - web_server - Retrieving data from hass for load forecast using method = naive
INFO - web_server - Retrieve hass get data method initiated...
ERROR - web_server - Exception on /action/dayahead-optim [POST]
Traceback (most recent call last):
  File "/usr/local/lib/python3.11/dist-packages/flask/app.py", line 1473, in wsgi_app
    response = self.full_dispatch_request()
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/flask/app.py", line 882, in full_dispatch_request
    rv = self.handle_user_exception(e)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/flask/app.py", line 880, in full_dispatch_request
    rv = self.dispatch_request()
         ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/flask/app.py", line 865, 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 325, in action_call
    input_data_dict = set_input_data_dict(emhass_conf, costfun,
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/emhass/command_line.py", line 114, in set_input_data_dict
    P_load_forecast = fcst.get_load_forecast(
                      ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/emhass/forecast.py", line 706, in get_load_forecast
    if not rh.get_data(days_list, var_list):
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/emhass/retrieve_hass.py", line 195, in get_data
    .astype(float)
     ^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/pandas/core/generic.py", line 6324, in astype
    new_data = self._mgr.astype(dtype=dtype, copy=copy, errors=errors)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/pandas/core/internals/managers.py", line 451, in astype
    return self.apply(
           ^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/pandas/core/internals/managers.py", line 352, in apply
    applied = getattr(b, f)(**kwargs)
              ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/pandas/core/internals/blocks.py", line 511, in astype
    new_values = astype_array_safe(values, dtype, copy=copy, errors=errors)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/pandas/core/dtypes/astype.py", line 242, in astype_array_safe
    new_values = astype_array(values, dtype, copy=copy)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/pandas/core/dtypes/astype.py", line 187, in astype_array
    values = _astype_nansafe(values, dtype, copy=copy)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/pandas/core/dtypes/astype.py", line 138, in _astype_nansafe
    return arr.astype(dtype, copy=True)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: could not convert string to float: 'Unknown'

My line of thinking:
If you have feedback from your hotwater system, such as water flow, temperature settings, temperature reading - so you can calculate predictable behaviour/energy demand, them you can model it in EMHASS and let system try to optimise.
If water heater do not offer any feedback, then you have to make some assumptions and ‘hard code it’. In this case, my logic would go as: Make it ‘deferable load’ so EMHASS get to get it to max temperature in most efficient way. Add second rule based on you most likely use of hot water to activate power to water heater during the actual use of it, so you do not run out of hot water. Say for 2 hours in the morning and 4 hours in the evening.
This way, EMHASS get to inject most of the power in most economical way. And water heater can always top up if needed during heavy use.

My take on it

1 Like

Mmm interesting, I’ll have a look at this. Thanks for the detailed logs @gieljnssns

1 Like

First, thanks for your excellent work on this tool!

Since the update, I’ve also ran to many issues with MPC. Seem pretty similar compared to before. See the logs below. To me, there should be plenty of hours in the timeframe for def3, but something doesn’t go quite right and result is infeasible optimization.

2024-10-30 06:47:59,540 - web_server - INFO - Passed runtime parameters: {'pv_power_forecast': [78, 0, 18, 78, 145, 218, 291, 416, 558, 710, 986, 1230, 1175, 966, 573, 358, 245, 142, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'load_power_forecast': [649, 1146, 1225, 1286, 1346, 1516, 1250, 1195, 1140, 1153, 1140, 1168, 2336, 1179, 1153, 990, 904, 1005, 1068, 1235, 1263, 1203, 2044, 1269, 1289, 1615, 1249, 1339, 1664, 1475, 1287, 1183, 1155, 1317, 1399], 'load_cost_forecast': [0.045, 0.046, 0.046, 0.048, 0.048, 0.052, 0.052, 0.051, 0.051, 0.05, 0.05, 0.05, 0.05, 0.048, 0.048, 0.048, 0.048, 0.048, 0.048, 0.049, 0.049, 0.05, 0.05, 0.053, 0.053, 0.05, 0.05, 0.05, 0.05, 0.049, 0.049, 0.049, 0.049, 0.048, 0.048], 'prod_price_forecast': [-0.001, 0.0, 0.0, 0.003, 0.003, 0.006, 0.006, 0.005, 0.005, 0.004, 0.004, 0.004, 0.004, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.003, 0.003, 0.004, 0.004, 0.007, 0.007, 0.004, 0.004, 0.004, 0.004, 0.003, 0.003, 0.003, 0.003, 0.003, 0.003], 'num_def_loads': 4, 'alpha': 0.25, 'beta': 0.75, 'P_def_nominal': [3000, 1500, 10500, 700], 'def_total_hours': [3, 0, 0, 5], 'treat_def_as_semi_cont': [True, True, True, True], 'def_start_timestep': [0, 0, 22, 0], 'def_end_timestep': [22, 22, 46, 22], 'prediction_horizon': 35}
2024-10-30 06:47:59,540 - web_server - INFO -  >> Setting input data dict
2024-10-30 06:47:59,540 - web_server - INFO - Setting up needed data
2024-10-30 06:47:59,543 - web_server - INFO - Retrieve hass get data method initiated...
2024-10-30 06:48:00,009 - web_server - INFO - Retrieving weather forecast data using method = list
2024-10-30 06:48:00,016 - web_server - INFO -  >> Performing naive MPC optimization...
2024-10-30 06:48:00,016 - web_server - INFO - Performing naive MPC optimization
2024-10-30 06:48:00,029 - web_server - INFO - Perform an iteration of a naive MPC controller
2024-10-30 06:48:00,094 - web_server - WARNING - Deferrable load 3 : Available timeframe is shorter than the specified number of hours to operate. Optimization will fail.
2024-10-30 06:48:00,097 - web_server - WARNING - Solver default unknown, using default
Welcome to the CBC MILP Solver 
Version: 2.10.10 
Build Date: Sep 26 2023 

For the add-on users who are interested.
The new sensor_replace_zero and sensor_linear_interp parameters (when migrating to 0.11.x) where added from the standalone emhass_config.yaml config. For add-on users, these parameters where previously hard coded to:

"sensor_replace_zero": ["sensor_power_photovoltaics"]
"sensor_linear_interp": ["sensor_power_photovoltaics", "sensor_power_load_no_var_loads"]

(Example above: sensor_power_photovoltaics=sensor.power_photovoltaics & sensor_power_load_no_var_loads=sensor.power_load_no_var_loads )

Also I believe there are some issues with the runtime paremeters. Im looking into this now.

4 Likes

Hi,

EMHASS stops working regularly and I can’t pinpoint why it happens, there are no errors in the EMHASS logging. I deleted the pkl files in the share folder and started-up EMHASS but after a while EMHASS stops again. Anyone an idea what I am missing? I run the add-on.

I don’t see anything strange in the logging?

waitress   INFO  Serving on http://0.0.0.0:5000
2024-10-30 14:52:00,294 - web_server - INFO - Passed runtime parameters: {'publish_prefix': ''}
2024-10-30 14:52:00,295 - web_server - INFO -  >> Setting input data dict
2024-10-30 14:52:00,295 - web_server - INFO - Setting up needed data
2024-10-30 14:52:00,338 - web_server - INFO -  >> Publishing data...
2024-10-30 14:52:00,338 - web_server - INFO - Publishing data to HASS instance
2024-10-30 14:52:00,358 - web_server - INFO - Successfully posted to sensor.p_pv_forecast = 578
2024-10-30 14:52:00,360 - web_server - INFO - Successfully posted to sensor.p_load_forecast = 193
2024-10-30 14:52:00,363 - web_server - INFO - Successfully posted to sensor.p_hybrid_inverter = 193.0
2024-10-30 14:52:00,366 - web_server - INFO - Successfully posted to sensor.p_deferrable0 = 0.0
2024-10-30 14:52:00,369 - web_server - INFO - Successfully posted to sensor.p_deferrable1 = 0.0
2024-10-30 14:52:00,371 - web_server - INFO - Successfully posted to sensor.p_batt_forecast = -385.0
2024-10-30 14:52:00,374 - web_server - INFO - Successfully posted to sensor.soc_batt_forecast = 33.18
2024-10-30 14:52:00,376 - web_server - INFO - Successfully posted to sensor.p_grid_forecast = 0.0
2024-10-30 14:52:00,379 - web_server - INFO - Successfully posted to sensor.total_cost_fun_value = 0.84
2024-10-30 14:52:00,381 - web_server - INFO - Successfully posted to sensor.optim_status = Optimal
2024-10-30 14:52:00,384 - web_server - INFO - Successfully posted to sensor.unit_load_cost = 0.2446
2024-10-30 14:52:00,387 - web_server - INFO - Successfully posted to sensor.unit_prod_price = 0.0925
2024-10-30 14:52:00,879 - web_server - INFO - Passed runtime parameters: {'prediction_horizon': 48, 'pv_power_forecast': [593, 974, 870, 744, 603, 418, 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, 0, 0, 143, 382, 804, 1302, 1735, 2170, 2588, 2901, 3023, 2897, 2517, 2087, 1713, 1443, 1227, 1033, 853, 600, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'num_def_loads': 2, 'P_deferrable_nom': [0, 0], 'def_total_hours': [0, 0], 'treat_def_as_semi_cont': [1, 1], 'set_def_constant': [1, 1], 'def_start_timestep': [0, 0], 'def_end_timestep': [0, 0], 'soc_init': 0.32, 'soc_final': 0.12, 'load_cost_forecast': [0.2446, 0.257, 0.257, 0.2878, 0.2878, 0.2981, 0.2981, 0.3155, 0.3155, 0.2953, 0.2953, 0.2609, 0.2609, 0.2546, 0.2546, 0.2513, 0.2513, 0.2497, 0.2497, 0.2426, 0.2426, 0.2362, 0.2362, 0.2342, 0.2342, 0.2321, 0.2321, 0.2344, 0.2344, 0.2394, 0.2394, 0.2574, 0.2574, 0.2694, 0.2694, 0.2754, 0.2754, 0.2627, 0.2627, 0.2453, 0.2453, 0.2385, 0.2385, 0.2312, 0.2312, 0.2337, 0.2337, 0.2397], 'prod_price_forecast': [0.0925, 0.1042, 0.1042, 0.1332, 0.1332, 0.143, 0.143, 0.1594, 0.1594, 0.1404, 0.1404, 0.1079, 0.1079, 0.1019, 0.1019, 0.0989, 0.0989, 0.0974, 0.0974, 0.0906, 0.0906, 0.0845, 0.0845, 0.0827, 0.0827, 0.0808, 0.0808, 0.0829, 0.0829, 0.0876, 0.0876, 0.1046, 0.1046, 0.1159, 0.1159, 0.1215, 0.1215, 0.1096, 0.1096, 0.0932, 0.0932, 0.0867, 0.0867, 0.0799, 0.0799, 0.0822, 0.0822, 0.0878], 'alpha': 1, 'beta': 0, 'load_power_forecast': [207, 200, 200, 300, 300, 1300, 200, 300, 200, 200, 200, 300, 200, 300, 200, 300, 200, 200, 200, 300, 200, 200, 200, 300, 300, 200, 200, 200, 300, 200, 200, 300, 500, 400, 200, 200, 300, 300, 200, 200, 200, 300, 200, 200, 200, 300, 300, 200]}
2024-10-30 14:52:00,880 - web_server - INFO -  >> Setting input data dict
2024-10-30 14:52:00,880 - web_server - INFO - Setting up needed data
2024-10-30 14:52:00,881 - web_server - INFO - Retrieve hass get data method initiated...
2024-10-30 14:52:01,429 - web_server - INFO - Retrieving weather forecast data using method = list
2024-10-30 14:52:01,431 - web_server - INFO -  >> Performing naive MPC optimization...
2024-10-30 14:52:01,431 - web_server - INFO - Performing naive MPC optimization
2024-10-30 14:52:01,436 - web_server - INFO - Perform an iteration of a naive MPC controller
2024-10-30 14:52:01,488 - web_server - DEBUG - Deferrable load 0: Proposed optimization window: 0 --> 0
2024-10-30 14:52:01,488 - web_server - DEBUG - Deferrable load 0: Validated optimization window: 0 --> 0
2024-10-30 14:52:01,489 - web_server - DEBUG - Deferrable load 1: Proposed optimization window: 0 --> 0
2024-10-30 14:52:01,489 - web_server - DEBUG - Deferrable load 1: Validated optimization window: 0 --> 0
2024-10-30 14:52:01,602 - web_server - INFO - Status: Optimal
2024-10-30 14:52:01,603 - web_server - INFO - Total value of the Cost function = -7.12
2024-10-30 14:52:01,871 - web_server - INFO - Passed runtime parameters: {'publish_prefix': ''}
2024-10-30 14:52:01,871 - web_server - INFO -  >> Setting input data dict
2024-10-30 14:52:01,871 - web_server - INFO - Setting up needed data
2024-10-30 14:52:01,873 - web_server - INFO -  >> Publishing data...
2024-10-30 14:52:01,873 - web_server - INFO - Publishing data to HASS instance
2024-10-30 14:52:01,881 - web_server - INFO - Successfully posted to sensor.p_pv_forecast = 593
2024-10-30 14:52:01,884 - web_server - INFO - Successfully posted to sensor.p_load_forecast = 207
2024-10-30 14:52:01,889 - web_server - INFO - Successfully posted to sensor.p_hybrid_inverter = 207.0
2024-10-30 14:52:01,891 - web_server - INFO - Successfully posted to sensor.p_deferrable0 = 0.0
2024-10-30 14:52:01,894 - web_server - INFO - Successfully posted to sensor.p_deferrable1 = 0.0
2024-10-30 14:52:01,897 - web_server - INFO - Successfully posted to sensor.p_batt_forecast = -386.0
2024-10-30 14:52:01,901 - web_server - INFO - Successfully posted to sensor.soc_batt_forecast = 33.18
2024-10-30 14:52:01,905 - web_server - INFO - Successfully posted to sensor.p_grid_forecast = 0.0
2024-10-30 14:52:01,908 - web_server - INFO - Successfully posted to sensor.total_cost_fun_value = 0.84
2024-10-30 14:52:01,910 - web_server - INFO - Successfully posted to sensor.optim_status = Optimal
2024-10-30 14:52:01,912 - web_server - INFO - Successfully posted to sensor.unit_load_cost = 0.2446
2024-10-30 14:52:01,915 - web_server - INFO - Successfully posted to sensor.unit_prod_price = 0.0925

Hi, I would like to record the consumption of my heat pump. Unfortunately, it only saves the consumption quantity as a counter value. Is there a way to convert this? Or do I need a power measurement sensor?

This issue solved! It has nothing to do with EMHASS itself, there was an out of memory problem with the Virtual Machine where home assistant runs, a restart solved the issue. Only thing is that I don’t know where the issue came from. I can see that EMHASS uses about 13% of available RAM.

Hey everyone, there was a recent PR merged that fixes some runtime parameter issues. The next version should see some things fixed. @gieljnssns I believe your issue was fixed in this change.

5 Likes

I will be pushing a new version in some minutes…

7 Likes

If you have installed the solcast addon, do you also have to enter the information in the EMHass configuration or is that information taken from Homeassistant?

My issue is fixed. Thanks!

1 Like

I believe this information isn’t automatically fetched. I have automations that share this data as runtime parameters in the curl-calls to the optimizations.

Would be nice if you could just point EMHASS to the sensors created by the solcast integration indeed.

If using the naive Model Predictive Controller you have to process the sensor.solcast_pv_forecast_forecast_today and possibly sensor.solcast_pv_forecast_forecast_tomorrow sensors from solcast. You need to extract the detailedForecast attribute from these two sensors into a series of half hour (if this is the time step you are using) PV production forecasts for at least the length of the prediction horizon you are using. This series needs to be in a json dictionary format. See here

Also if you want the system to be reactive to the actual current conditions as well as planning with the forecast data then you need to prefix this json dictionary with the actual PV production from your inverter. In my case this is sonnenbatterie_84324_production_w (All in Watts). See below

Something like this:

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

Output:

"pv_power_forecast": [290, 970, 1320, 1613, 1923, 2219, 2410, 2478, 2553, 2650, 2666, 2613, 2538, 2442, 2309, 2179, 2028, 1838, 1573, 1274, 955, 573, 243, 61, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 110, 396, 692, 946, 1118, 1329, 1539, 1573, 1454, 1499, 1648, 1737, 1813, 1830, 1791, 1675, 1526, 1408, 1284, 1112, 943, 776, 514, 248, 76, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0],

Thanks to your guide, mine look a lot like yours, but
I believe your template is incomplete, it misses the }} at the end.

I also think the | tojson does nothing?

Thats just an extract. My full template is:

{
  "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))
    | tojson 
  }},
  {%- set current_month = now().month %}
  {%- if (3 <= current_month <= 8) or (11 <= current_month <= 12) %}
  "load_cost_forecast": {%- set current_time = now() %}
  {%- set demand_tariff_start = "15:00:00" %}
  {%- set demand_tariff_end = "21:00:00" %}

  {%- set start_time = current_time.replace(hour=0, minute=0, second=0, microsecond=0) + timedelta(hours=(demand_tariff_start.split(":")[0]|int), minutes=(demand_tariff_start.split(":")[1]|int)) %}
  {%- set end_time = current_time.replace(hour=0, minute=0, second=0, microsecond=0) + timedelta(hours=(demand_tariff_end.split(":")[0]|int), minutes=(demand_tariff_end.split(":")[1]|int)) %}

  {%- if end_time <= start_time %}
    {%- set end_time = end_time + timedelta(days=1) %}
  {%- endif %}

  {%- set values = ([states("sensor.cecil_st_general_price")|float(0)] + state_attr("sensor.cecil_st_general_forecast", "forecasts")|map(attribute="per_kwh")|list) %}
  {%- set ns = namespace(x=[]) %}

  {%- for i in range(values|length) %}
    {%- set future_time = current_time + timedelta(minutes=i * 30) %}
    {%- if start_time <= future_time < end_time and values[i] < 1 %}
      {%- set ns.x = ns.x + [1.0] %}
    {%- else %}
      {%- set ns.x = ns.x + [values[i]] %}
    {%- endif %}
  {%- endfor %}

  {{- ns.x | tojson }},

  {%- else %}
  "load_cost_forecast": {{
    ([states('sensor.cecil_st_general_price')|float(0)] + 
    state_attr('sensor.cecil_st_general_forecast', 'forecasts') |map(attribute='per_kwh')|list) 
    | tojson 
  }},
  {%- endif %}
  "pv_power_forecast": {{
    ([states('sensor.sonnenbatterie_84324_production_w')|int(0)] +
    state_attr('sensor.solcast_pv_forecast_forecast_today', 'detailedForecast')|selectattr('period_start','gt',utcnow()) | map(attribute='pv_estimate')|map('multiply',1000)|map('int')|list +
    state_attr('sensor.solcast_pv_forecast_forecast_tomorrow', 'detailedForecast')|selectattr('period_start','gt',utcnow()) | map(attribute='pv_estimate')|map('multiply',1000)|map('int')|list
    )| tojson
  }},
  "load_power_forecast": {{
    ([states('sensor.house_power_consumption_less_deferrables')|int(0)] +
    states('input_text.fifo_buffer').split(',') | map('int') | list)
  }},
  {#"load_power_forecast": {{"[500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500]" 
  }},#}
  "prediction_horizon": {{
    min(48, (state_attr('sensor.cecil_st_feed_in_forecast', 'forecasts')|map(attribute='per_kwh')|list|length)+1)
  }},
  "num_def_loads": 2,
  "def_total_hours": [
    {%- if 'unny' in states('sensor.denistone_east_extended_text_0') and states('sensor.cecil_st_general_price') | float(0) < 0.15 -%}
      {%- if is_state('sensor.season', 'winter') -%}
        {{2}}
      {%- elif is_state('sensor.season', 'summer') -%}
        {{4}}
      {%- else -%}
        {{3}}
      {%- endif -%}
    {%- else -%}
      {{0}}
    {%- endif -%},
    {%- if is_state('device_tracker.ynot_location_tracker', ['home']) -%}
      {%- if is_state('binary_sensor.ynot_charger', ['on']) -%}
        {{ ((states('number.ynot_charge_limit')|int(80)-(states('sensor.ynot_battery')|int(0)))/30*3)|round(0) }}
      {%- else -%} 
        0
      {%- endif -%}
    {%- else -%} 
      0
    {%- endif -%}
    ],
  "P_deferrable_nom": [1300, {{ (states('input_number.ev_amps') | int(0) * 230)|int(0) }}],
  "treat_def_as_semi_cont": [1, 0],
  "set_def_constant": [0, 0],
  "soc_init": {{ (states('sensor.sonnenbatterie_84324_state_charge_user')|int(0))/100 }},
  "soc_final": 0,
  "alpha": 1,
  "beta": 0
}

tojson is a filter that converts a Python object (like a dictionary, list, or other data structure) into a JSON-formatted string.

The full output of this template is below and needs to be in json format or the POST will fail:

{
  "prod_price_forecast": [
    0.05,
    0.06,
    0.06,
    0.06,
    0.05,
    0.04,
    0.03,
    0.03,
    0.03,
    -0.02,
    -0.05,
    -0.05,
    -0.04,
    0,
    0.04,
    0.04,
    0.06,
    0.03,
    -0.01,
    0.02,
    0.03,
    0.1,
    0.12,
    0.13,
    0.13,
    0.12,
    0.11,
    0.1,
    0.09,
    0.08,
    0.08,
    0.08,
    0.08,
    0.08,
    0.07,
    0.07,
    0.06,
    0.06,
    0.06,
    0.06,
    0.06,
    0.06
  ],
  "load_cost_forecast": [
    0.13,
    0.14,
    0.14,
    0.14,
    0.14,
    0.13,
    0.12,
    0.12,
    0.12,
    0.06,
    0.04,
    0.04,
    0.04,
    0.09,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    0.19,
    0.18,
    0.17,
    0.16,
    0.16,
    0.16,
    0.16,
    0.16,
    0.15,
    0.15,
    0.14,
    0.14,
    0.14,
    0.14,
    0.14,
    0.14
  ],
  "pv_power_forecast": [
    759,
    1822,
    2267,
    2696,
    3037,
    3080,
    2929,
    2711,
    2666,
    2613,
    2538,
    2442,
    2309,
    2179,
    2028,
    1838,
    1573,
    1274,
    955,
    573,
    243,
    61,
    7,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    23,
    110,
    396,
    692,
    946,
    1118,
    1329,
    1539,
    1573,
    1454,
    1499,
    1648,
    1737,
    1813,
    1830,
    1791,
    1675,
    1526,
    1408,
    1284,
    1112,
    943,
    776,
    514,
    248,
    76,
    10,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0
  ],
  "load_power_forecast": [
    467,
    406,
    501,
    504,
    449,
    451,
    369,
    409,
    456,
    663,
    1980,
    1639,
    478,
    618,
    497,
    416,
    413,
    500,
    473,
    2057,
    583,
    590,
    537,
    546,
    526,
    602,
    613,
    588,
    518,
    515,
    429,
    411,
    401,
    340,
    330,
    315,
    341,
    308,
    315,
    319,
    327,
    336,
    321,
    309,
    451,
    434,
    530,
    482,
    534
  ],
  "prediction_horizon": 42,
  "num_def_loads": 2,
  "def_total_hours": [
    0,
    0
  ],
  "P_deferrable_nom": [
    1300,
    7360
  ],
  "treat_def_as_semi_cont": [
    1,
    0
  ],
  "set_def_constant": [
    0,
    0
  ],
  "soc_init": 0.01,
  "soc_final": 0,
  "alpha": 1,
  "beta": 0
}

I use this output in a Node-Red http node that POSTs the dictionaries to EMHASS and calls the MPC process. all documented here

1 Like

Hey.

Is there any good tutorial how to setup EMHASS? Or somebody that could guide me through to make the code for me that I want to do.

I have solar panels from huawei and battery also, I have also nordpool installed and I want to optimize when it should discharge (also be allowed to discharge to the grid) and when to charge from grid and solar.

I also have forecast solar installed in homeassistant.

Could anyone help me with a setup like this?

See the post from me just above your post. There is a link at the bottom to my documented configuration. If you go through that you’ll get an understanding of how to set up MPC rather than reading through all the messages in this community. This is a configuration that follows Mark Purcell’s setup.

I do use Node-Red in my system for automation so that needs to be considered.

There are a lot of people using EMHASS with nordpool so you’ll find norpool expertise throughout this community if you have nordpool specific issues.

The first thing you have to work out is if your battery is manageable. I have a sonnen battery which offers an API that allows manual control. Direct RESTful commands to charge and discharge at different wattages from 0 to 3300 W.

Does your inverter allow manual control? Do you have a hybrid inverter that separates your battery from your PV system. I think batteries connected directly to PV system typically can’t charge from and discharge to the grid, they can only charge from PV and discharge to the home.

Huawei batteries can potentially be integrated with EMHASS, though it depends on the specific model and its communication capabilities. Most Huawei energy storage systems communicate via Modbus, which could allow you to set up management for charge and discharge commands.

I believe some Huawei inverters and batteries support Modbus over TCP, not RESTful API so you have to ignore that in my document. If your model supports this, you can integrate it with EMHASS, provided you can access the necessary Modbus registers for managing charging and discharging on demand.

Yes so its an Hybrid huawei inverter and there’s a plugin done for Home Assistant that allows the users to do discharing and so on.

Thanks for the link! This is just the way I want to set it up, but this requires a lot of time to read through and do the automations. Will see if I can have Chatgpt to help me out also a bit

Also search in this topic for people that have also implemented huawei batteries.