EMHASS: An Energy Management for Home Assistant

General question to all of you with electrical cars or PHEV. How did you integrate it into EMHASS? I am trying with deferrable load, but the coding is a nightmare :-(. Maybe some of you can share some examples? I want to charge when prices are low as my tariff changes every hour. Any help is appreciated.

I have my EV charging integrated and my prices change every 5 minutes.

I set EV_total_hours based on the difference between the charge limit and current state of charge divided by my charging rate. If the EV isn’t plugged in I set the hours to 0.

With my EV automation I set the charging_amps based on the power level planned by EMHASS.

Here is my plan for tomorrow, I charges the home battery once solar starts production, waits for the cheapest of the day and starts charging the EV from grid and solar, then you can see in the afternoon the. EV charging curve follows the solar curve to consume all excess production.

      - name: def_total_hours_ev
        unique_id: 7663c831-7d49-4d62-a358-d743ddd25284
        state:
          "{{max(0,is_state('automation.p_deferreable3_automation_ev_tessie','on')|abs
          * (is_state('sensor.m3p_t_charging', ['charging', 'stopped']) | abs)
          * (70*(states('number.m3p_t_charge_limit')|int(0) - states('sensor.m3p_t_battery_level')|int(0))/100
          * (is_state('device_tracker.m3p_t_location_2','home')|abs)
          / states('sensor.p_nom_ev')|float(0.001)*1000 +0.5)|float(0)|round(0) + states('input_number.ev_boost_hours')|int(0))}}"

2 Likes

First of all: Huge Thanks for creating and maintaining this awesome addon

For me upgrading to 0.12.1 unfortunately killed my PV Configuration.
I had configured my PV System with multiple Inverters and orientations quite exatcly with a stunning good forecast over the last weeks. After the update the PV Section was deactivated as you explained. But after reactivating all my settings were overwritten with some default options. And even more, the AddonBackup does not include the Config.
But it seems to me i am the only one having this kind of problem after the update.

//edit:
I restored the backup. PV System gone nonetheless. Then i recreated the PV System and updated again. This time. All config is preserved. Don’t know what happened the first time…

Is it possible to provide heating_rate as a list? I tried to do that but it didn’t seem to work. My air-to-air heat pump heats a lot more effectively when it’s a bit warmer outside and that might be a useful thing for emhass to know as well.

1 Like

Finaly got around to upgrading EMHASS from 0.10.6 to 0.12.2. However It seems to be forecasting some inapropriate battery activity? Shouldn’t be charging to 100% at all today as prices are flat and no sun for the day. 0.10.6 forecast only one charge for the day to about 50%.
Any ideas?

Don’t know if I sould roll back or it’s something simple that I’ve missed in the config.

Logs:

2025-01-02 10:24:29,228 - web_server - INFO -  >> Obtaining params: 
2025-01-02 10:24:29,229 - web_server - INFO - Passed runtime parameters: {'prod_price_forecast': [0.04, 0.03, 0.01, -0.01, 0.03, 0.06, 0.05, 0.05, 0.03, 0.03, 0.04, 0.05, 0.07, 0.08, 0.06, 0.07, 0.06, 0.06, 0.06, 0.08, 0.12, 0.11, 0.08, 0.09, 0.08, 0.08, 0.08, 0.08, 0.09, 0.09, 0.09, 0.09, 0.09, 0.08, 0.09, 0.09, 0.09, 0.09], 'load_cost_forecast': [0.12, 0.12, 0.1, 0.08, 0.12, 0.15, 0.14, 0.14, 0.12, 0.12, 0.12, 0.13, 0.13, 0.14, 0.12, 0.13, 0.11, 0.11, 0.11, 0.14, 0.17, 0.17, 0.16, 0.17, 0.16, 0.16, 0.16, 0.16, 0.17, 0.17, 0.17, 0.17, 0.17, 0.16, 0.17, 0.17, 0.17, 0.18], 'pv_power_forecast': [2213, 1645, 2398, 2870, 3017, 2396, 1748, 1494, 1490, 1463, 1372, 1313, 1203, 1023, 845, 707, 491, 248, 72, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 140, 465, 746, 1007, 1232, 1442, 1624, 1796, 1963, 2054, 1989, 1914, 1806, 1811, 1918, 2014, 2109, 2116, 2085, 1991, 1839, 1613, 1313, 952, 577, 245, 63, 0, 0, 0, 0, 0, 0, 0, 0], 'load_power_forecast': [664, 731, 737, 717, 605, 504, 506, 663, 1173, 605, 682, 677, 508, 444, 511, 403, 428, 380, 397, 393, 447, 432, 445, 516, 471, 536, 487, 560, 404, 388, 416, 375, 361, 411, 425, 386, 387, 423, 429, 409, 400, 421, 426, 493, 525, 506, 472, 413, 510], 'prediction_horizon': 38, '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.06, 'soc_final': 0, 'alpha': 1, 'beta': 0}
2025-01-02 10:24:29,229 - web_server - INFO -  >> Setting input data dict
2025-01-02 10:24:29,229 - web_server - INFO - Setting up needed data
2025-01-02 10:24:29,237 - web_server - INFO - Retrieve hass get data method initiated...
2025-01-02 10:24:32,320 - web_server - INFO - Retrieving weather forecast data using method = list
2025-01-02 10:24:32,324 - web_server - INFO -  >> Performing naive MPC optimization...
2025-01-02 10:24:32,324 - web_server - INFO - Performing naive MPC optimization
2025-01-02 10:24:32,336 - web_server - INFO - Perform an iteration of a naive MPC controller
2025-01-02 10:24:32,396 - web_server - WARNING - Solver default unknown, using default
Welcome to the CBC MILP Solver 
Version: 2.10.3 
Build Date: Dec 15 2019 
command line - /usr/local/lib/python3.11/dist-packages/pulp/solverdir/cbc/linux/64/cbc /tmp/90d6cf3f1fdb4bd68121c88b7eae2a64-pulp.mps -max -timeMode elapsed -branch -printingOptions all -solution /tmp/90d6cf3f1fdb4bd68121c88b7eae2a64-pulp.sol (default strategy 1)
At line 2 NAME          MODEL
At line 3 ROWS
At line 800 COLUMNS
At line 6033 RHS
At line 6829 BOUNDS
At line 7400 ENDATA
Problem MODEL has 795 rows, 494 columns and 4548 elements
Coin0008I MODEL read with 0 errors
Option for timeMode changed from cpu to elapsed
Continuous objective value is 4.03771 - 0.00 seconds
Cgl0003I 0 fixed, 0 tightened bounds, 79 strengthened rows, 76 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 2 strengthened rows, 0 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 1 strengthened rows, 0 substitutions
Cgl0004I processed model has 517 rows, 378 columns (226 integer (226 of which binary)) and 4101 elements
Cbc0038I Initial state - 37 integers unsatisfied sum - 13.6676
Cbc0038I Pass   1: suminf.    0.00000 (0) obj. -0.805143 iterations 147
Cbc0038I Solution found of -0.805143
Cbc0038I Relaxing continuous gives -0.878613
Cbc0038I Before mini branch and bound, 189 integers at bound fixed and 68 continuous
Cbc0038I Full problem 517 rows 378 columns, reduced to 32 rows 26 columns
Cbc0038I Mini branch and bound improved solution from -0.878613 to -1.04658 (0.04 seconds)
Cbc0038I Freeing continuous variables gives a solution of -1.05345
Cbc0038I Round again with cutoff of -1.34044
Cbc0038I Pass   2: suminf.    0.75708 (6) obj. -1.34044 iterations 46
Cbc0038I Solution found of -1.34044
Cbc0038I Relaxing continuous gives -1.41704
Cbc0038I Before mini branch and bound, 185 integers at bound fixed and 62 continuous
Cbc0038I Full problem 517 rows 378 columns, reduced to 59 rows 38 columns
Cbc0038I Mini branch and bound improved solution from -1.41704 to -1.44194 (0.06 seconds)
Cbc0038I Round again with cutoff of -1.93821
Cbc0038I Pass   3: suminf.    3.18065 (13) obj. -1.93821 iterations 47
Cbc0038I Pass   4: suminf.    2.87620 (15) obj. -1.93821 iterations 79
Cbc0038I Pass   5: suminf.    2.59648 (12) obj. -1.93821 iterations 63
Cbc0038I Pass   6: suminf.    1.92025 (11) obj. -1.93821 iterations 20
Cbc0038I Pass   7: suminf.    1.87652 (11) obj. -1.93821 iterations 12
Cbc0038I Pass   8: suminf.    2.84035 (11) obj. -1.93821 iterations 103
Cbc0038I Pass   9: suminf.    2.49764 (10) obj. -1.93821 iterations 70
Cbc0038I Pass  10: suminf.    1.94236 (8) obj. -1.93821 iterations 21
Cbc0038I Pass  11: suminf.    2.36730 (11) obj. -1.93821 iterations 67
Cbc0038I Pass  12: suminf.    1.81154 (9) obj. -1.93821 iterations 14
Cbc0038I Pass  13: suminf.    1.54358 (6) obj. -1.93821 iterations 59
Cbc0038I Pass  14: suminf.    0.98340 (6) obj. -1.93821 iterations 14
Cbc0038I Pass  15: suminf.    0.83400 (5) obj. -1.93821 iterations 35
Cbc0038I Pass  16: suminf.    0.69806 (4) obj. -1.93821 iterations 22
Cbc0038I Pass  17: suminf.    0.48331 (4) obj. -1.93821 iterations 30
Cbc0038I Pass  18: suminf.    0.87213 (5) obj. -1.93821 iterations 27
Cbc0038I Pass  19: suminf.    0.59974 (5) obj. -1.93821 iterations 18
Cbc0038I Pass  20: suminf.    0.45271 (2) obj. -1.93821 iterations 19
Cbc0038I Pass  21: suminf.    0.31940 (3) obj. -1.93821 iterations 13
Cbc0038I Pass  22: suminf.    0.45247 (2) obj. -1.93821 iterations 22
Cbc0038I Pass  23: suminf.    0.17382 (3) obj. -1.93821 iterations 21
Cbc0038I Pass  24: suminf.    0.31638 (2) obj. -1.93821 iterations 23
Cbc0038I Pass  25: suminf.    0.11000 (2) obj. -1.93821 iterations 16
Cbc0038I Pass  26: suminf.    0.45247 (2) obj. -1.93821 iterations 16
Cbc0038I Pass  27: suminf.    4.01882 (13) obj. -1.93821 iterations 91
Cbc0038I Pass  28: suminf.    2.13362 (11) obj. -1.93821 iterations 48
Cbc0038I Pass  29: suminf.    0.50734 (4) obj. -1.93821 iterations 49
Cbc0038I Pass  30: suminf.    0.54234 (3) obj. -1.93821 iterations 20
Cbc0038I Pass  31: suminf.    0.11013 (2) obj. -1.93821 iterations 22
Cbc0038I Pass  32: suminf.    0.45263 (2) obj. -1.93821 iterations 16
Cbc0038I No solution found this major pass
Cbc0038I Before mini branch and bound, 151 integers at bound fixed and 27 continuous
Cbc0038I Full problem 517 rows 378 columns, reduced to 309 rows 176 columns - 20 fixed gives 250, 136 - ok now
Cbc0038I Full problem 517 rows 378 columns, reduced to 210 rows 119 columns
Cbc0038I Mini branch and bound improved solution from -1.44194 to -1.62859 (0.18 seconds)
Cbc0038I Round again with cutoff of -2.53371
Cbc0038I Pass  32: suminf.    5.92198 (22) obj. -2.53371 iterations 32
Cbc0038I Pass  33: suminf.    7.32244 (24) obj. -2.53371 iterations 86
Cbc0038I Pass  34: suminf.    6.68602 (25) obj. -2.53371 iterations 35
Cbc0038I Pass  35: suminf.    5.04045 (18) obj. -2.53371 iterations 58
Cbc0038I Pass  36: suminf.    4.50450 (17) obj. -2.53371 iterations 28
Cbc0038I Pass  37: suminf.    5.00945 (20) obj. -2.53371 iterations 68
Cbc0038I Pass  38: suminf.    4.97149 (21) obj. -2.53371 iterations 3
Cbc0038I Pass  39: suminf.    3.74150 (15) obj. -2.53371 iterations 79
Cbc0038I Pass  40: suminf.    2.95019 (12) obj. -2.53371 iterations 20
Cbc0038I Pass  41: suminf.    3.17078 (12) obj. -2.53371 iterations 58
Cbc0038I Pass  42: suminf.    2.84565 (12) obj. -2.53371 iterations 19
Cbc0038I Pass  43: suminf.    3.50750 (11) obj. -2.53371 iterations 71
Cbc0038I Pass  44: suminf.    2.82237 (11) obj. -2.53371 iterations 62
Cbc0038I Pass  45: suminf.    2.69945 (11) obj. -2.53371 iterations 9
Cbc0038I Pass  46: suminf.    2.73356 (11) obj. -2.53371 iterations 52
Cbc0038I Pass  47: suminf.    2.49942 (12) obj. -2.53371 iterations 10
Cbc0038I Pass  48: suminf.    3.50094 (12) obj. -2.53371 iterations 94
Cbc0038I Pass  49: suminf.    2.31215 (12) obj. -2.53371 iterations 50
Cbc0038I Pass  50: suminf.    2.04605 (10) obj. -2.53371 iterations 14
Cbc0038I Pass  51: suminf.    3.47499 (12) obj. -2.53371 iterations 57
Cbc0038I Pass  52: suminf.    3.01679 (10) obj. -2.53371 iterations 8
Cbc0038I Pass  53: suminf.    2.47631 (9) obj. -2.53371 iterations 68
Cbc0038I Pass  54: suminf.    2.29435 (9) obj. -2.53371 iterations 8
Cbc0038I Pass  55: suminf.    2.84025 (8) obj. -2.53371 iterations 81
Cbc0038I Pass  56: suminf.    2.65283 (9) obj. -2.53371 iterations 11
Cbc0038I Pass  57: suminf.    2.50417 (10) obj. -2.53371 iterations 31
Cbc0038I Pass  58: suminf.    2.35852 (10) obj. -2.53371 iterations 10
Cbc0038I Pass  59: suminf.    3.23552 (10) obj. -2.53371 iterations 53
Cbc0038I Pass  60: suminf.    3.14836 (9) obj. -2.53371 iterations 6
Cbc0038I Pass  61: suminf.    2.11841 (9) obj. -2.53371 iterations 41
Cbc0038I No solution found this major pass
Cbc0038I Before mini branch and bound, 168 integers at bound fixed and 33 continuous
Cbc0038I Full problem 517 rows 378 columns, reduced to 288 rows 163 columns - 20 fixed gives 229, 123 - ok now
Cbc0038I Full problem 517 rows 378 columns, reduced to 193 rows 108 columns
Cbc0038I Mini branch and bound did not improve solution (0.24 seconds)
Cbc0038I After 0.24 seconds - Feasibility pump exiting with objective of -1.62859 - took 0.17 seconds
Cbc0012I Integer solution of -1.6285871 found by feasibility pump after 0 iterations and 0 nodes (0.24 seconds)
Cbc0038I Full problem 517 rows 378 columns, reduced to 306 rows 174 columns - 19 fixed gives 250, 136 - ok now
Cbc0038I Full problem 517 rows 378 columns, reduced to 250 rows 136 columns
Cbc0012I Integer solution of -1.8756384 found by DiveCoefficient after 572 iterations and 0 nodes (0.39 seconds)
Cbc0031I 129 added rows had average density of 7.5116279
Cbc0013I At root node, 129 cuts changed objective from -3.9232146 to -2.2687993 in 14 passes
Cbc0014I Cut generator 0 (Probing) - 304 row cuts average 2.4 elements, 0 column cuts (0 active)  in 0.010 seconds - new frequency is 1
Cbc0014I Cut generator 1 (Gomory) - 149 row cuts average 26.2 elements, 0 column cuts (0 active)  in 0.008 seconds - new frequency is 1
Cbc0014I Cut generator 2 (Knapsack) - 37 row cuts average 2.2 elements, 0 column cuts (0 active)  in 0.006 seconds - new frequency is 1
Cbc0014I Cut generator 3 (Clique) - 0 row cuts average 0.0 elements, 0 column cuts (0 active)  in 0.000 seconds - new frequency is -100
Cbc0014I Cut generator 4 (MixedIntegerRounding2) - 188 row cuts average 4.0 elements, 0 column cuts (0 active)  in 0.009 seconds - new frequency is 1
Cbc0014I Cut generator 5 (FlowCover) - 0 row cuts average 0.0 elements, 0 column cuts (0 active)  in 0.002 seconds - new frequency is -100
Cbc0014I Cut generator 6 (TwoMirCuts) - 220 row cuts average 41.5 elements, 0 column cuts (0 active)  in 0.009 seconds - new frequency is 1
Cbc0010I After 0 nodes, 1 on tree, -1.8756384 best solution, best possible -2.2687993 (0.49 seconds)
Cbc0012I Integer solution of -1.8783743 found by DiveCoefficient after 980 iterations and 2 nodes (0.65 seconds)
Cbc0012I Integer solution of -1.9693093 found by DiveCoefficient after 1012 iterations and 2 nodes (0.73 seconds)
Cbc0038I Full problem 517 rows 378 columns, reduced to 324 rows 198 columns - 13 fixed gives 285, 172 - still too large
Cbc0038I Full problem 517 rows 378 columns, reduced to 278 rows 170 columns - too large
Cbc0012I Integer solution of -2.0023076 found by DiveCoefficient after 3712 iterations and 66 nodes (2.11 seconds)
Cbc0012I Integer solution of -2.0032 found by DiveCoefficient after 3781 iterations and 66 nodes (2.17 seconds)
Cbc0012I Integer solution of -2.0475046 found by DiveCoefficient after 3831 iterations and 67 nodes (2.23 seconds)
Cbc0038I Full problem 517 rows 378 columns, reduced to 202 rows 114 columns
Cbc0012I Integer solution of -2.0554546 found by DiveCoefficient after 6108 iterations and 170 nodes (2.90 seconds)
Cbc0001I Search completed - best objective -2.055454552629599, took 10298 iterations and 264 nodes (4.18 seconds)
Cbc0032I Strong branching done 1706 times (20336 iterations), fathomed 23 nodes and fixed 129 variables
Cbc0035I Maximum depth 17, 1400 variables fixed on reduced cost
Cuts at root node changed objective from -3.92321 to -2.2688
Probing was tried 397 times and created 4049 cuts of which 0 were active after adding rounds of cuts (0.140 seconds)
Gomory was tried 396 times and created 879 cuts of which 0 were active after adding rounds of cuts (0.169 seconds)
Knapsack was tried 396 times and created 115 cuts of which 0 were active after adding rounds of cuts (0.107 seconds)
Clique was tried 14 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)
MixedIntegerRounding2 was tried 396 times and created 866 cuts of which 0 were active after adding rounds of cuts (0.158 seconds)
FlowCover was tried 14 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.002 seconds)
TwoMirCuts was tried 396 times and created 520 cuts of which 0 were active after adding rounds of cuts (0.088 seconds)
ZeroHalf was tried 1 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)
ImplicationCuts was tried 238 times and created 74 cuts of which 0 were active after adding rounds of cuts (0.003 seconds)
Result - Optimal solution found
Objective value:                2.05545455
Enumerated nodes:               264
Total iterations:               10298
Time (CPU seconds):             3.81
Time (Wallclock seconds):       4.20
Option for printingOptions changed from normal to all
Total time (CPU seconds):       3.81   (Wallclock seconds):       4.20
2025-01-02 10:24:36,617 - web_server - INFO - Status: Optimal
2025-01-02 10:24:36,617 - web_server - INFO - Total value of the Cost function = 2.06
2025-01-02 10:24:36,857 - web_server - INFO -  >> Obtaining params: 
2025-01-02 10:24:36,858 - web_server - INFO - Passed runtime parameters: {}
2025-01-02 10:24:36,858 - web_server - INFO -  >> Setting input data dict
2025-01-02 10:24:36,858 - web_server - INFO - Setting up needed data
2025-01-02 10:24:36,867 - web_server - INFO -  >> Publishing data...
2025-01-02 10:24:36,867 - web_server - INFO - Publishing data to HASS instance
2025-01-02 10:24:36,888 - web_server - INFO - Successfully posted to sensor.p_pv_forecast = 2213
2025-01-02 10:24:36,899 - web_server - INFO - Successfully posted to sensor.p_load_forecast = 664
2025-01-02 10:24:36,912 - web_server - INFO - Successfully posted to sensor.p_deferrable0 = 0.0
2025-01-02 10:24:36,921 - web_server - INFO - Successfully posted to sensor.p_deferrable1 = 0.0
2025-01-02 10:24:36,929 - web_server - INFO - Successfully posted to sensor.p_batt_forecast = -3300.0
2025-01-02 10:24:36,938 - web_server - INFO - Successfully posted to sensor.soc_batt_forecast = 17.36
2025-01-02 10:24:36,950 - web_server - INFO - Successfully posted to sensor.p_grid_forecast = 1751.0
2025-01-02 10:24:36,969 - web_server - INFO - Successfully posted to sensor.total_cost_fun_value = -0.71
2025-01-02 10:24:36,978 - web_server - INFO - Successfully posted to sensor.optim_status = Optimal
2025-01-02 10:24:36,987 - web_server - INFO - Successfully posted to sensor.unit_load_cost = 0.12
2025-01-02 10:24:36,996 - web_server - INFO - Successfully posted to sensor.unit_prod_price = 0.04

Config:

{
  "battery_charge_efficiency": 0.95,
  "battery_charge_power_max": 3300,
  "battery_discharge_efficiency": 0.9,
  "battery_discharge_power_max": 3300,
  "battery_dynamic_max": 0.9,
  "battery_dynamic_min": -0.9,
  "battery_maximum_state_of_charge": 1,
  "battery_minimum_state_of_charge": 0,
  "battery_nominal_energy_capacity": 13800,
  "battery_target_state_of_charge": 0,
  "compute_curtailment": false,
  "continual_publish": false,
  "costfun": "profit",
  "delta_forecast_daily": 1,
  "end_timesteps_of_each_deferrable_load": [
    0,
    0
  ],
  "historic_days_to_retrieve": 9,
  "inverter_is_hybrid": false,
  "load_cost_forecast_method": "hp_hc_periods",
  "load_forecast_method": "naive",
  "load_negative": false,
  "load_offpeak_hours_cost": 0.1419,
  "load_peak_hour_periods": {
    "period_hp_1": [
      {
        "start": "02:54"
      },
      {
        "end": "15:24"
      }
    ],
    "period_hp_2": [
      {
        "start": "17:24"
      },
      {
        "end": "20:24"
      }
    ]
  },
  "load_peak_hours_cost": 0.1907,
  "logging_level": "INFO",
  "lp_solver": "default",
  "lp_solver_path": "empty",
  "maximum_power_from_grid": 14490,
  "maximum_power_to_grid": 9000,
  "method_ts_round": "first",
  "modules_per_string": [
    17
  ],
  "nominal_power_of_deferrable_loads": [
    1300,
    7300
  ],
  "number_of_deferrable_loads": 2,
  "operating_hours_of_each_deferrable_load": [
    2,
    1
  ],
  "optimization_time_step": 30,
  "photovoltaic_production_sell_price": 0.1419,
  "production_price_forecast_method": "constant",
  "pv_inverter_model": [
    "Fronius_International_GmbH__Fronius_Primo_6_0_1_208_240__240V_"
  ],
  "pv_module_model": [
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M"
  ],
  "sensor_linear_interp": [
    "sensor.house_power_consumption_less_deferrables"
  ],
  "sensor_power_load_no_var_loads": "sensor.house_power_consumption_less_deferrables",
  "sensor_power_photovoltaics": "sensor.sonnenbatterie_84324_production_w",
  "sensor_replace_zero": [
    "sensor.sonnenbatterie_84324_production_w"
  ],
  "set_battery_dynamic": true,
  "set_deferrable_load_single_constant": [
    false,
    false
  ],
  "set_deferrable_startup_penalty": [
    0,
    0
  ],
  "set_nocharge_from_grid": false,
  "set_nodischarge_to_grid": false,
  "set_total_pv_sell": false,
  "set_use_battery": true,
  "set_use_pv": true,
  "set_zero_min": true,
  "start_timesteps_of_each_deferrable_load": [
    0,
    0
  ],
  "strings_per_inverter": [
    1
  ],
  "surface_azimuth": [
    10
  ],
  "surface_tilt": [
    21
  ],
  "treat_deferrable_load_as_semi_cont": [
    true,
    true
  ],
  "weather_forecast_method": "scrapper",
  "weight_battery_charge": 1,
  "weight_battery_discharge": 1
}

It should probably look like this:

“weight_battery_charge”: 1,
“weight_battery_discharge”: 1

Should both be 0.

I previously had a PR accepted resolving this but they seem to have crept in with bad values.

1 Like

Thanks Mark that fixed it.

2 Likes

That PR was merged and now the default values are 0. But when upgrading the add-on HA will keep the previous values stored in the configuration. A fresh installation with with a sweep of any previous configuration (but a manual backup of your system config: PV system, etc) would solve this. A new user should directly see the default 0 values

Very interesting. Yes it is possible to update the code to accept a list of values. We can consider this in future releases

1 Like

Thank you @markpurcell , so I am on the right track, first perform a day-ahead optimisation save soc values as dh_soc_batt_forecast followed by MPC with receding prediction every 5 min to cope with changing pv forecasts and load forecasts. using dh_soc_batt_forecast values as soc_init and soc_final in the MPC optimisation.

Unfortunately I can’t access the Ford API to gather battery state etc. It’s an issue which has been addressed, however the Ford API changes a lot and third party apps get banned with the Ford account being blocked, so maybe someone has a workaround :slight_smile:

Hi guys! Is anyone running the Nordpool integration with the latest 12.x? I cannot get it to work. Is the documentation correct? If anyone got it working could they please send me in correct direction :slight_smile:

Thanks a bunch!

Just upgraded from v. 10 to v. 12 - it works, however the supervisor log is flooded with warning messages indicating the various “options” do not “exist in the schema for EMHASS”, below an example. Anyone got a clue as to what drives this?

2025-01-02 11:52:31.872 WARNING (MainThread) [supervisor.addons.options] Option 'battery_discharge_power_max' does not exist in the schema for EMHASS (5b918bf2_emhass)

2025-01-02 11:52:31.873 WARNING (MainThread) [supervisor.addons.options] Option 'battery_charge_power_max' does not exist in the schema for EMHASS (5b918bf2_emhass)

2025-01-02 11:52:31.873 WARNING (MainThread) [supervisor.addons.options] Option 'battery_discharge_efficiency' does not exist in the schema for EMHASS (5b918bf2_emhass)

2025-01-02 11:52:31.873 WARNING (MainThread) [supervisor.addons.options] Option 'battery_charge_efficiency' does not exist in the schema for EMHASS (5b918bf2_emhass)

2025-01-02 11:52:31.873 WARNING (MainThread) [supervisor.addons.options] Option 'battery_minimum_state_of_charge' does not exist in the schema for EMHASS (5b918bf2_emhass)

2025-01-02 11:52:31.873 WARNING (MainThread) [supervisor.addons.options] Option 'battery_maximum_state_of_charge' does not exist in the schema for EMHASS (5b918bf2_emhass)

2025-01-02 11:52:31.873 WARNING (MainThread) [supervisor.addons.options] Option 'battery_target_state_of_charge' does not exist in the schema for EMHASS (5b918bf2_emhass)

2025-01-02 11:57:31.827 WARNING (MainThread) [supervisor.addons.options] Option 'logging_level' does not exist in the schema for EMHASS (5b918bf2_emhass)

2025-01-02 11:57:31.828 WARNING (MainThread) [supervisor.addons.options] Option 'costfun' does not exist in the schema for EMHASS (5b918bf2_emhass)

2025-01-02 11:57:31.828 WARNING (MainThread) [supervisor.addons.options] Option 'sensor_power_photovoltaics' does not exist in the schema for EMHASS (5b918bf2_emhass)

2025-01-02 11:57:31.829 WARNING (MainThread) [supervisor.addons.options] Option 'sensor_power_load_no_var_loads' does not exist in the schema for EMHASS (5b918bf2_emhass)

2025-01-02 11:57:31.829 WARNING (MainThread) [supervisor.addons.options] Option 'set_total_pv_sell' does not exist in the schema for EMHASS (5b918bf2_emhass)

2025-01-02 11:57:31.829 WARNING (MainThread) [supervisor.addons.options] Option 'set_nocharge_from_grid' does not exist in the schema for EMHASS (5b918bf2_emhass)

2025-01-02 11:57:31.829 WARNING (MainThread) [supervisor.addons.options] Option 'set_nodischarge_to_grid' does not exist in the schema for EMHASS (5b918bf2_emhass)

2025-01-02 11:57:31.829 WARNING (MainThread) [supervisor.addons.options] Option 'maximum_power_from_grid' does not exist in the schema for EMHASS (5b918bf2_emhass)

2025-01-02 11:57:31.829 WARNING (MainThread) [supervisor.addons.options] Option 'maximum_power_to_grid' does not exist in the schema for EMHASS (5b918bf2_emhass)

2025-01-02 11:57:31.829 WARNING (MainThread) [supervisor.addons.options] Option 'number_of_deferrable_loads' does not exist in the schema for EMHASS (5b918bf2_emhass)

2025-01-02 11:57:31.829 WARNING (MainThread) [supervisor.addons.options] Option 'list_nominal_power_of_deferrable_loads' does not exist in the schema for EMHASS (5b918bf2_emhass)

2025-01-02 11:57:31.829 WARNING (MainThread) [supervisor.addons.options] Option 'list_operating_hours_of_each_deferrable_load' does not exist in the schema for EMHASS (5b918bf2_emhass)

2025-01-02 11:57:31.829 WARNING (MainThread) [supervisor.addons.options] Option 'list_start_timesteps_of_each_deferrable_load' does not exist in the schema for EMHASS (5b918bf2_emhass)

2025-01-02 11:57:31.829 WARNING (MainThread) [supervisor.addons.options] Option 'list_end_timesteps_of_each_deferrable_load' does not exist in the schema for EMHASS (5b918bf2_emhass)

2025-01-02 11:57:31.829 WARNING (MainThread) [supervisor.addons.options] Option 'list_peak_hours_periods_start_hours' does not exist in the schema for EMHASS (5b918bf2_emhass)

2025-01-02 11:57:31.829 WARNING (MainThread) [supervisor.addons.options] Option 'list_peak_hours_periods_end_hours' does not exist in the schema for EMHASS (5b918bf2_emhass)

2025-01-02 11:57:31.829 WARNING (MainThread) [supervisor.addons.options] Option 'list_treat_deferrable_load_as_semi_cont' does not exist in the schema for EMHASS (5b918bf2_emhass)

2025-01-02 11:57:31.829 WARNING (MainThread) [supervisor.addons.options] Option 'list_set_deferrable_load_single_constant' does not exist in the schema for EMHASS (5b918bf2_emhass)

2025-01-02 11:57:31.829 WARNING (MainThread) [supervisor.addons.options] Option 'list_set_deferrable_startup_penalty' does not exist in the schema for EMHASS (5b918bf2_emhass)

sorry - thought I sufficiently “Ctrl-F”-ed but clearly not…

Didn’t work for me. I rolled back to previous version and get it worked again.

did you roll back nordpool or emhass (or both)? Both seems to have updated the latest week.

EMHASS back to 0.11.2.
Nordpool works fine (HACS).

1 Like

First I’d like to say thanks for very intressting project. I have installed it and after a huge struggle I have a working EMHASS but, I need your help to achive all my goals. Maybe my questions is to simple, but I’m just a begeener so plese help me to finish my EMHASS.

My first problem is prediction, that is not usefull because of a quite bed prediction of battery usage in first place. The battery management is my first and most important goal. The battery should charge when PV production is sufficient or when electricity price is low, and discharge when PV production is low or when price is high. My last prediction seems like EMHASS want to charge with the most expensive energy. I have tried to adjust EMHASS according solutions from this post or from the documentation so my configuration.yaml and shell_commands are here:

{
  "battery_charge_efficiency": -0.95,
  "battery_charge_power_max": 10000,
  "battery_discharge_efficiency": 0.95,
  "battery_discharge_power_max": 10000,
  "battery_dynamic_max": 0.9,
  "battery_dynamic_min": -0.9,
  "battery_maximum_state_of_charge": 1,
  "battery_minimum_state_of_charge": 0.1,
  "battery_nominal_energy_capacity": 12000,
  "battery_target_state_of_charge": 0.3,
  "compute_curtailment": false,
  "continual_publish": true,
  "costfun": "self-consumption",
  "delta_forecast_daily": 1,
  "end_timesteps_of_each_deferrable_load": [
    0
  ],
  "historic_days_to_retrieve": 9,
  "inverter_is_hybrid": true,
  "load_cost_forecast_method": "hp_hc_periods",
  "load_forecast_method": "naive",
  "load_negative": false,
  "load_offpeak_hours_cost": 1,
  "load_peak_hour_periods": {
    "period_hp_1": [
      {
        "start": "07:00"
      },
      {
        "end": "10:00"
      }
    ],
    "period_hp_2": [
      {
        "start": "16:00"
      },
      {
        "end": "21:00"
      }
    ]
  },
  "load_peak_hours_cost": 2,
  "logging_level": "INFO",
  "lp_solver": "COIN_CMD",
  "lp_solver_path": "/usr/bin/cbc",
  "maximum_power_from_grid": 11000,
  "maximum_power_to_grid": 11000,
  "method_ts_round": "first",
  "modules_per_string": [
    12,
    18
  ],
  "nominal_power_of_deferrable_loads": [
    3000
  ],
  "number_of_deferrable_loads": 1,
  "operating_hours_of_each_deferrable_load": [
    0
  ],
  "optimization_time_step": 60,
  "photovoltaic_production_sell_price": 1,
  "production_price_forecast_method": "constant",
  "pv_inverter_model": [
    "Shenzhen_Growatt_New_Energy_Co___Ltd___MIN_10000TL_XH_US__240V_"
  ],
  "pv_module_model": [
    "Trina_Solar_TSM_400DE09_08"
  ],
  "sensor_linear_interp": [
    "sensor.power_load_no_var_loads"
  ],
  "sensor_power_load_no_var_loads": "sensor.power_load_no_var_loads",
  "sensor_power_photovoltaics": "sensor.solax_pv_power_total",
  "sensor_replace_zero": [
    "sensor.solax_pv_power_total"
  ],
  "set_battery_dynamic": false,
  "set_deferrable_load_single_constant": [
    false
  ],
  "set_deferrable_startup_penalty": [
    0
  ],
  "set_nocharge_from_grid": false,
  "set_nodischarge_to_grid": true,
  "set_total_pv_sell": false,
  "set_use_battery": true,
  "set_zero_min": true,
  "start_timesteps_of_each_deferrable_load": [
    0
  ],
  "strings_per_inverter": [
    2
  ],
  "surface_azimuth": [
    145
  ],
  "surface_tilt": [
    10,
    30
  ],
  "treat_deferrable_load_as_semi_cont": [
    true
  ],
  "weather_forecast_method": "solcast",
  "weight_battery_charge": 0,
  "weight_battery_discharge": 0
}
----------------------------------------
publish_data: 'curl -i -H "Content-Type:application/json" -X POST -d ''{}'' http://localhost:5000/action/publish-data'

update_weather_cache: "curl -i -H 'Content-Type:application/json' -X POST -d '{}' http://localhost:5000/action/weather-forecast-cache"

load_power_forecast: >
  curl -i -H "Content-Type: application/json" -X POST -d '{"load_power_forecast":{{[states('sensor.power_load_no_var_loads')|int] +(states('input_text.fi_fo_buffer').split(',')|map('int')|list)[1:48]}}' http://localhost:5000/action/dayahead-optim

nordpool_forecast: >
  curl -i -H "Content-Type: application/json" -X POST -d '{
    "load_cost_forecast": {{ ((state_attr("sensor.nordpool_cost", "raw_today") | map(attribute="value") | list) + (state_attr("sensor.nordpool_cost", "raw_tomorrow") | map(attribute="value") | list))[now().hour:][:24] | tojson }},
    "prod_price_forecast": {{ ((state_attr("sensor.nordpool_sell", "raw_today") | map(attribute="value") | list) + (state_attr("sensor.nordpool_sell", "raw_tomorrow") | map(attribute="value") | list))[now().hour:][:24] | tojson }},
  }' http://localhost:5000/action/dayahead-optim

solcast_dayahead_optim: >
  curl -i -H 'Content-Type: application/json' -X POST -d '{"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/dayahead-optim

ml_forecast_model_fit: >
  curl -i -H "Content-Type:application/json" -X POST -d 
    '{"days_to_retrieve": 9,
    "model_type": "load_forecast","var_model": "sensor.power_load_no_var_loads",
    "sklearn_model": "KNeighborsRegressor",
    "num_lags": 24,
    "split_date_delta": "24h",
    "perform_backtest": true}' 
    http://localhost:5000/action/forecast-model-fit   
forecast_model_predict: >
  curl -i -H "Content-Type: application/json" -X POST -d 
    '{"model_type": "load_forecast", "var_model": "sensor.power_load_no_var_loads"}' http://localhost:5000/action/forecast-model-predict    
ml_forecast_model_tune: >
  curl -i -H "Content-Type:application/json" -X POST -d 
    '{"var_model":"sensor.power_load_no_var_loads"}' http://localhost:5000/action/forecast-model-tune

dayahead_optim: > 
  curl -i -H 'Content-Type: application/json' -X POST -d '{
    "load_cost_forecast": {{ ((state_attr("sensor.nordpool_cost", "raw_today") | map(attribute="value") | list) + (state_attr("sensor.nordpool_cost", "raw_tomorrow") | map(attribute="value") | list))[now().hour:][:24] | tojson }},
    "prod_price_forecast": {{ ((state_attr("sensor.nordpool_sell", "raw_today") | map(attribute="value") | list) + (state_attr("sensor.nordpool_sell", "raw_tomorrow") | map(attribute="value") | list))[now().hour:][:24] | tojson }},
    "prediction_horizon": {{ min(24, (((state_attr("sensor.nordpool_kwh_se4_sek_2_00_0", "raw_today") | map(attribute="value") | list) + (state_attr("sensor.nordpool_kwh_se4_sek_2_00_0", "raw_tomorrow") | map(attribute="value") | list))[now().hour:][:24] | list | length)) }},
    "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 }},
    "load_power_forecast":{{[states('sensor.power_load_no_var_loads')|int] +(states('input_text.fi_fo_buffer').split(',')|map('int')|list)[1:48]}},
    "delta_forecast": 2
  }' http://localhost:5000/action/dayahead-optim

post_mpc_optim: >
  curl -i -H "Content-Type: application/json" -X POST -d '{
    "load_cost_forecast": {{ ((state_attr("sensor.nordpool_cost", "raw_today") | map(attribute="value") | list) + (state_attr("sensor.nordpool_cost", "raw_tomorrow") | map(attribute="value") | list))[now().hour:][:24] | tojson }},
    "prod_price_forecast": {{ ((state_attr("sensor.nordpool_sell", "raw_today") | map(attribute="value") | list) + (state_attr("sensor.nordpool_sell", "raw_tomorrow") | map(attribute="value") | list))[now().hour:][:24] | tojson }},
    "prediction_horizon": {{ min(24, ((state_attr("sensor.nordpool_kwh_se4_sek_2_00_0", "raw_today") | map(attribute="value") | list + state_attr("sensor.nordpool_kwh_se4_sek_2_00_0", "raw_tomorrow") | map(attribute="value") | list)[now().hour:][:48] | list | length)) }},
    "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 }},
    "weather_forecast_cache": {"weather_forecast_cache_only":true},
    "load_power_forecast": {{ ([states('sensor.power_load_no_var_loads') | int(0)]+(states('input_text.fi_fo_buffer') | default('') | string).split(',') | map('int') | list) [:48]| tojson }},
    "soc_init": {{ max(0, states("sensor.solax_battery_capacity") | int(0)) / 100 }},
    "soc_final": 0.3,
    "P_deferrable_nom": [{{ max(states("sensor.easee_garage_power") | int, 3000) }}, 0],
    "weight_battery_discharge": 0,
    "weight_battery_charge": 0,
    "delta_forecast_daily": 2,
    "alpha": 1,
    "beta": 0
  }' http://localhost:5000/action/naive-mpc-optim


Anyone else using a Huawei Hybrid inverter (solar and battery)?

I have the EMHASS day-ahead functionality working fine, but I’m currently refining the actual control of charging and discharging the battery. I use the Huawei Solar integration over Modbus TCP (via the Wi-Fi dongle in the inverter).

Using the EMHASS sensors p_hybrid_inverter, p_batt_forecast, and p_grid, I’ve created a template that determines one of four operating modes for the battery:

  • Do Nothing
  • Follow Grid
  • Forcible Charge
  • Forcible Discharge

The Huawei battery is set to Time of Use (TOU) mode, and every 30 seconds, a script runs that triggers the huawei_solar.forcible_discharge or huawei_solar.forcible_charge action with a specific power value based on the operating mode.

Is anyone else using this battery in combination with EMHASS? I find the 30-second interval quite slow but haven’t been able to achieve faster updates using Modbus TCP. Switching to Huawei’s “Maximise Self-Consumption” mode when EMHASS decides the battery should follow the grid could potentially allow faster responsiveness. However, I haven’t been able to reliably set those modes via the Home Assistant integration.

This discussion might not be entirely suited for the main EMHASS thread, but I’m interested in hearing others’ experiences with controlling Huawei batteries through Home Assistant.

1 Like

Check this out:

can’t seem to DM you (yet) @zlakes01
Had a look at the repo. So you are trowing predbat into the mix to control charging and dicharging of your battery? There seem to be a lot of overlap between emhass en predbat so to me it seems it might clutter/complicate things (even more :slight_smile: ) in my setup.