EMHASS: An Energy Management for Home Assistant

Also you need to provide the model_type otherwise we don’t what model you’re trying to fit/predict.

I did all the changes you suggested including the model_type, and still not starting the predict endpoint. I tried to run the command through the Terminal and this is the message I’ve got: curl: (7) Failed to connect to localhost 5000 after 1 ms: Couldn't connect to server I looked into the HA supervisor and core logs and I couldn’t see anything related to EMHASS.

Hey again david, I upgraded my HA to 2023.10 and now I can see the response of every service I ran. Here’s the response I got after running the predict endpoint command

stdout: "HTTP/1.1 400 BAD REQUEST\r\nContent-Length: 167\r\nContent-Type: text/html; charset=utf-8\r\nDate: Fri, 06 Oct 2023 19:26:10 GMT\r\nServer: waitress\r\n\r\n<!doctype html>\n<html lang=en>\n<title>400 Bad Request</title>\n<h1>Bad Request</h1>\n<p>The browser (or proxy) sent a request that this server could not understand.</p>"
stderr: "% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current\n                                 Dload  Upload   Total   Spent    Left  Speed\n\r  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0\r100   494  100   167  100   327  11686  22883 --:--:-- --:--:-- --:--:-- 35285"
returncode: 0

Hope it’s clear now.

Finally, I’ve managed to get it to work after updating my HA instance and tweaking the quote marks. Here’s the curl command that worked for me:

emhass_ml_temperature_predict: 'curl -i -H ''Content-Type:application/json'' -X POST -d ''{"model_type": "load_forecast", "var_model": "sensor.room_temperature", "days_to_retrieve": 30, "model_predict_publish": true, "model_predict_entity_id": "sensor.p_room_temperature_forecast_model", "model_predict_unit_of_measurement": "°C", "model_predict_friendly_name": "Room Temperature Forecast custom ML model"}'' http://localhost:5000/action/forecast-model-predict'

Thanks again david, Cheers.

1 Like

Great. Yes those quote marks are a pain.
However if you’re also using EMHASS for energy optimization then you need to change the model_type parameter to something else, otherwise you will overwrite your power load forecast model.

Change that for the fit, predict and tune calls to something else like this: "model_type": "room_temperature_forecast"

1 Like

Hey david, I start predicting my hot water temperature using the KNN. I run the fit endpoint everyday and the tune endpoint every week. I currently use 30 days of data and I noticed that the R² could really help to decide when the tune endpoint should be executed (e.g. an unexpected change in my hot water consumption or outdoor temperature). Therefore, I thought of using R² as an indicator in order to set the frequency at which the tune occurs. Is there anyway we can get the metric as an output?

Also, I made this visualization using Plotly integration for HA showing the future data. For those interested you can find the code here

image

4 Likes

Hi folks! New to emhass noob here… I’m trying to get everything set up, but I’m seem to be running into an issue with it not accepting the inverter model. I have a Solis S5-GC15K-LV, but it’s not in the list so I chose the only other 15kw Solis i could find in the list and input it as “Ningbo_Ginlong_Technologies_Co_0_Ltd_Solis_15K_US”.

2023-10-08 15:18:56,537 - web_server - ERROR - Exception on /action/dayahead-optim [POST]
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/dist-packages/pandas/core/indexes/base.py", line 3621, in get_loc
    return self._engine.get_loc(casted_key)
  File "pandas/_libs/index.pyx", line 136, in pandas._libs.index.IndexEngine.get_loc
  File "pandas/_libs/index.pyx", line 163, in pandas._libs.index.IndexEngine.get_loc
  File "pandas/_libs/hashtable_class_helper.pxi", line 5198, in pandas._libs.hashtable.PyObjectHashTable.get_item
  File "pandas/_libs/hashtable_class_helper.pxi", line 5206, in pandas._libs.hashtable.PyObjectHashTable.get_item
KeyError: 'Ningbo_Ginlong_Technologies_Co_0_Ltd_Solis_15K_US'
The above exception was the direct cause of the following exception:
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 179, 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 90, in set_input_data_dict
    P_PV_forecast = fcst.get_power_from_weather(df_weather)
  File "/usr/local/lib/python3.9/dist-packages/emhass/forecast.py", line 418, in get_power_from_weather
    inverter = cec_inverters[self.plant_conf['inverter_model'][i]]
  File "/usr/local/lib/python3.9/dist-packages/pandas/core/frame.py", line 3505, in __getitem__
    indexer = self.columns.get_loc(key)
  File "/usr/local/lib/python3.9/dist-packages/pandas/core/indexes/base.py", line 3623, in get_loc
    raise KeyError(key) from err
KeyError: 'Ningbo_Ginlong_Technologies_Co_0_Ltd_Solis_15K_US'

Any suggestions on what is wrong here?

(Also, lists linked in the documentation are from 2019 and neither my inverter or panels are in there… Are they not being updated?)

Does the addon work if you turn off the inverter option? Would suggest to work step by step and start with a very basic setup adding features one step at a time - i personally so not use the inverter settings, instead I push solcast pv forecast - based on the advice of @markpurcell

Oh, i got it now. Tried a different inverter and now it works, probably an issue with my formatting. Now i just have to wait two days for the necessary history (i hope).

Hi, me again. Got EMHASS working now (more or less), but I,m not sure I got the prices added in and working right: I use hourly prices from the Entso-E integration. Prices are included by these rest commands, copied from a forum and converted from nordpool to entso-e by me. They do give the correct prices when i test them in the template editor so I think they should work.

rest_command:
  trigger_entsoe_forecast:
    url: http://localhost:5000/action/dayahead-optim
    method: POST
    content_type: "application/json"
    timeout: 300
    payload: >-
      {
      "load_cost_forecast":{{((state_attr('sensor.strompriser_entso_e_nettleie_average_electricity_price_today', 'prices') | list))[now().hour:][:24] }},
      "prod_price_forecast":{{((state_attr('sensor.strompriser_entso_e_salg_average_electricity_price_today', 'prices') | list))[now().hour:][:24] }}
      }


Could someone explain what the four variables in the graph are? I’d think at least one of the blue ones should be the electricity price?

I use shell command, but see my entso-e syntax:

Shellcommand : "curl -i -H \"Content-Type: application/json\" -X POST -d '{
  \"load_cost_forecast\":{{((state_attr('sensor.entso_e_api_average_electricity_price_today', 'prices_today') | map(attribute='price') | list  + state_attr('sensor.entso_e_api_average_electricity_price_today', 'prices_tomorrow') | map(attribute='price') | list))[now().hour:][:24] }},
  \"prod_price_forecast\":{{((state_attr('sensor.entso_e_api_average_electricity_price_today', 'prices_today') | map(attribute='price') | list  + state_attr('sensor.entso_e_api_average_electricity_price_today', 'prices_tomorrow') | map(attribute='price') | list))[now().hour:][:24] }},
  \"prediction_horizon\":{{min(24, ((state_attr('sensor.entso_e_api_average_electricity_price_today', 'prices_today') | map(attribute='price') | list  + state_attr('sensor.entso_e_api_average_electricity_price_today', 'prices_tomorrow') | map(attribute='price') | list)[now().hour:][:24]|list|length))}},
  \"soc_init\":{{((states('sensor.growatt_growatt_battery_soc') | float(0))) / 100 }},
  \"soc_final\":0.10,
  \"def_total_hours\":[2],
  \"pv_power_forecast\":{{([states('sensor.solcast_pv_forecast_power_now')|int(0)] + state_attr('sensor.solcast_pv_forecast_forecast_today', 'detailedHourly')|selectattr('period_start','gt',utcnow()) | map(attribute='pv_estimate')|map('multiply',1000)|map('int')|list + state_attr('sensor.solcast_pv_forecast_forecast_tomorrow', 'detailedHourly')|selectattr('period_start','gt',utcnow()) | map(attribute='pv_estimate')|map('multiply',1000)|map('int')|list)| tojson}}
  }' http://localhost:5000/action/naive-mpc-optim"

It would help if you could also show the template editor output so we can see what is being fed into EMHASS.

The “prices” attribute of entso-e provides an array with time and prices as “sub attributes” for both today and tomorrow, similar to noordpool. If @ThorAlex follows my code that should work.

As you well know the format for yaml is very precise, a comma in the wrong place mucks every thing up.

Here is my rest command:

rest_command:
  naive_mpc_optim:
    url: http://localhost:5000/action/naive-mpc-optim
    method: POST
    content_type: 'application/json'
    payload: >-
      {
        "prod_price_forecast": {{
          ([states('sensor.amber_feed_in_price')|float(0)] +
          (state_attr('sensor.amber_feed_in_forecast', 'forecasts')|map(attribute='per_kwh')|list))
          | tojson 
        }},
        "load_cost_forecast": {{
          ([states('sensor.amber_general_price')|float(0)] + 
          state_attr('sensor.amber_general_forecast', 'forecasts') |map(attribute='per_kwh')|list) 
          | tojson 
        }},
        "load_power_forecast": {{
          ([states('sensor.power_load_no_var_loads')|int] +
          (states('input_text.fi_fo_buffer').split(', ')|map('multiply',1000)|map('int')|list)[1:]
          )| tojson 
        }},
        
        "pv_power_forecast": {{
          ([states('sensor.solaredge_nopowerlimit')|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
        }},
        "prediction_horizon": {{
          min(48, (state_attr('sensor.amber_feed_in_forecast', 'forecasts')|map(attribute='per_kwh')|list|length)+1)
        }},
        "alpha": 1,
        "beta": 0,
        "num_def_loads": 6,
        "def_total_hours": {{[states('sensor.def_total_hours_pool_filter')|int(0),
                              states('sensor.def_total_hours_pool_heatpump')|int(0),
                              states('sensor.def_total_hours_ev')|int(0),
                              states('sensor.def_total_hours_hvac')|int(0),
                              states('sensor.def_total_hours_hws')|int(0),
                              states('sensor.def_total_hours_ev2')|int(0)]}},
        "P_deferrable_nom":  [945,5000, 
                              {{ states('sensor.p_nom_ev')}}, 
                              4000, 
                              600, 
                              {{ states('sensor.p_nom_ev2')}}],
        "treat_def_as_semi_cont": [1, 1, 0, 0, 1, 0],
        "set_def_constant": [0, 0, 0, 0, 0, 0],
        "soc_init": {{ (states('sensor.gateway_battery')|int(0))/100 }},
        "soc_final": {{ (states('sensor.gateway_battery')|int(0))/100 }}
      }

and here is the output:

Ok, I updated it with Ronald’s example, still does not seem to work right.

  trigger_entsoe_forecast:
    url: http://localhost:5000/action/dayahead-optim
    method: POST
    content_type: "application/json"
    timeout: 300
    payload: >-
      {
        "load_cost_forecast\":{{((state_attr('sensor.strompriser_entso_e_nettleie_average_electricity_price_today', 'prices_today') | map(attribute='price') | list  + state_attr('sensor.strompriser_entso_e_nettleie_average_electricity_price_today', 'prices_tomorrow') | map(attribute='price') | list))[now().hour:][:24] }},
        "prod_price_forecast\":{{((state_attr('sensor.strompriser_entso_e_salg_average_electricity_price_today', 'prices_today') | map(attribute='price') | list  + state_attr('sensor.strompriser_entso_e_salg_average_electricity_price_today', 'prices_tomorrow') | map(attribute='price') | list))[now().hour:][:24] }},
        "prediction_horizon\":{{min(24, ((state_attr('sensor.strompriser_entso_e_nettleie_average_electricity_price_today', 'prices_today') | map(attribute='price') | list  + state_attr('sensor.strompriser_entso_e_nettleie_average_electricity_price_today', 'prices_tomorrow') | map(attribute='price') | list)[now().hour:][:24]|list|length))}}
      }

I think you need backslash before and after like this:

\"load_cost_forecast\":
\"prod_price_forecast\":

Do you get the emhass webpage when writing http://localhost:5000 in the browser?

Thanks, I should have seen that… No immediate reaction, but it might take a while?

Do you get this webpage when writing http://localhost:5000 in the browser? Try with your Home Assistant server ip-adresse instead.

You can try without the backslash also like this: "load_cost_forecast":

You can also log rest commands in the log. You must first enable debug for rest commands. The you must search in the Home Assistant log for rest command you execute.

logger:
  default: info
  logs:
    homeassistant.components.rest: debug
2 Likes

I came accros this EMHASS project a week ago and I beliefe this might be exactly what i’m looking for. I’m in the middle of an “energy transition”: full electric WP for heating just installed, second 3kWp solar system to be installed next month, 5kW battery underway and I’m about to change over from a (Dutch) peak/off-peak electricity contract to a dynamical contract with changing tariffs every hour.

On installing EMHASS I got stuck in the beginning of the proces:
I installed the Add-on via Supervisor. When I tried to start EMHASS I got a pop-up:
“Go to configuration. not a valid value.”
So I switched to the configuration UI and made some basic/default settings. Trying to save this configuration returns with an error: "Failed to save add-on configuration, not a valid value. "
Even when I change and unchange any setting in the default configuration and saving it after that I get the same error.

I hope anyone can point me in the right direction to find a solution for this.
I’m running HomeAssistant (2023.10.1) with Supervisor (2023.10) on a Raspberry Pi 4 ( OS 5.10.103)

This is great news, I have been seeing the rest command in the logs when I get an error, but this debug command will greatly assist debugging.

Btw, you can also access the web interface directly from the Add-On Web UI button now, both locally and remotely.