Skip to content

Commit

Permalink
Merge pull request #307 from davidusb-geek/davidusb-geek/dev/new_para…
Browse files Browse the repository at this point in the history
…ms_improv

Davidusb geek/dev/new params improv
  • Loading branch information
davidusb-geek authored Jul 5, 2024
2 parents b864ee1 + bbb8d57 commit 9e1636d
Show file tree
Hide file tree
Showing 14 changed files with 163 additions and 114 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Changelog

## 0.10.2 - 2024-07-06
### Improvement
- Weather forecast caching and Solcast method fix by @GeoDerp
- Added a new configuration parameter to control wether we compute PV curtailment or not
- Added hybrid inverter to data publish
- It is now possible to pass these battery parameters at runtime: `SOCmin`, `SOCmax`, `Pd_max` and `Pc_max`
### Fix
- Fixed problem with negative PV forecast values in optimization.py, by @GeoDerp

## 0.10.1 - 2024-06-03
### Fix
- Fixed PV curtailment maximum possible value constraint
Expand Down
22 changes: 14 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,9 @@ docker run -it --restart always -p 5000:5000 -e TZ="Europe/Paris" -e LOCAL_COS
### Method 3) Legacy method using a Python virtual environment
With this method it is recommended to install on a virtual environment.
For this you will need `virtualenv`, install it using:
Create and activate a virtual environment:
```bash
sudo apt install python3-virtualenv
```
Then create and activate the virtual environment:
```bash
virtualenv -p /usr/bin/python3 emhassenv
python3 -m venv emhassenv
cd emhassenv
source bin/activate
```
Expand Down Expand Up @@ -461,7 +457,7 @@ curl -i -H 'Content-Type:application/json' -X POST -d '{"publish_prefix":"all"}'
```
This action will publish the dayahead (_dh) and MPC (_mpc) optimization results from the optimizations above.

### Forecast data
### Forecast data at runtime

It is possible to provide EMHASS with your own forecast data. For this just add the data as list of values to a data dictionary during the call to `emhass` using the `runtimeparams` option.

Expand All @@ -484,7 +480,7 @@ The possible dictionary keys to pass data are:

- `prod_price_forecast` for the PV production selling price forecast.

### Passing other data
### Passing other data at runtime

It is possible to also pass other data during runtime in order to automate the energy management. For example, it could be useful to dynamically update the total number of hours for each deferrable load (`def_total_hours`) using for instance a correlation with the outdoor temperature (useful for water heater for example).

Expand All @@ -500,6 +496,8 @@ Here is the list of the other additional dictionary keys that can be passed at r
- `def_end_timestep` for the timestep before which each deferrable load should operate (if you don't want the deferrable load to use the whole optimization timewindow).

- `def_current_state` Pass this as a list of booleans (True/False) to indicate the current deferrable load state. This is used internally to avoid incorrectly penalizing a deferrable load start if a forecast is run when that load is already running.

- `treat_def_as_semi_cont` to define if we should treat each deferrable load as a semi-continuous variable.

- `set_def_constant` to define if we should set each deferrable load as a constant fixed value variable with just one startup for each optimization task.
Expand All @@ -510,8 +508,16 @@ Here is the list of the other additional dictionary keys that can be passed at r

- `solar_forecast_kwp` for the PV peak installed power in kW used for the solar.forecast API call.

- `SOCmin` the minimum possible SOC.

- `SOCmax` the maximum possible SOC.

- `SOCtarget` for the desired target value of initial and final SOC.

- `Pd_max` for the maximum battery discharge power.

- `Pc_max` for the maximum battery charge power.

- `publish_prefix` use this key to pass a common prefix to all published data. This will add a prefix to the sensor name but also to the forecasts attributes keys within the sensor.

## A naive Model Predictive Controller
Expand Down
4 changes: 4 additions & 0 deletions config_emhass.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ optim_conf:
set_def_constant: # set as a constant fixed value variable with just one startup for each 24h
- False
- False
def_start_penalty: # Set a penalty for each start up of a deferrable load
- 0.0
- 0.0
weather_forecast_method: 'scrapper' # options are 'scrapper', 'csv', 'list', 'solcast' and 'solar.forecast'
load_forecast_method: 'naive' # options are 'csv' to load a custom load forecast from a CSV file or 'naive' for a persistance model
load_cost_forecast_method: 'hp_hc_periods' # options are 'hp_hc_periods' for peak and non-peak hours contracts and 'csv' to load custom cost from CSV file
Expand Down Expand Up @@ -78,6 +81,7 @@ plant_conf:
strings_per_inverter: # The number of used strings per inverter
- 1
inverter_is_hybrid: False # Set if it is a hybrid inverter (PV+batteries) or not
compute_curtailment: False # Compute a PV curtailment variable or not
Pd_max: 1000 # If your system has a battery (set_use_battery=True), the maximum discharge power in Watts
Pc_max: 1000 # If your system has a battery (set_use_battery=True), the maximum charge power in Watts
eta_disch: 0.95 # If your system has a battery (set_use_battery=True), the discharge efficiency
Expand Down
Binary file modified data/test_df_final.pkl
Binary file not shown.
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
author = 'David HERNANDEZ'

# The full version, including alpha/beta/rc tags
release = '0.10.1'
release = '0.10.2'

# -- General configuration ---------------------------------------------------

Expand Down
5 changes: 4 additions & 1 deletion docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ These are the parameters needed to properly define the optimization problem.
- `set_def_constant`: Define if we should set each deferrable load as a constant fixed value variable with just one startup for each optimization task. For example:
- False
- False
- `def_start_penalty`: Set to a list of floats. For each deferrable load with a penalty `P`, each time the deferrable load turns on will incur an additional cost of `P * P_deferrable_nom * cost_of_electricity` at that time.
- `weather_forecast_method`: This will define the weather forecast method that will be used. The options are 'scrapper' for a scrapping method for weather forecast from clearoutside.com and 'csv' to load a CSV file. When loading a CSV file this will be directly considered as the PV power forecast in Watts. The default CSV file path that will be used is '/data/data_weather_forecast.csv'. Defaults to 'scrapper' method.
- `load_forecast_method`: The load forecast method that will be used. The options are 'csv' to load a CSV file or 'naive' for a simple 1-day persistance model. The default CSV file path that will be used is '/data/data_load_forecast.csv'. Defaults to 'naive'.
- `load_cost_forecast_method`: Define the method that will be used for load cost forecast. The options are 'hp_hc_periods' for peak and non-peak hours contracts and 'csv' to load custom cost from CSV file. The default CSV file path that will be used is '/data/data_load_cost_forecast.csv'.
Expand Down Expand Up @@ -106,7 +107,9 @@ Solution (2) would be to use SolCast and pass that data directly to emhass as a
- `surface_tilt`: The tilt angle of your solar panels. Defaults to 30. This parameter can be a list of items to enable the simulation of mixed orientation systems, for example one east-facing array (azimuth=90) and one west-facing array (azimuth=270).
- `surface_azimuth`: The azimuth of your PV installation. Defaults to 205. This parameter can be a list of items to enable the simulation of mixed orientation systems, for example one east-facing array (azimuth=90) and one west-facing array (azimuth=270).
- `modules_per_string`: The number of modules per string. Defaults to 16. This parameter can be a list of items to enable the simulation of mixed orientation systems, for example one east-facing array (azimuth=90) and one west-facing array (azimuth=270).
- `strings_per_inverter`: The number of used strings per inverter. Defaults to 1. This parameter can be a list of items to enable the simulation of mixed orientation systems, for example one east-facing array (azimuth=90) and one west-facing array (azimuth=270).
- `strings_per_inverter`: The number of used strings per inverter. Defaults to 1. This parameter can be a list of items to enable the simulation of mixed orientation systems, for example one east-facing array (azimuth=90) and one west-facing array (azimuth=270).
- `inverter_is_hybrid`: Set to True to consider that the installation inverter is hybrid for PV and batteries (Default False).
- `compute_curtailment`: Set to True to compute a special PV curtailment variable (Default False).

If your system has a battery (set_use_battery=True), then you should define the following parameters:

Expand Down
9 changes: 9 additions & 0 deletions options.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,14 @@
"set_deferrable_load_single_constant": false
}
],
"list_set_deferrable_startup_penalty": [
{
"set_deferrable_startup_penalty": 0.0
},
{
"set_deferrable_startup_penalty": 0.0
}
],
"load_peak_hours_cost": 0.1907,
"load_offpeak_hours_cost": 0.1419,
"production_price_forecast_method": "constant",
Expand Down Expand Up @@ -135,6 +143,7 @@
}
],
"inverter_is_hybrid": false,
"compute_curtailment": false,
"set_use_battery": false,
"battery_discharge_power_max": 1000,
"battery_charge_power_max": 1000,
Expand Down
8 changes: 5 additions & 3 deletions scripts/script_debug_optim.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@
# Set special debug cases
optim_conf.update({'lp_solver': 'PULP_CBC_CMD'}) # set the name of the linear programming solver that will be used. Options are 'PULP_CBC_CMD', 'GLPK_CMD' and 'COIN_CMD'.
optim_conf.update({'lp_solver_path': 'empty'}) # set the path to the LP solver, COIN_CMD default is /usr/bin/cbc
optim_conf.update({'treat_def_as_semi_cont': [True, True]})
optim_conf.update({'set_def_constant': [False, False]})
optim_conf.update({'treat_def_as_semi_cont': [True, False]})
optim_conf.update({'set_def_constant': [True, False]})
# optim_conf.update({'P_deferrable_nom': [[500.0, 100.0, 100.0, 500.0], 750.0]})

optim_conf.update({'set_use_battery': False})
Expand Down Expand Up @@ -101,9 +101,11 @@
if show_figures:
fig_inputs_dah.show()

vars_to_plot = ['P_deferrable0', 'P_deferrable1','P_grid', 'P_PV', 'P_PV_curtailment']
vars_to_plot = ['P_deferrable0', 'P_deferrable1','P_grid', 'P_PV']
if plant_conf['inverter_is_hybrid']:
vars_to_plot = vars_to_plot + ['P_hybrid_inverter']
if plant_conf['compute_curtailment']:
vars_to_plot = vars_to_plot + ['P_PV_curtailment']
if optim_conf['set_use_battery']:
vars_to_plot = vars_to_plot + ['P_batt'] + ['SOC_opt']
fig_res_dah = opt_res_dayahead[vars_to_plot].plot() # 'P_def_start_0', 'P_def_start_1', 'P_def_bin2_0', 'P_def_bin2_1'
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

setup(
name='emhass', # Required
version='0.10.1', # Required
version='0.10.2', # Required
description='An Energy Management System for Home Assistant', # Optional
long_description=long_description, # Optional
long_description_content_type='text/markdown', # Optional (see note above)
Expand Down
42 changes: 29 additions & 13 deletions src/emhass/command_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -849,19 +849,35 @@ def publish_data(input_data_dict: dict, logger: logging.Logger,
)
cols_published = ["P_PV", "P_Load"]
# Publish PV curtailment
custom_pv_curtailment_id = params["passed_data"]["custom_pv_curtailment_id"]
input_data_dict["rh"].post_data(
opt_res_latest["P_PV_curtailment"],
idx_closest,
custom_pv_curtailment_id["entity_id"],
custom_pv_curtailment_id["unit_of_measurement"],
custom_pv_curtailment_id["friendly_name"],
type_var="power",
publish_prefix=publish_prefix,
save_entities=entity_save,
dont_post=dont_post
)
cols_published = cols_published + ["P_PV_curtailment"]
if input_data_dict["fcst"].plant_conf['compute_curtailment']:
custom_pv_curtailment_id = params["passed_data"]["custom_pv_curtailment_id"]
input_data_dict["rh"].post_data(
opt_res_latest["P_PV_curtailment"],
idx_closest,
custom_pv_curtailment_id["entity_id"],
custom_pv_curtailment_id["unit_of_measurement"],
custom_pv_curtailment_id["friendly_name"],
type_var="power",
publish_prefix=publish_prefix,
save_entities=entity_save,
dont_post=dont_post
)
cols_published = cols_published + ["P_PV_curtailment"]
# Publish P_hybrid_inverter
if input_data_dict["fcst"].plant_conf['inverter_is_hybrid']:
custom_hybrid_inverter_id = params["passed_data"]["custom_hybrid_inverter_id"]
input_data_dict["rh"].post_data(
opt_res_latest["P_hybrid_inverter"],
idx_closest,
custom_hybrid_inverter_id["entity_id"],
custom_hybrid_inverter_id["unit_of_measurement"],
custom_hybrid_inverter_id["friendly_name"],
type_var="power",
publish_prefix=publish_prefix,
save_entities=entity_save,
dont_post=dont_post
)
cols_published = cols_published + ["P_hybrid_inverter"]
# Publish deferrable loads
custom_deferrable_forecast_id = params["passed_data"][
"custom_deferrable_forecast_id"
Expand Down
4 changes: 2 additions & 2 deletions src/emhass/forecast.py
Original file line number Diff line number Diff line change
Expand Up @@ -481,9 +481,9 @@ def get_power_from_weather(self, df_weather: pd.DataFrame,
# Setting the main parameters of the PV plant
location = Location(latitude=self.lat, longitude=self.lon)
temp_params = TEMPERATURE_MODEL_PARAMETERS['sapm']['close_mount_glass_glass']
cec_modules = bz2.BZ2File(self.emhass_conf['root_path'] / 'data/cec_modules.pbz2', "rb")
cec_modules = bz2.BZ2File(self.emhass_conf['root_path'] / 'data' / 'cec_modules.pbz2', "rb")
cec_modules = cPickle.load(cec_modules)
cec_inverters = bz2.BZ2File(self.emhass_conf['root_path'] / 'data/cec_inverters.pbz2', "rb")
cec_inverters = bz2.BZ2File(self.emhass_conf['root_path'] / 'data' / 'cec_inverters.pbz2', "rb")
cec_inverters = cPickle.load(cec_inverters)
if type(self.plant_conf['module_model']) == list:
P_PV_forecast = pd.Series(0, index=df_weather.index)
Expand Down
Loading

0 comments on commit 9e1636d

Please sign in to comment.