EMHASS: An Energy Management for Home Assistant

That was my understanding also

Do you run this as an separate rest command?

This how I did it, not sure if the second rest command is really necessary:

  emhass_mpc_optim_30min_fi_fo_buffer_mpc_prefix_dynamic_deferrable_loads_state_weight_battery_thermal_load:
    url: "http://localhost:5000/action/naive-mpc-optim"
    method: POST
    timeout: 15
    content_type: "application/json"
    payload: >-
      {
       "entity_save": "{{ entity_save }}",
       "publish_prefix": "{{ publish_prefix }}",
       "prediction_horizon": {{ prediction_horizon }},
       "pv_power_forecast": {{ pv_power_forecast | tojson }},
       "num_def_loads": {{ num_def_loads }},
       "nominal_power_of_deferrable_loads": {{ nominal_power_of_deferrable_loads | tojson }},
       "operating_hours_of_each_deferrable_load": {{ operating_hours_of_each_deferrable_load | tojson }},
       "treat_deferrable_load_as_semi_cont": {{ treat_deferrable_load_as_semi_cont | tojson }},
       "set_deferrable_load_single_constant": {{ set_deferrable_load_single_constant | tojson }},
       "start_timesteps_of_each_deferrable_load": {{ start_timesteps_of_each_deferrable_load | tojson }},
       "end_timesteps_of_each_deferrable_load": {{ end_timesteps_of_each_deferrable_load | tojson }},
       "def_current_state": {{ def_current_state | tojson }},
       "soc_init": {{ soc_init }},
       "soc_final": {{ soc_final }},
       "load_cost_forecast": {{ load_cost_forecast | tojson }},
       "prod_price_forecast": {{ prod_price_forecast | tojson }},
       "alpha": {{ alpha }},
       "beta": {{ beta }},
       "load_power_forecast": {{ load_power_forecast | tojson }},
       "weight_battery_charge": {{ weight_battery_charge | tojson }},
       "weight_battery_discharge": {{ weight_battery_discharge | tojson }},
       "def_load_config": {{ def_load_config | tojson }},
       "outdoor_temperature_forecast": {{ outdoor_temperature_forecast | tojson }}
      }
      
  emhass_publish_data_thermal_load:
    url: http://localhost:5000/action/publish-data
    method: POST
    content_type: 'application/json'
    payload: >-
      {"publish_prefix": {{ '"' ~ publish_prefix ~ '"' }},
       "def_load_config": {{ def_load_config | tojson }}      
      }

Here is my full rest command and payload script, there is a lot here to unpack:

My 7 loads are as follows:

load0 is pool filter pump (440 W)
load1 is pool heat pump (5 kW) - thermal load (heating)
load2 is EV1 charger (11 kW) variable
load3 is HVAC (11 kW) - thermal load (cooling)
load4 is Hot Water Heat Pump (600 W) - thermal load (heating)
load5 is EV2 charger (11 kW) variable
load6 is heater (660W) - fixed

sequence:
  - action: rest_command.mpc_servicecall_rest
    metadata: {}
    data:
      payload: |
        {{ payload}}
    enabled: true
  - action: rest_command.publish_data_rest
    enabled: true
    data: {}
alias: EMHASS Payload Script (Thermal)
variables:
  payload: |-
    {
      {% set count = state_attr('sensor.amber_30min_forecasts_feed_in_price','Forecasts')| selectattr('advanced_price_predicted','is_number') |list|count -%}
      {% set countML = state_attr('sensor.price_forecast_custom_model','scheduled_forecast')|list|count -%}
      {% set horizon = min(146,countML) -%}
      
      "prediction_horizon": {{horizon}},

      "prod_price_forecast": {{
        (
        [states('sensor.amber_5min_current_feed_in_price')|float(0)] 
        + (state_attr('sensor.amber_30min_forecasts_feed_in_price','Forecasts')
                    | selectattr('advanced_price_predicted','is_number')
                    | map(attribute='advanced_price_predicted')
                    | map('multiply', -1)
                    |list)
        + (state_attr('sensor.price_forecast_custom_model','scheduled_forecast')
           | map(attribute='price_forecast_custom_model')
           | map('float')|list)[count+1:]
        )        
      }}, 
      "load_cost_forecast": {{
        ([states('sensor.amber_5min_current_general_price')|float(0)]
        + (state_attr('sensor.amber_30min_forecasts_general_price','Forecasts')
                    | selectattr('advanced_price_predicted','is_number')
                    | map(attribute='advanced_price_predicted')
                    |list)
        + (state_attr('sensor.cost_forecast_custom_model','scheduled_forecast')
           | map(attribute='cost_forecast_custom_model')
           | map('float')|list)[count+1:]       
        )
      }},      
        "def_load_config": [{}, 
          {
          
          {%- if is_state('automation.p_deferable1_automation','on') -%}
          "thermal_config": 
            { "heating_rate": 2.0, 
              "sense": "heat",
              "cooling_constant": 0.007, 
              "overshoot_temperature": 33.0, 
              "start_temperature": {{states('sensor.ibs_th2_p01b_08ae_temperature')|float(0)}}, 

              {%- set set = states('sensor.emhass_sun_next_setting_timesteps')|int -%}
              {%- set total_blocks = horizon -%}
              {%- set max_heating_blocks = 6 -%}

              {# Calculate if heating is possible today #}
              {%- set heating_today = max(0, min(max_heating_blocks, set - 6)) -%}
              {%- set first_start = set - 9 -%}

              {# For second day, always schedule 6 blocks #}
              {%- set heating_tomorrow = max_heating_blocks -%}
              {%- set second_start = first_start + 48 -%}

              {# Calculate fill blocks #}
              {%- set before_first = max(0, first_start) -%}
              {%- set between = max(0, second_start - (first_start + heating_today)) -%}
              {%- set remaining = max(0, total_blocks - (second_start + heating_tomorrow)) -%}

              {%- set temps = 
                    [20]*before_first + 
                    [30]*heating_today + 
                    [24]*between + 
                    [30]*heating_tomorrow + 
                    [24]*remaining +
                    [30]*heating_tomorrow + 
                    [24]*remaining                    
              -%}

              "desired_temperatures": {{ (temps)[:horizon] }}

            }
            {%- endif -%}
          },
          {}, 
          {
          {%- if is_state('automation.p_deferrable3_hvac_v2','on') -%}
          "thermal_config": 
            { "heating_rate": -3.0, 
              "sense": "cool",
              "cooling_constant": 0.2, 
              "overshoot_temperature": 20.0, 
              "start_temperature": {{states('sensor.tewantin_temp')|float(0)}}, 
              "desired_temperatures": {{[states('input_number.emhass_deferrable3_set_point')|int(0)]*horizon}}
            }
            {%- endif -%}    
          }, 
          {
          "thermal_config": 
            { "heating_rate": 6.0, 
              "sense": "heat",
              "cooling_constant": 0.007, 
              "overshoot_temperature": 65.0, 
              "start_temperature": {{states('sensor.hws_power_based_sensor')|float(0)}}, 
              
              {%- set set = states('sensor.emhass_sun_next_setting_timesteps')|int -%}
              {%- set total_blocks = horizon -%}
              {%- set max_heating_blocks = 10 -%}

              {# Calculate if heating is possible today #}
              {%- set heating_today = max(0, min(max_heating_blocks, set - 10)) -%}
              {%- set first_start = set - 12 -%}

              {# For second day, always schedule 6 blocks #}
              {%- set heating_tomorrow = max_heating_blocks -%}
              {%- set second_start = first_start + 48 -%}

              {# Calculate fill blocks #}
              {%- set before_first = max(0, first_start) -%}
              {%- set between = max(0, second_start - (first_start + heating_today)) -%}
              {%- set remaining = max(0, total_blocks - (second_start + heating_tomorrow)) -%}

              {%- set temps = 
                    [50]*before_first + 
                    [60]*heating_today + 
                    [50]*between + 
                    [60]*heating_tomorrow + 
                    [50]*remaining +
                    [60]*heating_tomorrow + 
                    [50]*remaining                    
              -%}

              "desired_temperatures": {{ (temps)[:horizon] }}
            }
          }, 
          {}, 
          {}],
        "outdoor_temperature_forecast": {{state_attr('sensor.outdoor_temperature_forecast','forecasts')[:horizon]}}, 
        



      "alpha": 0,
      "beta": 1,
      "num_def_loads": 7,
      "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),
                              40]}},
      "def_current_state": {{[
                        iif(states('sensor.p_deferrable0')|int(0),1,0),
                        iif(states('sensor.p_deferrable1')|int(0),1,0),
                        iif(states('sensor.p_deferrable2')|int(0),1,0),
                        iif(states('sensor.p_deferrable3')|int(0),1,0),
                        iif(states('sensor.p_deferrable4')|int(0),1,0),
                        iif(states('sensor.p_deferrable5')|int(0),1,0),
                        iif(states('sensor.p_deferrable6')|int(0),1,0)
                      ]}},    
       "def_start_timestep": {{
          [0, 
          0, 
          max(0,states('sensor.emhass_deferrable2_start_timesteps')|int(0)), 
          0, 
          0, 
          max(0,states('sensor.emhass_deferrable5_start_timesteps')|int(0)),
          0]
          }},                      
       "def_end_timestep": {{
          [0, 
          0, 
          max(0,states('sensor.emhass_deferrable2_end_timeslots')|int(0)), 
          0, 
          0, 
          max(0,states('sensor.emhass_p_deferable_5_end_timeslots')|int(0)),
          0]
          }},
      "P_deferrable_nom":  [440,
                             5500, 
                            {{ states('sensor.p_nom_ev')}}, 
                           {{ states('input_number.p_nom_hvac')}}, 
                            600, 
                            {{ states('sensor.p_nom_ev2')}},
                            660],
      "treat_def_as_semi_cont": [1, 1, 0, 0, 1, 0, 1],
      "set_def_constant": [0, 0, 0, 0, 0, 0, 0],
      "def_start_penalty": [1, 0, 1, 1, 1, 1, 0],
      "weight_battery_charge": {{states('input_number.weight_battery_charge')}},
      "weight_battery_discharge": {{states('input_number.weight_battery_discharge')}},
      "battery_nominal_energy_capacity": {{ states('input_number.battery_nominal_energy_capacity')|int(0)*1000 }},
      "battery_discharge_power_max": {{ states('input_number.battery_discharge_power_max')|int(0)*1000}},
      "soc_final": {{states('input_number.soc_final')|int(0)/100}},
      "weather_forecast_cache_only": true,
      "optimization_time_step": 30,
      "set_nodischarge_to_grid": 0,

      "soc_init": 
          {% set primary = states('sensor.gateway_teslemetry_percentage_charged') %}
          {% set fallback = states('sensor.powerwall_charge') %}
          {% if primary not in ['unavailable', 'unknown'] %}
            {{ (primary | float/100) | round(2) }}
          {% elif fallback not in ['unavailable', 'unknown'] %}
            {{ (fallback | float /100) | round (2)}}
          {% else %}
            0
          {% endif %}
    }
mode: single
description: ""
2 Likes

Hi there, I am pretty new to Home Assistant and EMHASS as well. I have been using a commercial EMS for some years (energybase here in Germany) which is no longer supported.
I decided to give EMHASS a try and it looks very promising.
For now I am just trying to push the battery load to PV peak hours.
I’ve set up a defferabl load with 0 hours and configured battery as well as a inverter close to mine.
So inverter AC limit is 10KW, battery charge/discharg is around 10KW, battery capacity is 7.7KWh. Battery should be a 5% SOC at end of the forecast window (using day-ahead).
I configured the battery load as 7700 Wh in EMHASS.
Running the optimization gives me this:


Looks like the battery capacity is wrong.
Setting it to 77000Wh in EMHASS it looks more reasonable.

Am I doing something wrong?

I was thinking here, isn’t it possible to attach a temperature sensor to your DHW outlet from the waterpumpboiler? Or maybe your approach is good enough already.

I would check if all P parameters are in W and Wh and take it from there.

Thanks, this is my config:

"adjusted_pv_regression_model": "LassoRegression",
  "adjusted_pv_solar_elevation_threshold": 10,
  "battery_charge_efficiency": 0.98,
  "battery_charge_power_max": 10000,
  "battery_discharge_efficiency": 0.98,
  "battery_discharge_power_max": 10000,
  "battery_dynamic_max": 0.9,
  "battery_dynamic_min": -0.9,
  "battery_maximum_state_of_charge": 0.1,
  "battery_minimum_state_of_charge": 0,
  "battery_nominal_energy_capacity": 7700,
  "battery_target_state_of_charge": 0.05,
  "compute_curtailment": false,
  "continual_publish": false,
  "costfun": "self-consumption",
  "delta_forecast_daily": 1,
  "end_timesteps_of_each_deferrable_load": [
    0

Should be fine I guess.

Checking the optimization forecast re battery discharge, I am getting this:

|index|P_PV|P_Load|P_deferrable0|P_grid_pos|P_grid_neg|P_grid|P_batt|SOC_opt|

|2025-06-05 22:30:00+02:00|0|196|0|0|0|0|196|0.087|
|2025-06-06 02:00:00+02:00|0|281|0|0|0|0|281|0.068|
|2025-06-06 04:30:00+02:00|0|342|0|0|0|0|342|0.046|
|2025-06-06 05:30:00+02:00|0|366|0|0|0|0|366|0.021|
|2025-06-06 06:30:00+02:00|86|390|0|0|0|0|304|0.001|



So from 100 to 1% it is around 700Wh only.
And charging from 72% to 100%
index P_PV P_Load P_deferrable0 P_grid_pos P_grid_neg P_grid P_batt SOC_opt
2025-06-05 18:30:00+02:00 786 327 0 0 -113 -113 -346 0.072
2025-06-05 19:00:00+02:00 760 321 0 0 0 0 -439 0.100

That’s around 200Wh.


Edit, uhm. Problem between screen and chair.
Maximum should be 1 and not 0.1 :-(
Problem solved

Good to hear.

But what about the internal control of your DHW heat pump? You leave the setpoint always at 50 degrees celsius, so no time program.

I am currently working towards this, my shelly relay (which provides the SG ready signal) also has an input for a temperature sensor, so I will attach that to the hot water supply at the top which will enable the optimisation to be more accurate.

Unfortunately my DHW system doesn’t have a timer program.

The set point is 50 deg C normally and 65 deg C when the dry contact (SG ready) signal is set.

1 Like

Hi Mark,

I am working on the Hot water heat pump.

Looking at you setup, start and end timesteps for your def_4 are both 0. EMHASS looks what’s the best window for closing the PV contact on your hot water pump. I tried the same with these results (with 10 heating blocks)

Next I tried set start and end timestep to match the 60 degrees desired temp with these results:

Isn’t this what you are after? I am trying to understand what’s the best way to implement this. For the last optimization I had to lower the heating_rate from 6 to 5, but I don’t know the real value I need. I don’t have the hot waterpump yet. Just simulating and understanding the way the model works.

Can you explain a little more why you choose option 1?

Is you switch on debug you will see which loads are characterised as thermal or non-thermal loads.

I try not to constrain the solution with start/ end timesteps and just allow the optimization based on thermal performance.

In your example 1, the water heater switches on ‘early’ for two reasons:

  1. At the start it is below the desired 50 deg C, so it needs to start heating immediately. (13:00-)
  2. It is also attempting to get to the desired temp of 60 Dec C by 16:00, so it needs to run flat out and doesn’t quite get there.

You can also see it switches off early 18:30 as it has achieved the setpoint > 60 deg C.

In your example 2 your timestep constraints have it not achieving the 50 deg setpoint specified before 15:30 and it doesn’t achieve the required pre-heat to achieve 60 deg C specified for 15:30.

Got it! That makes sense.

A pratical question, for normal deferrable loads I use a countdown timer for the operating hours which decreases every hour by 1 until the def has finished. I feed the declining values to the runtime in my rolling window setup.

For the thermal load this doesn’t work, but I think it’s working automatically when temp increases. If at some timestep the desired temp is reached the def is reduced, but for the second start before the evening it is added as we defined 10 heating blocks. Hope I am correct. Or is there something else what I should do?

Hello,
I have EMHASS: v0.13.3 add-on
i’m trying to change Solar System (PV)
I have enphase solar system.1 micro inverter per panel
I found this:


and put it in te config.


But get this error

> Traceback (most recent call last):
>   File "/app/.venv/lib/python3.12/site-packages/pandas/core/indexes/base.py", line 3805, in get_loc
>     return self._engine.get_loc(casted_key)
>            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>   File "index.pyx", line 167, in pandas._libs.index.IndexEngine.get_loc
>   File "index.pyx", line 196, in pandas._libs.index.IndexEngine.get_loc
>   File "pandas/_libs/hashtable_class_helper.pxi", line 7081, in pandas._libs.hashtable.PyObjectHashTable.get_item
>   File "pandas/_libs/hashtable_class_helper.pxi", line 7089, in pandas._libs.hashtable.PyObjectHashTable.get_item
> KeyError: 'REC_Solar_REC365AA'
> The above exception was the direct cause of the following exception:
> Traceback (most recent call last):
>   File "/app/.venv/lib/python3.12/site-packages/flask/app.py", line 1511, in wsgi_app
>     response = self.full_dispatch_request()
>                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>   File "/app/.venv/lib/python3.12/site-packages/flask/app.py", line 919, in full_dispatch_request
>     rv = self.handle_user_exception(e)
>          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>   File "/app/.venv/lib/python3.12/site-packages/flask/app.py", line 917, in full_dispatch_request
>     rv = self.dispatch_request()
>          ^^^^^^^^^^^^^^^^^^^^^^^
>   File "/app/.venv/lib/python3.12/site-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 "/app/src/emhass/web_server.py", line 411, in action_call
>     input_data_dict = set_input_data_dict(
>                       ^^^^^^^^^^^^^^^^^^^^
>   File "/app/src/emhass/command_line.py", line 287, in set_input_data_dict
>     P_PV_forecast = fcst.get_power_from_weather(df_weather)
>                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>   File "/app/src/emhass/forecast.py", line 749, in get_power_from_weather
>     module = cec_modules[self.plant_conf["pv_module_model"][i]]
>              ~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>   File "/app/.venv/lib/python3.12/site-packages/pandas/core/frame.py", line 4102, in __getitem__
>     indexer = self.columns.get_loc(key)
>               ^^^^^^^^^^^^^^^^^^^^^^^^^
>   File "/app/.venv/lib/python3.12/site-packages/pandas/core/indexes/base.py", line 3812, in get_loc
>     raise KeyError(key) from err
> KeyError: 'REC_Solar_REC365AA

What went wrong?
REC_Solar_REC365AA is in the PVLib database for EMHASS
I have enphase solar system.1micro inverter per panel
Number of strings per inverter is set to 1
Adding in the yaml file is working
+/- (green arrow is not working)


My yaml file

{
  "optimization_time_step": 30,
  "historic_days_to_retrieve": 2,
  "sensor_power_photovoltaics": "sensor.envoy_122023077603_current_power_production",
  "sensor_power_photovoltaics_forecast": "sensor.p_pv_forecast",
  "sensor_power_load_no_var_loads": "sensor.power_load_no_var_loads",
  "load_negative": false,
  "set_zero_min": true,
  "sensor_replace_zero": [
    "sensor.power_photovoltaics",
    "sensor.p_pv_forecast"
  ],
  "sensor_linear_interp": [
    "sensor.power_photovoltaics",
    "sensor.power_load_no_var_loads"
  ],
  "method_ts_round": "nearest",
  "continual_publish": false,
  "costfun": "profit",
  "logging_level": "INFO",
  "set_use_pv": true,
  "set_use_adjusted_pv": false,
  "adjusted_pv_regression_model": "LassoRegression",
  "adjusted_pv_solar_elevation_threshold": 10,
  "set_use_battery": true,
  "number_of_deferrable_loads": 2,
  "nominal_power_of_deferrable_loads": [
    3000,
    750
  ],
  "minimum_power_of_deferrable_loads": [
    0,
    0
  ],
  "operating_hours_of_each_deferrable_load": [
    4,
    5
  ],
  "treat_deferrable_load_as_semi_cont": [
    true,
    true
  ],
  "set_deferrable_load_single_constant": [
    false,
    false
  ],
  "set_deferrable_startup_penalty": [
    0,
    0
  ],
  "delta_forecast_daily": 1,
  "load_forecast_method": "naive",
  "load_cost_forecast_method": "hp_hc_periods",
  "load_peak_hours_cost": 0.1907,
  "load_offpeak_hours_cost": 0.1419,
  "production_price_forecast_method": "constant",
  "photovoltaic_production_sell_price": 0.1419,
  "set_total_pv_sell": false,
  "lp_solver": "default",
  "lp_solver_path": "empty",
  "lp_solver_timeout": 45,
  "num_threads": 0,
  "set_nocharge_from_grid": false,
  "set_nodischarge_to_grid": true,
  "set_battery_dynamic": false,
  "battery_dynamic_max": 0.9,
  "battery_dynamic_min": -0.9,
  "weight_battery_discharge": 0,
  "weight_battery_charge": 0,
  "weather_forecast_method": "open-meteo",
  "open_meteo_cache_max_age": 30,
  "start_timesteps_of_each_deferrable_load": [
    0,
    0
  ],
  "end_timesteps_of_each_deferrable_load": [
    0,
    0
  ],
  "load_peak_hour_periods": {
    "period_hp_1": [
      {
        "start": "02:54"
      },
      {
        "end": "15:24"
      }
    ],
    "period_hp_2": [
      {
        "start": "17:24"
      },
      {
        "end": "20:24"
      }
    ]
  },
  "maximum_power_from_grid": 9000,
  "maximum_power_to_grid": 9000,
  "pv_module_model": [
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M",
    "CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M"
  ],
  "pv_inverter_model": [
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_",
    "Enphase_Energy_Inc___IQ7PLUS_72_2_US__240V_"
  ],
  "surface_tilt": [
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15,
    15
  ],
  "surface_azimuth": [
    220,
    220,
    220,
    220,
    220,
    220,
    220,
    220,
    220,
    220,
    220,
    220,
    220,
    220,
    220,
    220,
    220,
    220,
    220,
    220,
    140,
    140,
    140,
    140,
    140,
    140,
    140,
    140,
    140,
    140,
    140,
    140
  ],
  "modules_per_string": [
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1
  ],
  "strings_per_inverter": [
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1
  ],
  "inverter_is_hybrid": false,
  "compute_curtailment": false,
  "battery_discharge_power_max": 1000,
  "battery_charge_power_max": 1000,
  "battery_discharge_efficiency": 0.95,
  "battery_charge_efficiency": 0.95,
  "battery_nominal_energy_capacity": 5000,
  "battery_minimum_state_of_charge": 0.3,
  "battery_maximum_state_of_charge": 0.9,
  "battery_target_state_of_charge": 0.6
}