EMHASS: An Energy Management for Home Assistant

I have a sonnen battery with internal inverter (hybrid system).

The PV inverter is a fronius but I don’t touch that inverter in my system. My system is well balanced between battery (13.8kWh) + home consumption and PV output (5kWp) so I don’t need to curtail PV output much but I can curtail using amber app (amber support curtailing PV via Fronius inverter except its 100% curtailment or 0% no inbetween) or you can control curtailment via Fronius inverter using modbus I believe.

Sonnen offers a REST API that allows direct control of the charge discharge rate and is a good quality german LFP battery, assembled in SA I think. The Sonnen API Documentation is here along with how I’ve set up my system.

1 Like

Thank you. I guess my question is then, which ones are less difficult to implement in HA? Seems that Huawei and Sonnen are two which are easier to implement. Are there systems which do not allow controlling charging and discharging (regardless of HA)?

1 Like

Surprisingly, Tesla Powerwalls are very difficult to control.

Most of the other solutions; Fronious, Sungrow, GoodWe, Victron, Sonnen have open interfaces; ModBus/ RestAPI.

Some options have read-only, but for EMHASS to work best you ideally have read and control access.

Have a look through here with solutions that people have had success with.

1 Like

I have been interested in the vehicle-to-grid scenario for a while (even started a company to try and manufacture V2G enable EV conversion kits for Toyota hiluxes :slight_smile: ). Anyway recently I got connected with someone who is really serious about establishing a company that specialises in bidirectional chargers and software for V2X use cases. I have of course been selling the virtues of EMHASS.

Has anyone thought about the changes necessary to EMHASS to model both stationary storage and storage in a bidirectional enable EV? I can imagine using the current stationary battery support and modelling EV charging as a def load but that won’t result in the two being considered as an coupled system.

Would love thoughts from the brainstrust here. This is happening in Australia if anyone is interested in getting involved.

I think the only difference between a bidirectional EV battery and “stationary storage” would be the need for some forecast of availability of the EV. A calendar that stores the expected trips to be made in the EV each day and the distance to be travelled.

This schedule would then have to be used in the EV battery forecast.

Robert, that can be arranged and could manifest as additional constraints in the model. The thing I am unsure of is how to compute an appropriate value of def_total_hours taking discharging into account. Furthermore the “battery forecast” also influences def_total_hours and there is not concept of a target SOC (that corresponds to the EV SOC) by a certain time when a trip is started.

While not strictly a V2X use case, what about if you want to set a target EV SOC by a certain time? My approach would be

  • calculate SOC delta from current SOC and based on p_nom for the EV charger determine if can make it to the target SOC in the time remaining.
  • if yes, then use end time to ensure charging happens for before the target time
  • if no, then (if possible) raise p_nom and recalculate whether the target SOC can be hit. if the EV def load is defined to support range of power values then maybe I would change this to only schedule EV charging at p_nom.

It is interesting to see how many heuristics need to be applied outside of the optimisation. Also the need to perhaps repeat the optimisation adjusting values (according to heuritics) until you get an optimal result OR you tell the user to reduce their target SOC.

Feels like I am over thinking this!!!

Hello together, I really want emhass to work on my system. Without the termal model, everything is working fine:

trigger_tibber_solcast_mpc_zwei: “curl -i -H ‘Content-Type: application/json’ -X POST -d ‘{"pv_power_forecast": {{ [states(‘sensor.inverter_power_kombiniert’)|int(0)]| list + (state_attr(‘sensor.solcast_pv_forecast_prognose_heute’, ‘detailedHourly’) | map(attribute=‘pv_estimate’) | map(‘multiply’, 1000) | map(‘round’, 0) | list + state_attr(‘sensor.solcast_pv_forecast_prognose_morgen’, ‘detailedHourly’) | map(attribute=‘pv_estimate’) | map(‘multiply’, 1000) | map(‘round’, 0) | list)[now().hour:][:23] }}, "load_cost_forecast":{{states(‘sensor.tibber_forecast’) }}, "alpha":1, "beta":0,"prediction_horizon":24, "soc_init":{{states(‘sensor.battery_state_of_capacity’)|float(0)/100 }},"soc_final":0.6}’ http://localhost:5000/action/naive-mpc-optim

→ All three p_deferrable are working.
Now i wanted to implement ther thermal model:

publish_data_thermal: “curl -i -H ‘Content-Type:application/json’ -X POST -d ‘{"def_load_config": [{"thermal_config": {}},{},{}] }’ http://localhost:5000/action/publish-data

trigger_mpc_thermal: “curl -i -H ‘Content-Type: application/json’ -X POST -d ‘{"pv_power_forecast": {{ [states(‘sensor.inverter_power_kombiniert’)|int(0)]| list + (state_attr(‘sensor.solcast_pv_forecast_prognose_heute’, ‘detailedHourly’) | map(attribute=‘pv_estimate’) | map(‘multiply’, 1000) | map(‘round’, 0) | list + state_attr(‘sensor.solcast_pv_forecast_prognose_morgen’, ‘detailedHourly’) | map(attribute=‘pv_estimate’) | map(‘multiply’, 1000) | map(‘round’, 0) | list)[now().hour:][:23] }}, "load_cost_forecast":{{states(‘sensor.tibber_forecast’) }}, "alpha":1, "beta":0,"prediction_horizon":24, "soc_init":{{states(‘sensor.battery_state_of_capacity’)|float(0)/100 }},"soc_final":0.6, "outdoor_temperature_forecast": [17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17], "def_load_config": [{ "thermal_config": { "heating_rate": 8.63,"cooling_constant": 0.036,"overshoot_temperature": 75,"start_temperature": {{ states(‘sensor.warmwasseristtemperatur’) | float(0) }},"desired_temperatures": [{{ states(‘sensor.warmwasseristtemperatur’) | float(0) }}, {{ states(‘sensor.warmwasseristtemperatur’) | float(0) }}, {{ states(‘sensor.warmwasseristtemperatur’) | float(0) }}, {{ states(‘sensor.warmwasseristtemperatur’) | float(0) }}, {{ states(‘sensor.warmwasseristtemperatur’) | float(0) }}, {{ states(‘sensor.warmwasseristtemperatur’) | float(0) }}, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55]}},{},{}],"num_def_loads": 3,"def_total_hours":[0,12,12],"treat_def_as_semi_cont": [1, 1, 1],"P_deferrable_nom":[2000, 670, 230]}’ http://localhost:5000/action/naive-mpc-optim

The protocoll:

2024-10-22 13:25:55,653 - web_server - INFO - Passed runtime parameters: {‘pv_power_forecast’: [10226, 3736, 4722, 3955, 2454, 582, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 612, 3082, 6137, 8174], ‘load_cost_forecast’: [0.2579, 0.261, 0.2771, 0.3014, 0.3044, 0.3405, 0.3612, 0.3092, 0.2918, 0.2874, 0.2787, 0.2697, 0.2726, 0.2711, 0.2725, 0.2756, 0.2849, 0.3023, 0.3791, 0.3914, 0.3263, 0.2974, 0.2852, 0.2754], ‘alpha’: 1, ‘beta’: 0, ‘prediction_horizon’: 24, ‘soc_init’: 0.08, ‘soc_final’: 0.6, ‘outdoor_temperature_forecast’: [17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17], ‘def_load_config’: [{‘thermal_config’: {‘heating_rate’: 8.63, ‘cooling_constant’: 0.036, ‘overshoot_temperature’: 75, ‘start_temperature’: 62.0, ‘desired_temperatures’: [62.0, 62.0, 62.0, 62.0, 62.0, 62.0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55]}}, {}, {}], ‘num_def_loads’: 3, ‘def_total_hours’: [0, 12, 12], ‘treat_def_as_semi_cont’: [1, 1, 1], ‘P_deferrable_nom’: [2000, 670, 230]}
2024-10-22 13:25:55,654 - web_server - INFO - >> Setting input data dict
2024-10-22 13:25:55,654 - web_server - INFO - Setting up needed data
2024-10-22 13:25:55,657 - web_server - INFO - Retrieve hass get data method initiated…
2024-10-22 13:26:01,430 - web_server - INFO - Retrieving weather forecast data using method = list
2024-10-22 13:26:01,431 - web_server - INFO - Retrieving data from hass for load forecast using method = naive
2024-10-22 13:26:01,432 - web_server - INFO - Retrieve hass get data method initiated…
2024-10-22 13:26:14,439 - web_server - INFO - >> Performing naive MPC optimization…
2024-10-22 13:26:14,439 - web_server - INFO - Performing naive MPC optimization
2024-10-22 13:26:14,452 - web_server - INFO - Perform an iteration of a naive MPC controller
2024-10-22 13:26:14,513 - web_server - DEBUG - Deferrable load 0: Proposed optimization window: 0 → 0
2024-10-22 13:26:14,513 - web_server - DEBUG - Deferrable load 0: Validated optimization window: 0 → 0
2024-10-22 13:26:14,516 - web_server - DEBUG - Deferrable load 1: Proposed optimization window: 0 → 0
2024-10-22 13:26:14,516 - web_server - DEBUG - Deferrable load 1: Validated optimization window: 0 → 0
2024-10-22 13:26:14,518 - web_server - DEBUG - Deferrable load 2: Proposed optimization window: 0 → 0
2024-10-22 13:26:14,518 - web_server - DEBUG - Deferrable load 2: Validated optimization window: 0 → 0
2024-10-22 13:26:14,907 - web_server - INFO - Status: Optimal
2024-10-22 13:26:14,907 - web_server - INFO - Total value of the Cost function = 1.64
2024-10-22 13:26:25,928 - web_server - INFO - Passed runtime parameters: {‘def_load_config’: [{‘thermal_config’: {}}, {}, {}]}
2024-10-22 13:26:25,928 - web_server - INFO - >> Setting input data dict
2024-10-22 13:26:25,928 - web_server - INFO - Setting up needed data
2024-10-22 13:26:25,931 - web_server - INFO - >> Publishing data…
2024-10-22 13:26:25,931 - web_server - INFO - Publishing data to HASS instance
2024-10-22 13:26:25,957 - web_server - INFO - Successfully posted to sensor.p_pv_forecast = 10226
2024-10-22 13:26:25,975 - web_server - INFO - Successfully posted to sensor.p_load_forecast = 219.67
2024-10-22 13:26:25,995 - web_server - INFO - Successfully posted to sensor.p_hybrid_inverter = 5226.0
2024-10-22 13:26:26,012 - web_server - INFO - Successfully posted to sensor.p_deferrable0 = 2000.0
2024-10-22 13:26:26,026 - web_server - INFO - Successfully posted to sensor.p_deferrable1 = 0.0
2024-10-22 13:26:26,041 - web_server - INFO - Successfully posted to sensor.p_deferrable2 = 0.0
2024-10-22 13:26:26,053 - web_server - INFO - Successfully posted to sensor.temp_predicted0 = 62.0
2024-10-22 13:26:26,067 - web_server - INFO - Successfully posted to sensor.p_batt_forecast = -5000.0
2024-10-22 13:26:26,082 - web_server - INFO - Successfully posted to sensor.soc_batt_forecast = 53.0
2024-10-22 13:26:26,097 - web_server - INFO - Successfully posted to sensor.p_grid_forecast = -3006.33
2024-10-22 13:26:26,114 - web_server - INFO - Successfully posted to sensor.total_cost_fun_value = 1.64
2024-10-22 13:26:26,127 - web_server - INFO - Successfully posted to sensor.optim_status = Optimal
2024-10-22 13:26:26,143 - web_server - INFO - Successfully posted to sensor.unit_load_cost = 0.2579
2024-10-22 13:26:26,156 - web_server - INFO - Successfully posted to sensor.unit_prod_price = 0.078

Last run optimization results table

index P_PV P_Load P_deferrable0 P_deferrable1 P_deferrable2 P_grid_pos P_grid_neg P_grid P_batt SOC_opt P_hybrid_inverter unit_load_cost unit_prod_price cost_profit cost_fun_profit predicted_temp_heater0 target_temp_heater0
2024-10-22 13:00:00+02:00 10226 219 2000 0 0 0 -3006 -3006 -5000 0.530 5226 0.258 0.078 0.234 0.234 62.00 62.0
2024-10-22 14:00:00+02:00 3736 243 0 0 0 0 0 0 -3492 0.844 243 0.261 0.078 -0.000 -0.000 69.01 62.0

The thermal_deferrable_load is my warm-water-tank (200L with a 2kW heating rod). I have 2 main problems:

  1. if i want all desired_temperatures = 55°C, but if the starting temperatur =47°C the model wants to heat with 20kw instead of 2kW.–> this is why i work with my real heating temperature. Any suggestion how to avoid this problem?
index P_PV P_Load P_deferrable0 P_deferrable1 P_deferrable2 P_grid_pos P_grid_neg P_grid P_batt SOC_opt P_hybrid_inverter unit_load_cost unit_prod_price cost_profit cost_fun_profit predicted_temp_heater0 target_temp_heater0
2024-10-22 10:00:00+02:00 750 238 20483 0 0 19341 0 19341 630 0.100 1380 0.292 0.078 -5.640 -5.640 47.00 55
2024-10-22 11:00:00+02:00 1233 204 2000 0 0 971 0 971 0 0.100 1233 0.278 0.078 -0.270 -0.270 124.58 55
2024-10-22 12:00:00+02:00 2437 206 2000 0 0 -230 0 -230 0 0.100 2437 0.265 0.078 0.061 0.061 94.48 55
2024-10-22 13:00:00+02:00 2812 219 2000 0 0 -592 0 -592 0 0.100 2812 0.258 0.078 0.153 0.153 75.22 55
2024-10-22 14:00:00+02:00 3736 243 2000 0 0 0 0 0 -1492 0.234 2243 0.261 0.078 -0.000 -0.000 62.89 55
2024-10-22 15:00:00+02:00 4722 220 0 0 0 0 -5216 -5216 714 0.170 5436 0.277 0.078 0.407 0.407 55.00 55
  1. The bigger problem: With the thermal model, the othe deferrable loads are not working anymore (always 0).

If needed I can post my emhass-addon yaml.
Thanks a lot!

For EV charging to a desired SOC by a desired time I utilize

I calculate def total hours by comparing current and desired SOC ~ 1 hr per 10% ( charging at 11 kW).

I time box the window by calculating how many times slots until the nominated end time and decrement def end.

I haven’t thought about discharging, but do have a V2L / V2H that could benefit from some discharge optimisation.

  1. Forecasting EV Availability: The system needs a way to predict when the EV will be available for V2G use, which requires an accurate schedule of the EV’s usage. A calendar-based forecast could store the times and distances of planned trips, influencing the charging/discharging strategy. This scheduling would also need to incorporate uncertainties like unexpected trips, affecting the battery availability.
  2. Coupling EV and Stationary Storage: Treating the EV battery and stationary storage, if it exists, as a combined resource is key to effective optimisation. The two batteries need to be modelled together to allow for shared storage capacity and integrated control, rather than treating the EV as a separate deferrable load. This requires a holistic approach to energy management, where both assets are managed based on the same objectives (e.g., self-consumption, peak shaving).
  3. State of Charge (SOC) Management: A critical aspect of V2G is ensuring the EV’s SOC meets specific targets by the time it’s needed for a trip. This introduces additional constraints to the optimisation, where the system must calculate whether the EV can reach a target SOC by a certain time and adjust charging/discharging power accordingly.
  4. Voltage Regulation and Grid Constraints: When many EVs participate in V2G in the same area, managing local voltage stability would become an issue I expect. EMHASS would need to incorporate voltage regulation strategies to prevent grid overloads or voltage sags, especially during periods of high demand or heavy discharging. I don’t think the NEM wholesale prices would be fine tuned to local street conditions so some alignment with or communication with local grid conditions might be required.

Good evening,

I’m looking for a setting to figure out the time when a deferable loads should start.

I would like to use it to display the time next to hour washing machine,… This way i can put the timer from the machine to the hour calculated by Emhass. Is there already an approach for this?

I already searched through these posts here and trough the docs but nothing mentions this use case?

Greets
Axe

Greetings Everyone,

v0.11.0 is here!

And therefore a lot of braking changes. This version includes the merge of the standalone and add-on modes which merge there parameter definitions and config file (config.json).
There will likely be some small bugs in this version so it is a good idea to be cautious when updating.

Changes

It would be recommended to either read the updated documentation and/or view the video discussing the changes before proceeding to this release of EMHASS.

Documentation: EMHASS & EMHASS-Add-on differences — emhass 0.11.0 documentation

Video: https://youtu.be/T85DAdXnGFY.

PR history: Standalone and Add-on merge by GeoDerp · Pull Request #334 · davidusb-geek/emhass · GitHub

Note: for addon users, parameters: sensor_linear_interp & sensor_replace_zero are brand new and will need to be setup to match your preferred sensors

There will also likely be some inconsistencies with the documentation (ie, places I have missed or spelling/grammar errors). If you find any please feel free to notify on GitHub.

5 Likes

I’m also an failing to schedule other loads when using the thermal model.

Please feel free to provide any additional contact to the issue below:

I have also started a discussion where we are sharing our experiences in setting up the thermal model, including some alternative approaches.

Hey Mark, this is the approach I also use in order to force charging by a certain time. How does the EV boost hours feature work? Do you turn off EMHASS scheduling and just charge the EV straight away for X hours?

Without trying to create a sense of competition :slight_smile: there is another optimisation framework called FlexMeasures which has a demo project exhibiting several of the requirements you mention Robert - V2G@Home Living Lab - Seita . They use Google Calendar as the mechanism to define vehicle availability.

Do you see a way to model EV storage and stationary storage in a coupled way using EMHASS today?

Regarding voltage regulation and grid constraints, I expect the project I referred to earlier will need to respond to dynamic operating envelopes. This could make for an interesting integration for Home Assistant !

That’s a cool thought. I also have a few non-smart devices. I think you could find it out by looking at the attributes of e.g. p_deferrable0, it has all the timeslots with the expected wattage, so you could iterate them and find out at which time it’s above zero.

Any idea if this is possible via automations from homeassistant?
Or does this require external scripts to run?

Thanks for the hard work.
I’m coming from the legacy add-on and had a look at the video but I’m not sure I completely got how to update to the new version, if this is happening correctly or if I’m doing something wrong.
I manually converted the config file into the new json format but I see a couple of odds things: the cost function is always back to profit, no matter what I select and I see some battery settings duplicated.
I also tried to uninstall and reinstall but the behaviour is the same.
Lastly, I’m not sure what I should do with sensor_linear_interp & sensor_replace_zero as they are parameters new to me.
Thanks

Screenshot 2024-10-26 alle 22.28.41

You can calculate this with some template code, which you could turn into a template helper.

First time window
{{(state_attr('sensor.p_deferrable5','deferrables_schedule')|selectattr('p_deferrable5','gt','0.0')|list).1}}


current_state:
{{states('sensor.p_deferrable5')}}

deferrable5_schedule:
{{state_attr('sensor.p_deferrable5','deferrables_schedule')}}

deferrable5_schedule > 0
{{state_attr('sensor.p_deferrable5','deferrables_schedule')|selectattr('p_deferrable5','gt','0.0')|list}}

2 Likes

ev_boost_hours just gets added to the calculation for SOC charging.

If the EV is not home or not plugged in I just schedule 0 hours, which helps with Roberts question above around scheduling. If the EV is available for charging I schedule hours, otherwise that power is allocated to something else.

      - name: def_total_hours_ev2
        unique_id: ba63549a-b9ac-4f44-8386-973855ec17e9
        state: "{{max(0,is_state('automation.p_deferable5_automation','on')|abs
          * (is_state('sensor.my_t_charging', ['charging', 'stopped'] ) | abs)
          * (65*(states('number.my_t_charge_limit')|int(0) - states('sensor.my_t_battery_level')|int(0))/100
          * (is_state('device_tracker.my_t_location','home')|abs)
          / states('sensor.p_nom_ev2')|float(0.001)*1000 +0.5)|float(0)|round(0) 
          + states('input_number.ev_boost_hours')|int(0))}}"
1 Like

Hey @110hs, thanks for the reply. I think both the cost and battery issues are genuine bugs and I’ll look into them (when I’m out of hospital for my partner :sweat_smile:)