EMHASS: An Energy Management for Home Assistant

I have Solax so the battery solution doesn’t suit me. I have used other parts of this repo.

By the way, is anyone here running EMHASS with Solax inverter + battery?

Hi @HansD I seem to have the same setup: SUN2000-6KTL-M1 (maybe you have different inverter), and Huawei battery stack. I have the dongle set to 'maximise self-consumption within the fusion solar app, what I see if you issue commands the self-consumption setting is overwritten. About 10-12 sec updates with TCP-IP, I use LAN cable.

With all the automations it works nicely it seems, battery follows the EMHASS optimisation good. Besides some experiments I did

This error comes out of the blue for me. I don’t do anything with temperatures.
What could be the issue, using latest version of EMHASS.

2025-01-04 10:23:24,704 - web_server - DEBUG - Converting param to config
2025-01-04 10:23:24,706 - web_server - INFO - Saved parameters from webserver
2025-01-04 10:23:42,102 - web_server - INFO -  >> Obtaining params: 
2025-01-04 10:23:42,103 - web_server - INFO - Passed runtime parameters: {'prediction_horizon': 28, 'pv_power_forecast': [523, 873, 1059, 1195, 1291, 1352, 1366, 1327, 1254, 1150, 1004, 813, 589, 372, 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, 153, 228, 301, 363, 407, 438, 456, 458, 443, 417, 381, 332, 269, 195, 123, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'num_def_loads': 2, 'P_deferrable_nom': [0, 0], 'def_total_hours': [0, 0], 'treat_def_as_semi_cont': [1, 1], 'set_def_constant': [1, 1], 'def_start_timestep': [0, 0], 'def_end_timestep': [0, 0], 'soc_init': 0.64, 'soc_final': 0.9, 'load_cost_forecast': [0.2751, 0.2751, 0.2729, 0.2729, 0.2748, 0.2748, 0.2746, 0.2746, 0.2815, 0.2815, 0.2841, 0.2841, 0.282, 0.282, 0.288, 0.288, 0.29, 0.29, 0.2841, 0.2841, 0.2747, 0.2747, 0.2677, 0.2677, 0.2628, 0.2628, 0.2532, 0.2532], 'prod_price_forecast': [0.1213, 0.1213, 0.1192, 0.1192, 0.121, 0.121, 0.1208, 0.1208, 0.1274, 0.1274, 0.1298, 0.1298, 0.1278, 0.1278, 0.1335, 0.1335, 0.1353, 0.1353, 0.1298, 0.1298, 0.1209, 0.1209, 0.1143, 0.1143, 0.1097, 0.1097, 0.1007, 0.1007], 'alpha': 1, 'beta': 0, 'load_power_forecast': [399, 300, 400, 600, 300, 200, 200, 200, 200, 300, 300, 200, 400, 200, 200, 400, 400, 400, 300, 300, 300, 600, 800, 500, 400, 400, 500, 500, 2400, 2300, 2400, 2400, 2300, 2400, 2400, 2400, 2300, 2400, 2400, 200, 200, 300, 300, 300, 300, 300, 300, 300]}
2025-01-04 10:23:42,103 - web_server - INFO -  >> Setting input data dict
2025-01-04 10:23:42,103 - web_server - INFO - Setting up needed data
2025-01-04 10:23:42,107 - web_server - ERROR - Exception on /action/naive-mpc-optim [POST]
Traceback (most recent call last):
  File "/usr/local/lib/python3.11/dist-packages/flask/app.py", line 1511, in wsgi_app
    response = self.full_dispatch_request()
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/flask/app.py", line 919, in full_dispatch_request
    rv = self.handle_user_exception(e)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/flask/app.py", line 917, in full_dispatch_request
    rv = self.dispatch_request()
         ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/flask/app.py", line 902, 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 388, in action_call
    input_data_dict = set_input_data_dict(
                      ^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/emhass/command_line.py", line 107, in set_input_data_dict
    params = utils.update_params_with_ha_config(
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/emhass/utils.py", line 185, in update_params_with_ha_config
    params['passed_data']['custom_predicted_temperature_id'][k].update(
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^
IndexError: list index out of range
2025-01-04 10:23:42,108 - web_server - INFO -  >> Obtaining params: 
2025-01-04 10:23:42,109 - web_server - INFO - Passed runtime parameters: {'publish_prefix': ''}
2025-01-04 10:23:42,109 - web_server - INFO -  >> Setting input data dict
2025-01-04 10:23:42,109 - web_server - INFO - Setting up needed data
2025-01-04 10:23:42,112 - web_server - INFO -  >> Publishing data...
2025-01-04 10:23:42,112 - web_server - INFO - Publishing data to HASS instance
2025-01-04 10:23:42,116 - web_server - INFO - Successfully posted to sensor.p_pv_forecast = 533
2025-01-04 10:23:42,119 - web_server - INFO - Successfully posted to sensor.p_load_forecast = 495
2025-01-04 10:23:42,122 - web_server - INFO - Successfully posted to sensor.p_hybrid_inverter = 533.0
2025-01-04 10:23:42,125 - web_server - INFO - Successfully posted to sensor.p_deferrable0 = 0.0
2025-01-04 10:23:42,127 - web_server - INFO - Successfully posted to sensor.p_batt_forecast = 0.0
2025-01-04 10:23:42,130 - web_server - INFO - Successfully posted to sensor.soc_batt_forecast = 86.03
2025-01-04 10:23:42,132 - web_server - INFO - Successfully posted to sensor.p_grid_forecast = -38.0
2025-01-04 10:23:42,134 - web_server - INFO - Successfully posted to sensor.total_cost_fun_value = 0.39
2025-01-04 10:23:42,136 - web_server - INFO - Successfully posted to sensor.optim_status = Optimal
2025-01-04 10:23:42,139 - web_server - INFO - Successfully posted to sensor.unit_load_cost = 0.2751
2025-01-04 10:23:42,141 - web_server - INFO - Successfully posted to sensor.unit_prod_price = 0.1213
2025-01-04 10:23:46,229 - web_server - INFO - EMHASS server online, serving index.html...

I’m currently trying to debug this.
You are passing the number_of_deferrable_loads parameter at runtime, could you please check if it is the same number set in your configuration?

This PR solves the issue PR#418 but still need to find the root cause.

Thanks @RikBast .
The logic I use now is

    {% set p_batt = states('sensor.p_batt_forecast') | float(0) %}  
    {% set p_grid = states('sensor.p_grid') | float(0) %}  
    {% if p_batt == 0 %}
      Do Nothing
    {% elif p_grid == 0 %}
      Follow Grid
    {% elif p_batt < 0 %}
      Forcible Charge
    {% elif p_batt > 0 %}
      Forcible Discharge
    {% else %}
      Unknown
    {% endif %}

For follow grid I now set the Huawei mode to “Maximise self consuption” and send a stop forcible charge command.
This is my automation

actions:
  - choose:
      - conditions:
          - condition: state
            entity_id: input_select.battery_control_mode
            state: Forcible Charge
        sequence:
          - action: huawei_solar.forcible_charge
            data:
              duration: 30
              power: "{{ states('sensor.p_batt_forecast') | int | abs }}"
              device_id: f0c20b3b4e7a1af202ae2bca230becbe
      - conditions:
          - condition: state
            entity_id: input_select.battery_control_mode
            state: Forcible Discharge
        sequence:
          - action: huawei_solar.forcible_discharge
            data:
              duration: 30
              power: "{{ states('sensor.p_batt_forecast') | int }}"
              device_id: f0c20b3b4e7a1af202ae2bca230becbe
      - conditions:
          - condition: state
            entity_id: input_select.battery_control_mode
            state: Follow Grid
        sequence:
          - action: huawei_solar.stop_forcible_charge
            metadata: {}
            data:
              device_id: f0c20b3b4e7a1af202ae2bca230becbe

So far this seems to work as intended and by using the huawei battery function to follow grid it reacts faster than the 15 sec limit from modbus tcp.

My SoC curve now does more or less what is predicted by EMHASS but doesn’t align as closely as yours does however. I now only use the day ahead (daily) emhass values (the 30 min value blocks for p_batt) ). You probably use the mpc forecaster with a higher frequency to calculate the power values to send to forcible charge and discharge to have it align as you show in your graph?

Yes, my mistake! Just figured it out. 1 deferrable load in the config and 2 in the MPC call. I deleted one deferrable load in the MPC call, so now all ok. Sorry again:

2025-01-04 12:02:32,133 - web_server - INFO -  >> Obtaining params: 
2025-01-04 12:02:32,139 - web_server - INFO - Passed runtime parameters: {'prediction_horizon': 24, 'pv_power_forecast': [1164, 1149, 1620, 1588, 1441, 1253, 1040, 810, 567, 352, 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, 151, 227, 299, 361, 406, 436, 455, 458, 442, 416, 381, 332, 269, 195, 123, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'num_def_loads': 1, 'P_deferrable_nom': [0], 'def_total_hours': [0], 'treat_def_as_semi_cont': [1], 'set_def_constant': [1], 'def_start_timestep': [0], 'def_end_timestep': [0], 'soc_init': 0.68, 'soc_final': 0.9, 'load_cost_forecast': [0.2748, 0.2748, 0.2746, 0.2746, 0.2815, 0.2815, 0.2841, 0.2841, 0.282, 0.282, 0.288, 0.288, 0.29, 0.29, 0.2841, 0.2841, 0.2747, 0.2747, 0.2677, 0.2677, 0.2628, 0.2628, 0.2532, 0.2532], 'prod_price_forecast': [0.121, 0.121, 0.1208, 0.1208, 0.1274, 0.1274, 0.1298, 0.1298, 0.1278, 0.1278, 0.1335, 0.1335, 0.1353, 0.1353, 0.1298, 0.1298, 0.1209, 0.1209, 0.1143, 0.1143, 0.1097, 0.1097, 0.1007, 0.1007], 'alpha': 1, 'beta': 0, 'load_power_forecast': [284, 200, 200, 200, 200, 300, 300, 200, 400, 200, 200, 400, 400, 400, 300, 300, 300, 600, 800, 500, 400, 400, 500, 500, 2400, 2300, 2400, 2400, 2300, 2400, 2400, 2400, 2300, 2400, 2400, 200, 200, 300, 300, 300, 300, 300, 300, 300, 400, 300, 300, 200]}
2025-01-04 12:02:32,140 - web_server - INFO -  >> Setting input data dict
2025-01-04 12:02:32,140 - web_server - INFO - Setting up needed data
2025-01-04 12:02:32,150 - web_server - INFO - Retrieve hass get data method initiated...
2025-01-04 12:02:32,322 - web_server - INFO - EMHASS server online, serving index.html...
2025-01-04 12:02:32,527 - web_server - INFO - Retrieving weather forecast data using method = list
2025-01-04 12:02:32,534 - web_server - INFO -  >> Performing naive MPC optimization...
2025-01-04 12:02:32,534 - web_server - INFO - Performing naive MPC optimization
2025-01-04 12:02:32,540 - web_server - INFO - Perform an iteration of a naive MPC controller
2025-01-04 12:02:32,593 - web_server - DEBUG - Deferrable load 0: Proposed optimization window: 0 --> 0
2025-01-04 12:02:32,593 - web_server - DEBUG - Deferrable load 0: Validated optimization window: 0 --> 0
2025-01-04 12:02:32,641 - web_server - INFO - Status: Optimal
2025-01-04 12:02:32,641 - web_server - INFO - Total value of the Cost function = -636.73
2025-01-04 12:02:32,768 - web_server - INFO -  >> Obtaining params: 
2025-01-04 12:02:32,769 - web_server - INFO - Passed runtime parameters: {'publish_prefix': ''}
2025-01-04 12:02:32,769 - web_server - INFO -  >> Setting input data dict
2025-01-04 12:02:32,769 - web_server - INFO - Setting up needed data
2025-01-04 12:02:32,773 - web_server - INFO -  >> Publishing data...
2025-01-04 12:02:32,774 - web_server - INFO - Publishing data to HASS instance
2025-01-04 12:02:32,782 - web_server - INFO - Successfully posted to sensor.p_pv_forecast = 1164
2025-01-04 12:02:32,794 - web_server - INFO - Successfully posted to sensor.p_load_forecast = 284
2025-01-04 12:02:32,797 - web_server - INFO - Successfully posted to sensor.p_hybrid_inverter = 284.0
2025-01-04 12:02:32,799 - web_server - INFO - Successfully posted to sensor.p_deferrable0 = 0.0
2025-01-04 12:02:32,803 - web_server - INFO - Successfully posted to sensor.p_batt_forecast = -880.0
2025-01-04 12:02:32,810 - web_server - INFO - Successfully posted to sensor.soc_batt_forecast = 70.7
2025-01-04 12:02:32,814 - web_server - INFO - Successfully posted to sensor.p_grid_forecast = 0.0
2025-01-04 12:02:32,817 - web_server - INFO - Successfully posted to sensor.total_cost_fun_value = -0.64
2025-01-04 12:02:32,819 - web_server - INFO - Successfully posted to sensor.optim_status = Optimal
2025-01-04 12:02:32,822 - web_server - INFO - Successfully posted to sensor.unit_load_cost = 0.2748
2025-01-04 12:02:32,825 - web_server - INFO - Successfully posted to sensor.unit_prod_price = 0.121
1 Like

Cost of battery charging.
I just want to check my logic here.
Taking into account what it costs to charge my battery I now did:
battery : 20kwh
cost : 10000€
max expected cycles during lifetime : 6000
This means that charging my battery costs me 10000/(6000x20)= 0.083€/kwh
Following this I set the weight_battery_discharge and weight_battery_charge to 0.083. Correct?

What I notice now is that even when dynamic pricing is rather flat EMHASS still charges the battery from the grid. Last night lowest prices were 0.203€/kwh and peak this evening will be 0.262€/kwh which means less that 0.083€ difference. Still battery was topped up last night. Does this make sense?

Still dont get how the battery weight discharge works even when i get it for a higher value the battery still wants to discharge

2025-01-04 22:22:00,256 - web_server - INFO - Passed runtime parameters: {'load_cost_forecast': [0.32, 0.33, 0.33, 0.33, 0.33, 0.31, 0.29, 0.29, 0.29, 0.29, 0.29, 0.29, 0.29, 0.3, 0.3, 0.31, 0.29, 0.24, 0.28, 0.25, 0.26, 0.3, 0.26, 0.17, 0.09, 0.09, 0.09, 0.1, 0.09, 0.09, 0.06, 0.06, 0.04, 0.06, 0.06, 0.16, 0.27, 0.3, 0.59, 0.58, 0.58, 0.58, 0.58, 0.62, 0.61, 0.58, 0.31, 0.31, 0.3], 'prod_price_forecast': [0.15, 0.15, 0.16, 0.16, 0.15, 0.14, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.13, 0.13, 0.14, 0.12, 0.08, 0.11, 0.08, 0.09, 0.13, 0.09, 0.01, 0.0, 0.0, -0.0, 0.0, 0.0, -0.0, -0.03, -0.03, -0.05, -0.03, -0.03, 0.06, 0.1, 0.13, 0.28, 0.28, 0.27, 0.28, 0.28, 0.31, 0.3, 0.28, 0.14, 0.14, 0.13], 'pv_power_forecast': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 136, 560, 1218, 1915, 2727, 3548, 4277, 4854, 5455, 5979, 6415, 6881, 7189, 7454, 7535, 7402, 7177, 6932, 6571, 5834, 4909, 3938, 2979, 2128, 1405, 657, 160, 34, 0, 0, 0], 'prediction_horizon': 24, 'num_def_loads': 1, 'p_deferrable_nom': [1800], 'soc_init': 0.53, 'soc_final': 0.13, 'def_total_hours': [0], 'def_load_start': [0], 'def_load_end': [0], 'weight_battery_discharge': 0.2, 'weight_battery_charge': 0.02}

Back now after a while but have had problems setting up emhass again
I run with the solcast integration and get uncertain here when I run dayahead

dayahead_optim: >
  curl -i -H 'Content-Type: application/json' -X POST -d '{
    "load_cost_forecast":{{((state_attr("sensor.nordpool_tibber", "raw_today") | map(attribute="value") | list  + state_attr("sensor.nordpool_tibber", "raw_tomorrow") | map(attribute="value") | list))[now().hour:][:24] }},
    "prod_price_forecast":{{((state_attr("sensor.nordpool_kwh_se3_sek_3_10_025", "raw_today") | map(attribute="value") | list  + state_attr("sensor.nordpool_kwh_se3_sek_3_10_025", "raw_tomorrow") | map(attribute="value") | list))[now().hour:][:24] }},
    "prediction_horizon":{{min(24, (((state_attr("sensor.nordpool_tibber", "raw_today")|map(attribute="value")|list + state_attr("sensor.nordpool_tibber", "raw_tomorrow") | map(attribute="value")| list)[now().hour:][:24]|list|length)))}},    
    "weather_forecast_cache_only": True,
    "delta_forecast_daily": 2
  }' http://localhost:5000/action/dayahead-optim
2025-01-04 14:20:15,368 - web_server - INFO -  >> Obtaining params: 
2025-01-04 14:20:15,368 - web_server - INFO - Passed runtime parameters: {}
2025-01-04 14:20:15,369 - web_server - INFO -  >> Setting input data dict
2025-01-04 14:20:15,369 - web_server - INFO - Setting up needed data
2025-01-04 14:20:15,377 - web_server - INFO -  >> Publishing data...
2025-01-04 14:20:15,378 - web_server - INFO - Publishing data to HASS instance
2025-01-04 14:20:15,386 - web_server - INFO - Successfully posted to sensor.p_pv_forecast = 0
2025-01-04 14:20:15,391 - web_server - INFO - Successfully posted to sensor.p_load_forecast = 991
2025-01-04 14:20:15,397 - web_server - INFO - Successfully posted to sensor.p_hybrid_inverter = 0.0
2025-01-04 14:20:15,403 - web_server - INFO - Successfully posted to sensor.p_deferrable0 = 0.0
2025-01-04 14:20:15,408 - web_server - INFO - Successfully posted to sensor.p_batt_forecast = 0.0
2025-01-04 14:20:15,414 - web_server - INFO - Successfully posted to sensor.soc_batt_forecast = 100.0
2025-01-04 14:20:15,421 - web_server - INFO - Successfully posted to sensor.p_grid_forecast = 991.0
2025-01-04 14:20:15,427 - web_server - INFO - Successfully posted to sensor.total_cost_fun_value = -12.69
2025-01-04 14:20:15,432 - web_server - INFO - Successfully posted to sensor.optim_status = Optimal
2025-01-04 14:20:15,438 - web_server - INFO - Successfully posted to sensor.unit_load_cost = 1.72
2025-01-04 14:20:15,444 - web_server - INFO - Successfully posted to sensor.unit_prod_price = 1.605
2025-01-04 14:24:06,065 - web_server - INFO -  >> Obtaining params: 
2025-01-04 14:24:06,066 - web_server - WARNING - Unable to parse runtime parameters
2025-01-04 14:24:06,066 - web_server - INFO -  >> Setting input data dict
2025-01-04 14:24:06,066 - web_server - INFO - Setting up needed data
2025-01-04 14:24:06,073 - web_server - INFO - Retrieving weather forecast data using method = solcast
2025-01-04 14:24:06,538 - web_server - ERROR - Solcast error: There was a issue with the solcast request, check solcast API key and rooftop ID.
2025-01-04 14:24:06,539 - web_server - ERROR - Solcast error: Check that your subscription is valid and your network can connect to Solcast.

Yes, I use MPC, but now switching to day-ahead and then MPC to cope with PV prediction changes.

My automations were built by trial and error, it works well, but I don’t know if it’s ideal. For daylight schedule I have this:

alias: >-
  Battery SOC control EMHASS Daytime Actual Inverter Power Charge 0 discharge
  auto mode and forced discharge NEW
description: Automation which controls battery SOClvl
triggers:
  - entity_id:
      - sensor.soc_batt_forecast
      - sensor.battery_batterijpercentage
    trigger: state
  - minutes: /1
    trigger: time_pattern
conditions:
  - condition: sun
    before: sunset
    after: sunrise
actions:
  - choose:
      - conditions:
          - condition: numeric_state
            entity_id: sensor.battery_batterijpercentage
            above: sensor.soc_batt_forecast
          - condition: numeric_state
            entity_id: sensor.p_grid_forecast
            above: -1
            below: 1
        sequence:
          - action: huawei_solar.stop_forcible_charge
            data:
              device_id: 07e2bedc6fd0bd3c2d22dbc36696daf7
      - conditions:
          - condition: numeric_state
            entity_id: sensor.battery_batterijpercentage
            above: sensor.soc_batt_forecast
          - condition: numeric_state
            entity_id: sensor.p_grid_forecast
            below: -1
        sequence:
          - data:
              target_soc: "{{states('sensor.soc_batt_forecast')|int(0)}}"
              power: >-
                {{ (states('sensor.p_batt_forecast') | int(0) | abs / 0.95) |
                int }}
              device_id: 07e2bedc6fd0bd3c2d22dbc36696daf7
            action: huawei_solar.forcible_discharge_soc
      - conditions:
          - condition: numeric_state
            entity_id: sensor.battery_batterijpercentage
            above: sensor.soc_batt_forecast
          - condition: numeric_state
            entity_id: sensor.p_grid_forecast
            above: 0
          - condition: numeric_state
            entity_id: sensor.p_batt_forecast
            above: 0
        sequence:
          - data:
              target_soc: "{{states('sensor.soc_batt_forecast')|int(0)}}"
              power: >-
                {{ (states('sensor.p_batt_forecast') | int(0) | abs / 0.95) |
                int }}
              device_id: 07e2bedc6fd0bd3c2d22dbc36696daf7
            action: huawei_solar.forcible_discharge_soc
      - conditions:
          - condition: numeric_state
            entity_id: sensor.battery_batterijpercentage
            below: sensor.soc_batt_forecast
          - condition: numeric_state
            entity_id: sensor.positive_battery_power_forecast
            below: sensor.inverter_ingangsvermogen
          - condition: state
            entity_id: sensor.inverter_toestel_status
            state: On-grid
        sequence:
          - data:
              target_soc: "{{states('sensor.soc_batt_forecast')|int(0)}}"
              power: >-
                {{(states('sensor.inverter_ingangsvermogen') | int(0) | abs) -
                (states('sensor.power_load_no_var_loads') | int(0) | abs)}}
              device_id: 07e2bedc6fd0bd3c2d22dbc36696daf7
            action: huawei_solar.forcible_charge_soc
      - conditions:
          - condition: numeric_state
            entity_id: sensor.battery_batterijpercentage
            below: sensor.soc_batt_forecast
          - condition: numeric_state
            entity_id: sensor.positive_battery_power_forecast
            below: sensor.inverter_ingangsvermogen
          - condition: state
            entity_id: sensor.inverter_toestel_status
            state: "Grid Connection: power limited"
        sequence:
          - data:
              target_soc: "{{states('sensor.soc_batt_forecast')|int(0)}}"
              power: "{{states('sensor.p_batt_forecast') | int(0) | abs}}"
              device_id: 07e2bedc6fd0bd3c2d22dbc36696daf7
            action: huawei_solar.forcible_charge_soc
      - conditions:
          - condition: numeric_state
            entity_id: sensor.battery_batterijpercentage
            below: sensor.soc_batt_forecast
          - condition: numeric_state
            entity_id: sensor.positive_battery_power_forecast
            above: sensor.inverter_ingangsvermogen
          - condition: numeric_state
            entity_id: sensor.p_grid_forecast
            below: 1
          - condition: numeric_state
            entity_id: sensor.inverter_ingangsvermogen
            below: sensor.power_load_no_var_loads
          - condition: state
            entity_id: sensor.inverter_toestel_status
            state: On-grid
        sequence:
          - data:
              target_soc: "{{states('sensor.soc_batt_forecast')|int(0)}}"
              power: "{{(states('sensor.inverter_ingangsvermogen') | int(0) | abs)}}"
              device_id: 07e2bedc6fd0bd3c2d22dbc36696daf7
            action: huawei_solar.forcible_charge_soc
      - conditions:
          - condition: numeric_state
            entity_id: sensor.battery_batterijpercentage
            below: sensor.soc_batt_forecast
          - condition: numeric_state
            entity_id: sensor.positive_battery_power_forecast
            above: sensor.inverter_ingangsvermogen
          - condition: numeric_state
            entity_id: sensor.p_grid_forecast
            below: 1
          - condition: numeric_state
            entity_id: sensor.inverter_ingangsvermogen
            above: sensor.power_load_no_var_loads
          - condition: state
            entity_id: sensor.inverter_toestel_status
            state: On-grid
        sequence:
          - data:
              target_soc: "{{states('sensor.soc_batt_forecast')|int(0)}}"
              power: >-
                {{(states('sensor.inverter_ingangsvermogen') | int(0) | abs) -
                (states('sensor.power_load_no_var_loads') | int(0) | abs)}}
              device_id: 07e2bedc6fd0bd3c2d22dbc36696daf7
            action: huawei_solar.forcible_charge_soc
      - conditions:
          - condition: numeric_state
            entity_id: sensor.battery_batterijpercentage
            below: sensor.soc_batt_forecast
          - condition: numeric_state
            entity_id: sensor.p_grid_forecast
            above: 1
          - condition: state
            entity_id: sensor.inverter_toestel_status
            state: On-grid
            enabled: false
        sequence:
          - data:
              target_soc: "{{states('sensor.soc_batt_forecast')|int(0)}}"
              power: "{{states('sensor.p_batt_forecast') | int(0)|abs}}"
              device_id: 07e2bedc6fd0bd3c2d22dbc36696daf7
            action: huawei_solar.forcible_charge_soc
    default:
      - action: huawei_solar.forcible_discharge
        data:
          duration: 1
          power: "0"
          device_id: 07e2bedc6fd0bd3c2d22dbc36696daf7
mode: single

Nice, do you have one for the nights too?
Nice that there are more people who have huawei and we can share experiences.
How do you handle power?

Then I wonder what sensor.positive_battery_power_forecast is?

I think it is to compare battery_power_forecast so I had to make it positive value in order for the automation to work.

And this is for evenings/nights:

alias: Battery SOC control EMHASS Evening auto mode forced discharge
description: Automation which controls battery SOClvl
triggers:
  - entity_id:
      - sensor.soc_batt_forecast
      - sensor.battery_batterijpercentage
    trigger: state
  - minutes: /1
    trigger: time_pattern
conditions:
  - condition: sun
    before: sunrise
    after: sunset
actions:
  - choose:
      - conditions:
          - condition: numeric_state
            entity_id: sensor.battery_batterijpercentage
            above: sensor.soc_batt_forecast
          - condition: numeric_state
            entity_id: sensor.p_grid_forecast
            above: -1
            below: 1
        sequence:
          - action: huawei_solar.stop_forcible_charge
            data:
              device_id: 07e2bedc6fd0bd3c2d22dbc36696daf7
      - conditions:
          - condition: numeric_state
            entity_id: sensor.battery_batterijpercentage
            above: sensor.soc_batt_forecast
          - condition: numeric_state
            entity_id: sensor.p_grid_forecast
            above: 0
          - condition: numeric_state
            entity_id: sensor.p_batt_forecast
            above: 0
        sequence:
          - data:
              target_soc: "{{states('sensor.soc_batt_forecast')|int(0)}}"
              power: >-
                {{ (states('sensor.p_batt_forecast') | int(0) | abs / 0.95) |
                int }}
              device_id: 07e2bedc6fd0bd3c2d22dbc36696daf7
            action: huawei_solar.forcible_discharge_soc
      - conditions:
          - condition: numeric_state
            entity_id: sensor.battery_batterijpercentage
            below: sensor.soc_batt_forecast
        sequence:
          - data:
              target_soc: "{{states('sensor.soc_batt_forecast')|int(0)}}"
              power: "{{ (states('sensor.p_batt_forecast') | int(0) | abs)}}"
              device_id: 07e2bedc6fd0bd3c2d22dbc36696daf7
            action: huawei_solar.forcible_charge_soc
    default:
      - action: huawei_solar.forcible_discharge
        data:
          duration: 1
          power: "0"
          device_id: 07e2bedc6fd0bd3c2d22dbc36696daf7
mode: single

Thanks. Interesting to see you use

huawei_solar.forcible_charge_soc

with p_batt_forecast as power instead of huawei_solar.forcible_charge with the same power and a number of minutes like I do and get better results that way.
Will try that.

1 Like

any of you Huawei users also have the capacity control options automated together with the emhass automations? I save a certain battery precentage as backup to filter out unexpected peak values (if grid power goes above a centrain set treshhold). There is this setting in the Huawei inverter itself but that does not work well together with forcible charging or discharging modes of course.
So this automation should always kick in, no mater what the battery is doing.

My experience is only use one of the two weight.

For me , I vary discharge weight, and leave charge weight at 0.

With discharge weight at 0.20 it will only discharge if there is a 20¢ variance between low/ high prices.

I noticed that when restarting HA (I use the add-on with a VM UTM on a mac mini) I lose the day-ahead predictions ‘dh_’, I can’t access them via Developer Tools → States, they are gione.

However they are available in the terminal, am I missing something here?

Ok so it’s a sensor.p_batt_forecast but with positive value when the battery discharges ?

That’s correct. I compare this with the actual inverter power, hence I made it positive. So when the the sensor.positive_battery_power_forecast is > sensor.inverter_ingangsvermogen (Actual inverter power), charge battery with the actual inverter power.