EMHASS: An Energy Management for Home Assistant

I added a second deferrable load and changed all deferrable load values to arrays and that seems to have done the trick.

Also when you have only one deferrable load (or even none - set P_deferrable_nom, def_start_timestep and def_end_timestep to [0]; num_def_loads, treat_def_as_semi_cont and def_total_hours to [1]) it’s advised to use 1-element arrays.

Thanks for the tip - may give it a try.

Is it possible to force battery charging more towards the morning? Even if prices are same or almost same over day.

I am also interested in setting up the thermal deferable load but not sure quite how it needs to look from the documentation.

Does anyone have an example of the log of what is passed to emhass, especially with 1+ deferable loads, and the thermal deferable load?

Thanks

1 Like

Sure, here’s one cycle:

2024-09-25 14:42:54,745 - web_server - INFO - Passed runtime parameters: {'prod_price_forecast': [0.08, 0.11, 0.08, 0.09, 0.11, 0.15, 0.18, 0.21, 0.34, 0.17, 0.15, 0.16, 0.15, 0.11, 0.08, 0.1, 0.08, 0.09, 0.08, 0.09, 0.09, 0.09, 0.09, 0.09, 0.09, 0.09, 0.09, 0.07, 0.08, 0.08, 0.08, 0.09, 0.1, 0.08, 0.08, 0.08, 0.06, 0.04, 0.04, 0.03, 0.03, 0.03, 0.04, 0.04, 0.05, 0.05, 0.06, 0.06, 0.1], 'load_cost_forecast': [0.17, 0.2, 0.16, 0.14, 0.17, 0.21, 0.24, 0.28, 0.42, 0.23, 0.21, 0.23, 0.21, 0.19, 0.16, 0.18, 0.16, 0.17, 0.16, 0.17, 0.17, 0.17, 0.17, 0.17, 0.17, 0.17, 0.17, 0.15, 0.16, 0.16, 0.16, 0.18, 0.19, 0.16, 0.16, 0.16, 0.14, 0.12, 0.12, 0.12, 0.12, 0.12, 0.13, 0.13, 0.14, 0.14, 0.15, 0.15, 0.19], 'pv_power_forecast': [1122, 1123, 575, 410, 104, 31, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 32, 126, 354, 557, 662, 731, 859, 996, 1025, 932, 888, 874, 804, 690, 635, 615, 495, 312, 241, 222, 139, 74, 19, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'load_power_forecast': [459, 423, 450, 454, 421, 403, 487, 752, 781, 580, 546, 523, 540, 437, 501, 395, 325, 369, 340, 320, 309, 334, 331, 453, 428, 310, 303, 319, 330, 314, 342, 382, 497, 359, 319, 431, 362, 336, 411, 525, 870, 398, 412, 349, 340, 553, 403, 371, 637], 'prediction_horizon': 48, '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.57, 'soc_final': 0, 'alpha': 1, 'beta': 0}
2024-09-25 14:42:54,746 - web_server - INFO -  >> Setting input data dict
2024-09-25 14:42:54,746 - web_server - INFO - Setting up needed data
2024-09-25 14:42:54,748 - web_server - INFO - Retrieve hass get data method initiated...
2024-09-25 14:42:59,178 - web_server - INFO - Retrieving weather forecast data using method = list
2024-09-25 14:42:59,181 - web_server - INFO -  >> Performing naive MPC optimization...
2024-09-25 14:42:59,182 - web_server - INFO - Performing naive MPC optimization
2024-09-25 14:42:59,194 - web_server - INFO - Perform an iteration of a naive MPC controller
2024-09-25 14:42:59,381 - web_server - INFO - Status: Optimal
2024-09-25 14:42:59,381 - web_server - INFO - Total value of the Cost function = 0.77
2024-09-25 14:42:59,774 - web_server - INFO - Passed runtime parameters: {}
2024-09-25 14:42:59,775 - web_server - INFO -  >> Setting input data dict
2024-09-25 14:42:59,775 - web_server - INFO - Setting up needed data
2024-09-25 14:42:59,777 - web_server - INFO -  >> Publishing data...
2024-09-25 14:42:59,777 - web_server - INFO - Publishing data to HASS instance
2024-09-25 14:42:59,793 - web_server - INFO - Successfully posted to sensor.p_pv_forecast = 1122
2024-09-25 14:42:59,806 - web_server - INFO - Successfully posted to sensor.p_load_forecast = 459
2024-09-25 14:42:59,816 - web_server - INFO - Successfully posted to sensor.p_deferrable0 = 0.0
2024-09-25 14:42:59,826 - web_server - INFO - Successfully posted to sensor.p_deferrable1 = 0.0
2024-09-25 14:42:59,838 - web_server - INFO - Successfully posted to sensor.p_batt_forecast = -663.0
2024-09-25 14:42:59,851 - web_server - INFO - Successfully posted to sensor.soc_batt_forecast = 59.1
2024-09-25 14:42:59,862 - web_server - INFO - Successfully posted to sensor.p_grid_forecast = 0.0
2024-09-25 14:42:59,873 - web_server - INFO - Successfully posted to sensor.total_cost_fun_value = 0.77
2024-09-25 14:42:59,882 - web_server - INFO - Successfully posted to sensor.optim_status = Optimal
2024-09-25 14:42:59,896 - web_server - INFO - Successfully posted to sensor.unit_load_cost = 0.17
2024-09-25 14:42:59,911 - web_server - INFO - Successfully posted to sensor.unit_prod_price = 0.08

Nice project, I’m currently programming my first custom component and I’m looking at other projects to see how it’s done and to get some ideas.
I get the price forecast for the electrical energy from my electricity provider until day end - the current price changes every hour
Question: is there any plan to integrate a service for your project that switches on consumers depending on the price when it’s cheap?
I’m currently working on how to implement something like that.
At the moment I know what the current price is and when it’s cheapest (time of day)
Or has anyone seen something similar in another project?

That’s a central function of EMHASS. Referred to as "deferrable loads”, the system can be configured to manage any number of loads within reason.

When calling EMHASS to produce a plan you pass the details of the deferrable loads:

  • Number of hours to operate
  • variable or static load
  • window of operation

The system then calculates the best time and power (if a variable load) to run the loads and passes this back into HA as a sensor (in kW) that can be used directly to operate the load.

Thanks for sharing, but unless I’ve misunderstood something that doesn’t have the thermal deferable load? I have a working setup for the normal deferable loads currently.

It lists on the documentation as such, for “two deferrable loads and the second load is a thermal load”:

'def_load_config': {
    {},
    {'thermal_config': {
        'heating_rate': 5.0,
        'cooling_constant': 0.1,
        'overshoot_temperature': 24.0,
        'start_temperature': 20,
        'desired_temperatures': [...]
    }}
}

But I am unsure how to combine this with other deferable loads. For instance, should it be like this?:

'def_load_config': {
    {total_hours: 1,
    nominal_power: 2000,  
    start_penalty: 1,  
    start_timestep: 5,  
    end_timestep: 15,  
    set_def_constant: false  },
    {'thermal_config': {
        'heating_rate': 5.0,
        'cooling_constant': 0.1,
        'overshoot_temperature': 24.0,
        'start_temperature': 20,
        'desired_temperatures': [...]
    }}

Hi Arva,
Did you find a solution for this strange behaviour? I see the same thing happen in my Emhass (Home Assistant add-on) setup. I’m using rest commands similar like yours, strait out of the Emhass documentation. The model tune works fine with 48 num_lags but the model fit returns only 24.
I have no idea how to adress this issue…

When starting the Day-Ahead Optimization, I get the following error:

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 122, 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 98, in set_input_data_dict
    df_weather = fcst.get_weather_forecast(
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/emhass/forecast.py", line 372, in get_weather_forecast
    data.index = self.forecast_dates
    ^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/pandas/core/generic.py", line 6002, in __setattr__
    return object.__setattr__(self, name, value)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "pandas/_libs/properties.pyx", line 69, in pandas._libs.properties.AxisProperty.__set__
  File "/usr/local/lib/python3.11/dist-packages/pandas/core/generic.py", line 730, in _set_axis
    self._mgr.set_axis(axis, labels)
  File "/usr/local/lib/python3.11/dist-packages/pandas/core/internals/managers.py", line 225, in set_axis
    self._validate_set_axis(axis, new_labels)
  File "/usr/local/lib/python3.11/dist-packages/pandas/core/internals/base.py", line 70, in _validate_set_axis
    raise ValueError(
ValueError: Length mismatch: Expected axis has 1176 elements, new values have 48 elements

The Optimization keeps loading and nothing is returned.

It’s me again …

I managed to set up EMHASS finally.

The PV system consists of 4 roofs with solar panels, 24.9 kWp in total, and 15 kWh battery, 2 Deye inverters. I have 3 deferrable loads.

But the main goal is to find out when it is suitable to charge the battery from grid during nighttime using a variable grid price, based on day-ahead prices given in 1 hour steps (Tibber Germany). This is because I have the special case that water heating is done by continous-flow electrical water heaters (22 kW each). And I have a high 24/7 base load (small data center). Those drain the battery quickly, so that the SOC of the battery falls below 10% before the people living here start their morning showers…

The Tibber prices normally have two peaks: 18:00-20:00 in the evening and 7:00 to 9:00 in the morning. We therefore hit the morning price peak with the water heaters with nothing left in the battery and nothing produced by the solar panels. On the other hand the Tibber prices normally are low during nighttime. If prices are low enough to compensate for the charge/discharge losses of around 20%, it should be feasible to charge from grid during nighttime, but just enough to cover the consumption peak - not more.

In Germany, I get a fixed low price for selling to the grid (around 7.4 ct/kWh). Day-ahead prices for buying are mostly around 20-22 ct/kWh during night and 28 -32 ct/kWh during the morning peak and around 28-45 ct/kWh during the evening peak. I am not allowed to discharge the battery to the grid, but I can charge from the grid.

Now the challenges:

  • the water heaters cause very huge but short peaks in the optimization variable load_no_var_loads at varying timestamps, depending e.g. on the work shedules of the people living here. This seems to be to difficult for the ML forecaster: the optimization status is always “Infeasible”.
  • what optimization strategy should I choose? Cost, profit or self-consumption?
  • in the results I see cost_profit, total_cost_fun and soc forecast. But in HA I never get cost_profit, only the other two. ???
  • which variables should I use to decide whether to charge from grid during nighttime? Cost_profit? That doesn’t show up in HA :frowning: :disappointed:
  • how much should I charge from grid? I guess: up to SOC forecast?

Some data:




2024-09-27 18:12:33,030 - web_server - INFO - EMHASS server online, serving index.html...
2024-09-27 18:15:01,164 - web_server - INFO - Passed runtime parameters: {}
2024-09-27 18:15:01,165 - web_server - INFO -  >> Setting input data dict
2024-09-27 18:15:01,165 - web_server - INFO - Setting up needed data
2024-09-27 18:15:01,174 - web_server - INFO -  >> Publishing data...
2024-09-27 18:15:01,174 - web_server - INFO - Publishing data to HASS instance
2024-09-27 18:15:01,815 - web_server - INFO - Successfully posted to sensor.p_pv_forecast = 981.23
2024-09-27 18:15:01,934 - web_server - INFO - Successfully posted to sensor.p_load_forecast = 1170.68
2024-09-27 18:15:02,021 - web_server - INFO - Successfully posted to sensor.p_hybrid_inverter = 1170.68
2024-09-27 18:15:02,068 - web_server - INFO - Successfully posted to sensor.p_deferrable0 = 0.0
2024-09-27 18:15:02,098 - web_server - INFO - Successfully posted to sensor.p_deferrable1 = 0.0
2024-09-27 18:15:02,139 - web_server - INFO - Successfully posted to sensor.p_deferrable2 = 0.0
2024-09-27 18:15:02,215 - web_server - INFO - Successfully posted to sensor.p_batt_forecast = 189.45
2024-09-27 18:15:02,242 - web_server - INFO - Successfully posted to sensor.soc_batt_forecast = 76.14
2024-09-27 18:15:02,274 - web_server - INFO - Successfully posted to sensor.p_grid_forecast = 0.0
2024-09-27 18:15:02,298 - web_server - INFO - Successfully posted to sensor.total_cost_fun_value = -0.19
2024-09-27 18:15:02,323 - web_server - INFO - Successfully posted to sensor.optim_status = Infeasible
2024-09-27 18:15:02,355 - web_server - INFO - Successfully posted to sensor.unit_load_cost = 0.107
2024-09-27 18:15:02,384 - web_server - INFO - Successfully posted to sensor.unit_prod_price = 0.0744


Hi! I did not do anything and it’s working again.

here are my rest commands

  ml_forecast_model_fit:
    url: http://192.168.1.35:5001/action/forecast-model-fit
    method: POST
    content_type: 'application/json'
    payload: >-
      {
        "days_to_retrieve": 16,
        "model_type": "load_forecast",
        "var_model": "sensor.ss_load_power_without_deferrable",
        "sklearn_model": "KNeighborsRegressor",
        "num_lags": 48,
        "split_date_delta": "48h",
        "perform_backtest": "True"
      }

  ml_forecast_model_tune:
    url: http://192.168.1.35:5001/action/forecast-model-tune
    method: POST
    content_type: 'application/json'
    payload: >-
      {
        "days_to_retrieve": 16,
        "model_type": "load_forecast",
        "var_model": "sensor.ss_load_power_without_deferrable",
        "sklearn_model": "KNeighborsRegressor",
        "num_lags": 48,
        "split_date_delta": "48h",
        "perform_backtest": "True"
      }

EDIT: just tested and still have same issue that i cannot run the Model Tune. After running it and then mpc run:

2024-09-28 21:35:00,410 - web_server - INFO -  >> Setting input data dict
2024-09-28 21:35:00,410 - web_server - INFO - Setting up needed data
2024-09-28 21:35:00,415 - web_server - INFO - Retrieve hass get data method initiated...
2024-09-28 21:35:05,043 - web_server - INFO - Retrieving weather forecast data using method = list
2024-09-28 21:35:05,044 - web_server - INFO - Retrieving data from hass for load forecast using method = mlforecaster
2024-09-28 21:35:05,045 - web_server - INFO - Retrieve hass get data method initiated...
2024-09-28 21:35:11,520 - web_server - INFO - Passed runtime parameters: {'load_cost_forecast': [0.1764242, 0.15435439999999997, 0.139568, 0.0745664, 0.07024760000000001, 0.05958480000000001, 0.057584, 0.05648600000000001, 0.0564372, 0.0573644, 0.05958480000000001, 0.06190280000000001, 0.06068280000000001, 0.0605852, 0.0562176, 0.054595000000000005, 0.0545828, 0.05399720000000001, 0.0540582, 0.054595000000000005, 0.10075980000000001, 0.1677134, 0.23482560000000002, 0.2692052, 0.1899052, 0.1525366, 0.1402756], 'prod_price_forecast': [0.09819, 0.08009999999999999, 0.06798, 0.014700000000000003, 0.01116, 0.00242, 0.0007800000000000003, -0.0001200000000000001, -0.00015999999999999999, 0.0005999999999999998, 0.00242, 0.004320000000000001, 0.0033200000000000005, 0.0032400000000000003, -0.00034, -0.00167, -0.00168, -0.00216, -0.00211, -0.00167, 0.03617000000000001, 0.09104999999999999, 0.14606, 0.17423999999999998, 0.10923999999999999, 0.07861, 0.06856], 'prediction_horizon': 27, 'pv_power_forecast': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 339, 1044, 1897, 2730, 3216, 3192, 2979, 2653, 1972, 1021, 224, 0, 0, 0, 0, 0], 'soc_init': 0.35, 'def_total_hours': [1, 0, 0], 'def_end_timestep': [10, 0, 0], 'var_model': 'sensor.ss_load_power_without_deferrable', 'alpha': 1, 'beta': 0}
2024-09-28 21:35:11,521 - web_server - INFO -  >> Setting input data dict
2024-09-28 21:35:11,521 - web_server - INFO - Setting up needed data
2024-09-28 21:35:11,525 - web_server - INFO - Retrieve hass get data method initiated...
2024-09-28 21:35:14,916 - web_server - ERROR - Unable to obtain: 27 lags_opt values from sensor: power load no var loads, check optimization_time_step/freq and historic_days_to_retrieve/days_to_retrieve parameters
2024-09-28 21:35:14,916 - web_server - ERROR - Unable to get sensor power photovoltaics, or sensor power load no var loads. Check HA sensors and their daily data
2024-09-28 21:35:17,523 - web_server - INFO - Retrieving weather forecast data using method = list
2024-09-28 21:35:17,525 - web_server - INFO - Retrieving data from hass for load forecast using method = mlforecaster
2024-09-28 21:35:17,526 - web_server - INFO - Retrieve hass get data method initiated...
2024-09-28 21:35:25,876 - web_server - ERROR - Unable to obtain: 27 lags_opt values from sensor: power load no var loads, check optimization_time_step/freq and historic_days_to_retrieve/days_to_retrieve parameters
2024-09-28 21:35:25,876 - web_server - ERROR - Unable to get sensor power photovoltaics, or sensor power load no var loads. Check HA sensors and their daily data
2024-09-28 21:35:31,878 - web_server - INFO - EMHASS server online, serving index.html...

After running model fit, MPC works again.

Very interested to find this paper presented in August using EMHASS.

Are the authors here?

https://www.researchgate.net/publication/382464807_Enhancing_Home_Energy_Management_A_Day-ahead_Machine_Learning_Approach_Using_EMHASS_for_Predictive_Temperature_Control

Hi Guys,

Does someone know why the forecast grid power is so different than the real grid power?

My power_var_no_loads look like this, and I think this is correct?

      power_load_no_var_loads:
        unit_of_measurement: "W"
        value_template: "{{ (states('sensor.power_consumption') | float * 1000) - states('sensor.vermogen_naar_auto')| float(0)| round(2) }}"

I think if you can match battery charge/discharge to EMHASS battery forecast (sensor.p_batt_forecast):

Then real grid power follows forecast grid power very closely.
Real grid power in/out is not power_load_no_var_loads, it includes all loads.

So I think how they track each other depends on how much control you have over your battery.

Compare EMHASS forecast grid power to total grid export/consumption.
Some batteries don’t offer this level of control. What type of battery do you have and how do you control it?

My rest commands are similar and I’m running them once per day.:

  model_fit:
    url: http://localhost:5000/action/forecast-model-fit
    method: POST
    timeout: 500
    content_type: 'application/json'
    payload: >-
      {
      "days_to_retrieve": 30, 
      "model_type": "load_forecast", 
      "var_model": "sensor.house_entity_no_deferrable_loads", 
      "sklearn_model": "KNeighborsRegressor", 
      "num_lags": 48, 
      "perform_backtest": "True", 
      "split_date_delta": "72h"
      }

  model_tune:
    url: http://localhost:5000/action/forecast-model-tune
    method: POST
    timeout: 500
    content_type: 'application/json'
    payload: >-
      {
      "days_to_retrieve": 30, 
      "model_type": "load_forecast", 
      "var_model": "sensor.house_entity_no_deferrable_loads", 
      "num_lags": 48, 
      "perform_backtest": "False" 
      }

Everything has been running fine for months, but some time ago I started receiving this errors in the log:

2024-09-30 16:38:29,930 - web_server - INFO -  >> Performing a machine learning forecast model tune...
2024-09-30 16:38:29,938 - web_server - INFO - Bayesian hyperparameter optimization with backtesting

  0%|          | 0/10 [00:00<?, ?it/s]
Best trial: 0. Best value: 0.667668:   0%|          | 0/10 [00:06<?, ?it/s]
Best trial: 0. Best value: 0.667668:  10%|█         | 1/10 [00:06<01:00,  6.67s/it]
Best trial: 1. Best value: 0.325283:  10%|█         | 1/10 [00:11<01:00,  6.67s/it]
Best trial: 1. Best value: 0.325283:  20%|██        | 2/10 [00:11<00:42,  5.35s/it]
Best trial: 1. Best value: 0.325283:  20%|██        | 2/10 [00:11<00:42,  5.35s/it]
Best trial: 1. Best value: 0.325283:  30%|███       | 3/10 [00:11<00:21,  3.07s/it]
Best trial: 3. Best value: 0.292502:  30%|███       | 3/10 [00:11<00:21,  3.07s/it]
Best trial: 3. Best value: 0.292502:  40%|████      | 4/10 [00:11<00:11,  1.99s/it]
Best trial: 3. Best value: 0.292502:  40%|████      | 4/10 [00:12<00:11,  1.99s/it]
Best trial: 3. Best value: 0.292502:  50%|█████     | 5/10 [00:12<00:06,  1.38s/it]
Best trial: 3. Best value: 0.292502:  50%|█████     | 5/10 [00:12<00:06,  1.38s/it]
Best trial: 3. Best value: 0.292502:  60%|██████    | 6/10 [00:12<00:04,  1.04s/it]
Best trial: 6. Best value: 0.249394:  60%|██████    | 6/10 [00:12<00:04,  1.04s/it]
Best trial: 6. Best value: 0.249394:  70%|███████   | 7/10 [00:12<00:02,  1.24it/s]
Best trial: 6. Best value: 0.249394:  70%|███████   | 7/10 [00:13<00:02,  1.24it/s]
Best trial: 6. Best value: 0.249394:  80%|████████  | 8/10 [00:13<00:01,  1.50it/s]
Best trial: 8. Best value: 0.21763:  80%|████████  | 8/10 [00:13<00:01,  1.50it/s] 
Best trial: 8. Best value: 0.21763:  90%|█████████ | 9/10 [00:13<00:00,  1.78it/s]
Best trial: 8. Best value: 0.21763:  90%|█████████ | 9/10 [00:13<00:00,  1.78it/s]
Best trial: 8. Best value: 0.21763: 100%|██████████| 10/10 [00:13<00:00,  2.00it/s]
Best trial: 8. Best value: 0.21763: 100%|██████████| 10/10 [00:13<00:00,  1.38s/it]
2024-09-30 16:38:44,064 - web_server - INFO - Elapsed time: 14.125211238861084
2024-09-30 16:38:44,265 - web_server - INFO - R2 score for optimized prediction in train period: -0.2176300302069616
2024-09-30 16:38:44,274 - web_server - INFO - R2 score for optimized prediction in test period: -1.8226690635332856
2024-09-30 16:38:44,275 - web_server - INFO - Number of optimal lags obtained: 12

I am a little bit lost here. I even don’t realy understand what the model tune is suppost to do. For now I only run the model fit…

I have a Solaredge SE5K-RWS48BEN4 and 12kWh BYD batteries.
I based my control on you’re config.


I changed some variables and this morning there was ±15sec difference between
Battery Power Forecast and the real charge/discharge power from the battery.
But now there is already 27 seconds difference.

Hi

I’m trying to use the “def_current_state” function but can’t make it work. Would appreciate some help. My understanding is that if you set “def_current_state” = true the def load will be running in the current period, even if it’s not optimal. Typically to not turn off a load thats running. Is this correct?

I have an example below. I set “def_current_state” = true but the result is sensor.p_deferrable0 = 0.0.

curl -i -H "Content-Type: application/json" -X POST -d '{
      "load_cost_forecast":[1.075, 1.075, 1.001, 1.001, 0.971, 0.971, 0.942, 0.942, 0.946, 0.946, 0.938, 0.938, 0.938, 0.938, 0.937, 0.937, 0.938, 0.938, 0.984, 0.984, 1.048, 1.048, 1.29, 1.29, 1.521, 1.521, 1.524, 1.524, 1.483, 1.483, 1.432, 1.432, 1.379, 1.379, 1.361, 1.361, 1.431, 1.431, 1.498, 1.498, 1.553, 1.553, 1.643, 1.643, 1.684, 1.684, 1.713, 1.713, 1.612, 1.612, 1.573, 1.573, 1.529, 1.529, 1.451, 1.451],
      "prod_price_forecast":[0.777, 0.777, 0.717, 0.717, 0.693, 0.693, 0.67, 0.67, 0.677, 0.677, 0.671, 0.671, 0.671, 0.671, 0.67, 0.67, 0.671, 0.671, 0.707, 0.707, 0.758, 0.758, 0.952, 0.952, 1.137, 1.137, 1.139, 1.139, 1.107, 1.107, 1.066, 1.066, 1.023, 1.023, 1.009, 1.009, 1.065, 1.065, 1.119, 1.119, 1.163, 1.163, 1.235, 1.235, 1.268, 1.268, 1.291, 1.291, 1.21, 1.21, 1.179, 1.179, 1.144, 1.144, 1.081, 1.081],
      "pv_power_forecast":[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, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 8.0, 91.0, 989.0, 1983.0, 3862.0, 5691.0, 6836.0, 7316.0, 7659.0, 7538.0, 7369.0, 7138.0, 6727.0, 6151.0, 5419.0, 4404.0, 3338.0, 2203.0, 1144.0, 374.0, 317.0, 238.0, 115.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
      "prediction_horizon":56,
      "alpha": 0.0,
      "beta": 1.0,
      "num_def_loads": 3,
      "num_lags":96,
      "P_deferrable_nom":[
            2200.0,
            1400,
            2000
          ],
      "treat_def_as_semi_cont": [true, true, true],
      "def_current_state": [
                        true,
                        false,
                        false],
      "def_total_hours":[
                        6.5,
                        0.0,
                        0],
      "soc_init": 0.74,
      "set_def_constant": [false,
                          false,false]
      }' http://localhost:5000/action/naive-mpc-optim
2024-09-30 20:15:32,185 - web_server - INFO - Passed runtime parameters: {'load_cost_forecast': [1.075, 1.075, 1.001, 1.001, 0.971, 0.971, 0.942, 0.942, 0.946, 0.946, 0.938, 0.938, 0.938, 0.938, 0.937, 0.937, 0.938, 0.938, 0.984, 0.984, 1.048, 1.048, 1.29, 1.29, 1.521, 1.521, 1.524, 1.524, 1.483, 1.483, 1.432, 1.432, 1.379, 1.379, 1.361, 1.361, 1.431, 1.431, 1.498, 1.498, 1.553, 1.553, 1.643, 1.643, 1.684, 1.684, 1.713, 1.713, 1.612, 1.612, 1.573, 1.573, 1.529, 1.529, 1.451, 1.451], 'prod_price_forecast': [0.777, 0.777, 0.717, 0.717, 0.693, 0.693, 0.67, 0.67, 0.677, 0.677, 0.671, 0.671, 0.671, 0.671, 0.67, 0.67, 0.671, 0.671, 0.707, 0.707, 0.758, 0.758, 0.952, 0.952, 1.137, 1.137, 1.139, 1.139, 1.107, 1.107, 1.066, 1.066, 1.023, 1.023, 1.009, 1.009, 1.065, 1.065, 1.119, 1.119, 1.163, 1.163, 1.235, 1.235, 1.268, 1.268, 1.291, 1.291, 1.21, 1.21, 1.179, 1.179, 1.144, 1.144, 1.081, 1.081], 'pv_power_forecast': [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, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 8.0, 91.0, 989.0, 1983.0, 3862.0, 5691.0, 6836.0, 7316.0, 7659.0, 7538.0, 7369.0, 7138.0, 6727.0, 6151.0, 5419.0, 4404.0, 3338.0, 2203.0, 1144.0, 374.0, 317.0, 238.0, 115.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'prediction_horizon': 56, 'alpha': 0.0, 'beta': 1.0, 'num_def_loads': 3, 'num_lags': 96, 'P_deferrable_nom': [2200.0, 1400, 2000], 'treat_def_as_semi_cont': [True, True, True], 'def_current_state': [True, False, False], 'def_total_hours': [6.5, 0.0, 0], 'soc_init': 0.74, 'set_def_constant': [False, False, False]}
2024-09-30 20:16:26,552 - web_server - INFO - Publishing data to HASS instance
2024-09-30 20:16:26,561 - web_server - INFO - Successfully posted to sensor.p_pv_forecast = 1.61
2024-09-30 20:16:26,566 - web_server - INFO - Successfully posted to sensor.p_load_forecast = 941.34
2024-09-30 20:16:26,571 - web_server - INFO - Successfully posted to sensor.p_deferrable0 = 0.0
2024-09-30 20:16:26,576 - web_server - INFO - Successfully posted to sensor.p_deferrable1 = 0.0
2024-09-30 20:16:26,580 - web_server - INFO - Successfully posted to sensor.p_deferrable2 = 0.0
2024-09-30 20:16:26,585 - web_server - INFO - Successfully posted to sensor.p_batt_forecast = 0.0
2024-09-30 20:16:26,589 - web_server - INFO - Successfully posted to sensor.soc_batt_forecast = 74.0
2024-09-30 20:16:26,594 - web_server - INFO - Successfully posted to sensor.p_grid_forecast = 939.73
2024-09-30 20:16:26,598 - web_server - INFO - Successfully posted to sensor.total_cost_fun_value = 17.18
2024-09-30 20:16:26,601 - web_server - INFO - Successfully posted to sensor.optim_status = Optimal
2024-09-30 20:16:26,606 - web_server - INFO - Successfully posted to sensor.unit_load_cost = 1.075
2024-09-30 20:16:26,611 - web_server - INFO - Successfully posted to sensor.unit_prod_price = 0.777

As the EMHASS system is not directly interacting with your inverter I think you have to look at the Node-Red to inverter configuration.

I’m not familiar with Solaredge API or Modbus TCP interface but what I understand is that you can use Modbus to control the battery through the Solaredge inverter?

I have a Sonnen battery which presents a RESTful API for real time control of the battery and is easy to send a kW value using sensor.p_batt_forecast.

So do you use something like this with node-red-contrib-modbus which is the real time interface for Solaredge inverter or do you use a REST API which I understand is also available but not real time?

To use the sensor.p_batt_forecast kW signal from EMHASS and command your SolarEdge inverter for battery charging/discharging, you will likely need to use Modbus TCP rather than a RESTful command, as SolarEdge primarily supports Modbus for direct control over the battery.

How to Command the SolarEdge Inverter via Modbus TCP:

1. Modbus TCP Protocol

  • Modbus TCP is the protocol you’ll use to send commands to the inverter over its IP address.
  • You would use a Modbus write command to control charging or discharging power to the battery.

2. Relevant Modbus Registers

For the SolarEdge hybrid inverter (like the SE5K-RWS48BEN4), the following Modbus registers are typically used to control battery operation:

  • Register 62852: Battery charge power command (in Watts).
  • Register 62853: Battery discharge power command (in Watts).

3. Node-RED Modbus TCP Configuration

In Node-RED, you’ll use a Modbus Write Node to send the command to the inverter:

  • Server: This is the IP address of your SolarEdge inverter.
  • Port: The default Modbus TCP port is 502.
  • Unit ID: Set this to 1 (the default for SolarEdge devices).
  • Register Address: Depending on whether you want to charge or discharge the battery, use the appropriate register:
    • 62852 for charging power.
    • 62853 for discharging power.
  • Payload: The value of sensor.p_batt_forecast multiplied by 1000 (to convert kW to W), as the registers accept values in Watts.

Example Node-RED Flow:

  1. Get forecast: Fetch the sensor.p_batt_forecast value using an HTTP Request Node from Home Assistant.
  2. Modbus TCP Write Node:
  • Use a function node in Node-RED to check the value of sensor.p_batt_forecast.
  • If the value is positive (indicating charging), write it to register 62852.
  • If the value is negative (indicating discharging), write the absolute value to register 62853.

4. Command via REST API (Alternative)

If you prefer using HTTP requests and SolarEdge’s monitoring API for higher-level data but don’t need real-time control, the SolarEdge cloud API allows you to monitor battery performance. However, control commands for real-time battery operation are generally performed using Modbus TCP, not via a RESTful API.

Key Points:

  • Modbus TCP is used for real-time battery control.
  • You send a write command to the inverter’s Modbus registers (e.g., 62852 for charge power, 62853 for discharge power).
  • Use Node-RED’s Modbus Write node to execute commands based on the EMHASS sensor.p_batt_forecast.

This setup ensures you’re using the forecast from EMHASS to dynamically control the battery, maximizing energy efficiency based on real-time or predicted solar and grid conditions.