Skip to content

Commit

Permalink
Merge pull request #298 from davidusb-geek/davidusb-geek/patch/fix_v0…
Browse files Browse the repository at this point in the history
…p10p1

Fixed PV curtailment limitation and publish
  • Loading branch information
davidusb-geek authored Jun 3, 2024
2 parents 13eba04 + bd410aa commit dd00d43
Show file tree
Hide file tree
Showing 9 changed files with 115 additions and 57 deletions.
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
# Changelog

## 0.10.1 - 2024-06-03
### Fix
- Fixed PV curtailment maximum possible value constraint
- Added PV curtailement to variable to publish to HA

## 0.10.0 - 2024-06-02
### BREAKING CHANGE
- In this new version we have added support for PV curtailment computation. While doing this the nominal PV peak power is needed. The easiest way find this information is by directly using the `inverter_model` defined in the configuration. As this is needed in the optimization to correctly compute PV curtailment, this parameter need to be properly defined for your installation. Before this chage this parameter was only needed if using the PV forecast method `scrapper`, but now it is not optional as it is directly used in the optimization.
Use the dedicated webapp to find the correct model for your inverter, if you cannot find your exact brand/model then just pick an inverter with the same nominal power as yours: [https://emhass-pvlib-database.streamlit.app/](https://emhass-pvlib-database.streamlit.app/)
### Improvement
- Added support for hybrid inverters
- Added support for hybrid inverters and PV curtailment computation
- Implemented a new `continual_publish` service that avoid the need of setting a special automation for data publish. Thanks to @GeoDerp
- Implement a deferrable load start penalty functionality. Thanks to @werdnum
- This feature also implement a `def_current_state` that can be passed at runtime to let the optimization consider that a deferrable load is currently scheduled or under operation when launching the optimization task
Expand Down
60 changes: 49 additions & 11 deletions data/opt_res_latest.csv
Original file line number Diff line number Diff line change
@@ -1,11 +1,49 @@
timestamp,P_PV,P_Load,P_deferrable0,P_deferrable1,P_grid_pos,P_grid_neg,P_grid,unit_load_cost,unit_prod_price,cost_profit,cost_fun_profit
2023-01-27 10:30:00+01:00,0.5,1127.6172187500001,3000.0,750.0,4877.1172,0.0,4877.1172,1,1,-2.4385586,-2.4385586
2023-01-27 11:00:00+01:00,2.0,2.0,3000.0,750.0,3750.0,0.0,3750.0,2,2,-3.75,-3.75
2023-01-27 11:30:00+01:00,3.0,3.0,3000.0,750.0,3750.0,0.0,3750.0,3,3,-5.625,-5.625
2023-01-27 12:00:00+01:00,4.0,4.0,3000.0,750.0,3750.0,0.0,3750.0,4,4,-7.5,-7.5
2023-01-27 12:30:00+01:00,5.0,5.0,3000.0,750.0,3750.0,0.0,3750.0,5,5,-9.375,-9.375
2023-01-27 13:00:00+01:00,6.0,6.0,3000.0,750.0,3750.0,0.0,3750.0,6,6,-11.25,-11.25
2023-01-27 13:30:00+01:00,7.0,7.0,3000.0,750.0,3750.0,0.0,3750.0,7,7,-13.125,-13.125
2023-01-27 14:00:00+01:00,8.0,8.0,3000.0,750.0,3750.0,0.0,3750.0,8,8,-15.0,-15.0
2023-01-27 14:30:00+01:00,9.0,9.0,6000.0,750.0,6750.0,0.0,6750.0,9,9,-30.375,-30.375
2023-01-27 15:00:00+01:00,10.0,10.0,0.0,5250.0,5250.0,0.0,5250.0,10,10,-26.25,-26.25
timestamp,P_PV,P_Load,P_deferrable0,P_deferrable1,P_grid_pos,P_grid_neg,P_grid,P_PV_curtailment,unit_load_cost,unit_prod_price,cost_profit,cost_fun_profit,optim_status
2024-06-03 23:00:00+02:00,0.0,2124.8911797752808,0.0,750.0,2874.8912,0.0,2874.8912,0.0,0.1419,0.065,-0.20397353064,-0.20397353064,Optimal
2024-06-03 23:30:00+02:00,0.0,393.7693220338983,3000.0,750.0,4143.7693,0.0,4143.7693,0.0,0.1419,0.065,-0.29400043183499996,-0.29400043183499996,Optimal
2024-06-04 00:00:00+02:00,0.0,329.5656571428571,0.0,750.0,1079.5657,0.0,1079.5657,0.0,0.1419,0.065,-0.076595186415,-0.076595186415,Optimal
2024-06-04 00:30:00+02:00,0.0,214.95473988439306,0.0,750.0,964.95474,0.0,964.95474,0.0,0.1419,0.065,-0.068463538803,-0.068463538803,Optimal
2024-06-04 01:00:00+02:00,0.0,254.92180790960455,3000.0,0.0,3254.9218,0.0,3254.9218,0.0,0.1419,0.065,-0.23093670171,-0.23093670171,Optimal
2024-06-04 01:30:00+02:00,0.0,653.0385393258427,0.0,0.0,653.03854,0.0,653.03854,0.0,0.1419,0.065,-0.046333084413000006,-0.046333084413000006,Optimal
2024-06-04 02:00:00+02:00,0.0,694.8668181818182,0.0,0.0,694.86682,0.0,694.86682,0.0,0.1419,0.065,-0.049300800879,-0.049300800879,Optimal
2024-06-04 02:30:00+02:00,0.0,856.8446739130435,0.0,0.0,856.84467,0.0,856.84467,0.0,0.1419,0.065,-0.060793129336499996,-0.060793129336499996,Optimal
2024-06-04 03:00:00+02:00,0.0,914.380597826087,0.0,0.0,914.3806,0.0,914.3806,0.0,0.1907,0.065,-0.08718619021000001,-0.08718619021000001,Optimal
2024-06-04 03:30:00+02:00,0.0,599.8399421965318,0.0,0.0,599.83994,0.0,599.83994,0.0,0.1907,0.065,-0.057194738279,-0.057194738279,Optimal
2024-06-04 04:00:00+02:00,0.0,703.5027607361963,0.0,0.0,703.50276,0.0,703.50276,0.0,0.1907,0.065,-0.067078988166,-0.067078988166,Optimal
2024-06-04 04:30:00+02:00,0.0,646.7419879518072,0.0,0.0,646.74199,0.0,646.74199,0.0,0.1907,0.065,-0.061666848746500004,-0.061666848746500004,Optimal
2024-06-04 05:00:00+02:00,0.0,1009.152816091954,0.0,0.0,1009.1528,0.0,1009.1528,0.0,0.1907,0.065,-0.09622271948,-0.09622271948,Optimal
2024-06-04 05:30:00+02:00,0.0,967.1363841807911,0.0,0.0,967.13638,0.0,967.13638,0.0,0.1907,0.065,-0.092216453833,-0.092216453833,Optimal
2024-06-04 06:00:00+02:00,0.0,935.1571508379889,0.0,0.0,935.15715,0.0,935.15715,0.0,0.1907,0.065,-0.0891672342525,-0.0891672342525,Optimal
2024-06-04 06:30:00+02:00,60.0,3267.5106703910615,0.0,0.0,3207.5107,0.0,3207.5107,0.0,0.1907,0.065,-0.305836145245,-0.305836145245,Optimal
2024-06-04 07:00:00+02:00,840.0,3286.2027777777776,0.0,0.0,2446.2028,0.0,2446.2028,0.0,0.1907,0.065,-0.23324543698000003,-0.23324543698000003,Optimal
2024-06-04 07:30:00+02:00,660.0,1496.1914772727273,0.0,0.0,836.19148,0.0,836.19148,0.0,0.1907,0.065,-0.079730857618,-0.079730857618,Optimal
2024-06-04 08:00:00+02:00,620.0,794.2991620111732,0.0,0.0,174.29916,0.0,174.29916,0.0,0.1907,0.065,-0.016619424906,-0.016619424906,Optimal
2024-06-04 08:30:00+02:00,620.0,832.2424719101124,0.0,0.0,212.24247,0.0,212.24247,0.0,0.1907,0.065,-0.020237319514500002,-0.020237319514500002,Optimal
2024-06-04 09:00:00+02:00,6380.0,788.9761235955057,3000.0,750.0,0.0,-1841.0239,-1841.0239,0.0,0.1907,0.065,0.05983327675,0.05983327675,Optimal
2024-06-04 09:30:00+02:00,1095.5620000000001,781.2152298850575,0.0,750.0,435.65323,0.0,435.65323,0.0,0.1907,0.065,-0.0415395354805,-0.0415395354805,Optimal
2024-06-04 10:00:00+02:00,811.4380000000002,664.0545197740113,0.0,0.0,0.0,-147.38348,-147.38348,0.0,0.1907,0.065,0.0047899631,0.0047899631,Optimal
2024-06-04 10:30:00+02:00,681.0759999999999,666.1989265536723,0.0,0.0,0.0,-14.877073,-14.877073,0.0,0.1907,0.065,0.00048350487250000003,0.00048350487250000003,Optimal
2024-06-04 11:00:00+02:00,671.9846666666667,669.4183146067417,0.0,0.0,0.0,-2.5663521,-2.5663521,0.0,0.1907,0.065,8.340644325000001e-05,8.340644325000001e-05,Optimal
2024-06-04 11:30:00+02:00,6469.634666666666,579.2235294117647,3000.0,750.0,0.0,0.0,0.0,2140.4111,0.1907,-0.07,-0.0,-0.0,Optimal
2024-06-04 12:00:00+02:00,2992.012,642.7344318181817,3000.0,0.0,650.72243,0.0,650.72243,0.0,0.1907,-0.07,-0.06204638370050001,-0.06204638370050001,Optimal
2024-06-04 12:30:00+02:00,1867.9053333333331,637.1688636363637,0.0,750.0,0.0,0.0,0.0,480.73647,0.1907,-0.07,-0.0,-0.0,Optimal
2024-06-04 13:00:00+02:00,2067.554666666667,649.3890173410405,3000.0,0.0,1581.8344,0.0,1581.8344,0.0,0.1907,-0.07,-0.15082791004,-0.15082791004,Optimal
2024-06-04 13:30:00+02:00,622.756,509.79664739884396,0.0,0.0,0.0,0.0,0.0,112.95935,0.1907,-0.07,-0.0,-0.0,Optimal
2024-06-04 14:00:00+02:00,1518.7553333333335,500.53686046511626,0.0,750.0,0.0,-268.21847,-268.21847,0.0,0.1907,0.065,0.008717100275000002,0.008717100275000002,Optimal
2024-06-04 14:30:00+02:00,2551.502,520.944,3000.0,0.0,969.442,0.0,969.442,0.0,0.1907,0.065,-0.0924362947,-0.0924362947,Optimal
2024-06-04 15:00:00+02:00,4160.0,415.32341040462427,3000.0,750.0,5.3234104,0.0,5.3234104,0.0,0.1907,0.065,-0.00050758718164,-0.00050758718164,Optimal
2024-06-04 15:30:00+02:00,4240.0,321.6410285714286,3000.0,750.0,0.0,-168.35897,-168.35897,0.0,0.1419,0.065,0.005471666525,0.005471666525,Optimal
2024-06-04 16:00:00+02:00,560.0,3778.0933888888894,3000.0,750.0,6968.0934,0.0,6968.0934,0.0,0.1419,0.065,-0.49438622673,-0.49438622673,Optimal
2024-06-04 16:30:00+02:00,380.0,3990.816179775281,0.0,750.0,4360.8162,0.0,4360.8162,0.0,0.1419,0.065,-0.30939990939,-0.30939990939,Optimal
2024-06-04 17:00:00+02:00,0.0,3909.8039890710384,0.0,750.0,4659.804,0.0,4659.804,0.0,0.1419,0.065,-0.33061309380000004,-0.33061309380000004,Optimal
2024-06-04 17:30:00+02:00,0.0,4206.869447513812,0.0,0.0,4206.8694,0.0,4206.8694,0.0,0.1907,0.065,-0.40112499728999995,-0.40112499728999995,Optimal
2024-06-04 18:00:00+02:00,0.0,486.26584269662925,0.0,0.0,486.26584,0.0,486.26584,0.0,0.1907,0.065,-0.046365447844000006,-0.046365447844000006,Optimal
2024-06-04 18:30:00+02:00,0.0,402.43446927374305,0.0,0.0,402.43447,0.0,402.43447,0.0,0.1907,0.065,-0.0383721267145,-0.0383721267145,Optimal
2024-06-04 19:00:00+02:00,0.0,316.17875,0.0,0.0,316.17875,0.0,316.17875,0.0,0.1907,0.065,-0.0301476438125,-0.0301476438125,Optimal
2024-06-04 19:30:00+02:00,0.0,867.4,0.0,0.0,867.4,0.0,867.4,0.0,0.1907,0.065,-0.08270659000000001,-0.08270659000000001,Optimal
2024-06-04 20:00:00+02:00,0.0,340.8070760233918,0.0,0.0,340.80708,0.0,340.80708,0.0,0.1907,0.065,-0.032495955078,-0.032495955078,Optimal
2024-06-04 20:30:00+02:00,0.0,349.07406779661017,0.0,750.0,1099.0741,0.0,1099.0741,0.0,0.1419,0.065,-0.077979307395,-0.077979307395,Optimal
2024-06-04 21:00:00+02:00,0.0,1790.5224581005587,0.0,750.0,2540.5225,0.0,2540.5225,0.0,0.1419,0.065,-0.18025007137500001,-0.18025007137500001,Optimal
2024-06-04 21:30:00+02:00,0.0,2612.0882857142856,0.0,0.0,2612.0883,0.0,2612.0883,0.0,0.1419,0.065,-0.185327664885,-0.185327664885,Optimal
2024-06-04 22:00:00+02:00,0.0,2617.098882681564,0.0,0.0,2617.0989,0.0,2617.0989,0.0,0.1419,0.065,-0.185683166955,-0.185683166955,Optimal
2024-06-04 22:30:00+02:00,0.0,2254.2344375000002,0.0,0.0,2254.2344,0.0,2254.2344,0.0,0.1419,0.065,-0.15993793068,-0.15993793068,Optimal
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.0'
release = '0.10.1'

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

Expand Down
6 changes: 4 additions & 2 deletions scripts/script_debug_optim.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
optim_conf.update({'set_battery_dynamic': True})
optim_conf.update({'set_nodischarge_to_grid': True})

plant_conf.update({'inverter_is_hybrid': True})
plant_conf.update({'inverter_is_hybrid': False})

df_input_data.loc[df_input_data.index[25:30],'unit_prod_price'] = -0.07
df_input_data['P_PV_forecast'] = df_input_data['P_PV_forecast']*2
Expand All @@ -105,7 +105,7 @@
if plant_conf['inverter_is_hybrid']:
vars_to_plot = vars_to_plot + ['P_hybrid_inverter']
if optim_conf['set_use_battery']:
vars_to_plot = vars_to_plot + ['P_batt']
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'
fig_res_dah.layout.template = template
fig_res_dah.update_yaxes(title_text = "Powers (W)")
Expand All @@ -115,4 +115,6 @@

print("System with: PV, two deferrable loads, dayahead optimization, profit >> total cost function sum: "+\
str(opt_res_dayahead['cost_profit'].sum())+", Status: "+opt_res_dayahead['optim_status'].unique().item())

print(opt_res_dayahead[vars_to_plot])

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.0', # Required
version='0.10.1', # 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
41 changes: 21 additions & 20 deletions src/emhass/command_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def set_input_data_dict(emhass_conf: dict, costfun: str,
logger.info("Setting up needed data")
# Parsing yaml
retrieve_hass_conf, optim_conf, plant_conf = utils.get_yaml_parse(
emhass_conf, use_secrets=not (get_data_from_file), params=params)
emhass_conf, use_secrets=not(get_data_from_file), params=params)
# Treat runtimeparams
params, retrieve_hass_conf, optim_conf, plant_conf = utils.treat_runtimeparams(
runtimeparams, params, retrieve_hass_conf, optim_conf, plant_conf, set_type, logger)
Expand Down Expand Up @@ -683,8 +683,6 @@ def regressor_model_predict(input_data_dict: dict, logger: logging.Logger,
type_var="mlregressor")
return prediction



def publish_data(input_data_dict: dict, logger: logging.Logger,
save_data_to_file: Optional[bool] = False,
opt_res_latest: Optional[pd.DataFrame] = None,
Expand All @@ -708,12 +706,10 @@ def publish_data(input_data_dict: dict, logger: logging.Logger,
"""
logger.info("Publishing data to HASS instance")

if not isinstance(input_data_dict["params"],dict):
params = json.loads(input_data_dict["params"])
else:
params = input_data_dict["params"]

# Check if a day ahead optimization has been performed (read CSV file)
if save_data_to_file:
today = datetime.now(timezone.utc).replace(
Expand All @@ -726,7 +722,6 @@ def publish_data(input_data_dict: dict, logger: logging.Logger,
opt_res_list_names = []
publish_prefix = params["passed_data"]["publish_prefix"]
entity_path = input_data_dict['emhass_conf']['data_path'] / "entities"

# Check if items in entity_path
if os.path.exists(entity_path) and len(os.listdir(entity_path)) > 0:
# Obtain all files in entity_path
Expand Down Expand Up @@ -805,6 +800,20 @@ def publish_data(input_data_dict: dict, logger: logging.Logger,
dont_post=dont_post
)
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"]
# Publish deferrable loads
custom_deferrable_forecast_id = params["passed_data"][
"custom_deferrable_forecast_id"
Expand Down Expand Up @@ -944,7 +953,7 @@ def publish_data(input_data_dict: dict, logger: logging.Logger,
opt_res_latest.index[idx_closest]]]
return opt_res

def continual_publish(input_data_dict,entity_path,logger):
def continual_publish(input_data_dict: dict, entity_path: pathlib.Path, logger: logging.Logger):
"""
If continual_publish is true and a entity file saved in /data_path/entities, continually publish sensor on freq rate, updating entity current state value based on timestamp
Expand All @@ -959,23 +968,22 @@ def continual_publish(input_data_dict,entity_path,logger):
logger.info("Continual publish thread service started")
freq = input_data_dict['retrieve_hass_conf'].get("freq", pd.to_timedelta(1, "minutes"))
entity_path_contents = []

while True:
# Sleep for x seconds (using current time as a reference for time left)
time.sleep(max(0,freq.total_seconds() - (datetime.now(input_data_dict["retrieve_hass_conf"]["time_zone"]).timestamp() % 60)))

# Loop through all saved entity files
if os.path.exists(entity_path) and len(os.listdir(entity_path)) > 0:
entity_path_contents = os.listdir(entity_path)
for entity in entity_path_contents:
if entity != "metadata.json":
# Call publish_json with entity file, build entity, and publish
publish_json(entity,input_data_dict,entity_path,logger,"continual_publish")
publish_json(entity, input_data_dict, entity_path, logger, "continual_publish")
pass
# This function should never return
return False

def publish_json(entity,input_data_dict,entity_path,logger,reference: Optional[str] = ""):
def publish_json(entity: dict, input_data_dict: dict, entity_path: pathlib.Path,
logger: logging.Logger, reference: Optional[str] = ""):
"""
Extract saved entity data from .json (in data_path/entities), build entity, post results to post_data
Expand All @@ -989,9 +997,8 @@ def publish_json(entity,input_data_dict,entity_path,logger,reference: Optional[s
:type logger: logging.Logger
:param reference: String for identifying who ran the function
:type reference: str, optional
"""

# Retrieve entity metadata from file
if os.path.isfile(entity_path / "metadata.json"):
with open(entity_path / "metadata.json", "r") as file:
Expand All @@ -1001,16 +1008,12 @@ def publish_json(entity,input_data_dict,entity_path,logger,reference: Optional[s
else:
logger.error("unable to located metadata.json in:" + entity_path)
return False

# Round current timecode (now)
now_precise = datetime.now(input_data_dict["retrieve_hass_conf"]["time_zone"]).replace(second=0, microsecond=0)

# Retrieve entity data from file
entity_data = pd.read_json(entity_path / entity , orient='index')

# Remove ".json" from string for entity_id
entity_id = entity.replace(".json", "")

# Adjust Dataframe from received entity json file
entity_data.columns = [metadata[entity_id]["name"]]
entity_data.index.name = "timestamp"
Expand All @@ -1025,15 +1028,13 @@ def publish_json(entity,input_data_dict,entity_path,logger,reference: Optional[s
idx_closest = entity_data.index.get_indexer([now_precise], method="bfill")[0]
if idx_closest == -1:
idx_closest = entity_data.index.get_indexer([now_precise], method="nearest")[0]

# Call post data
if reference == "continual_publish":
logger.debug("Auto Published sensor:")
logger_levels = "DEBUG"
else:
logger_levels = "INFO"

#post/save entity
# post/save entity
input_data_dict["rh"].post_data(
data_df=entity_data[metadata[entity_id]["name"]],
idx=idx_closest,
Expand Down
Loading

0 comments on commit dd00d43

Please sign in to comment.