emhass 0.11.1__tar.gz → 0.11.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {emhass-0.11.1 → emhass-0.11.2}/CHANGELOG.md +7 -0
- {emhass-0.11.1 → emhass-0.11.2}/PKG-INFO +1 -4
- {emhass-0.11.1 → emhass-0.11.2}/README.md +0 -3
- {emhass-0.11.1 → emhass-0.11.2}/setup.py +1 -1
- {emhass-0.11.1 → emhass-0.11.2}/src/emhass/data/config_defaults.json +1 -2
- {emhass-0.11.1 → emhass-0.11.2}/src/emhass/retrieve_hass.py +20 -11
- {emhass-0.11.1 → emhass-0.11.2}/src/emhass/static/configuration_script.js +4 -4
- {emhass-0.11.1 → emhass-0.11.2}/src/emhass/utils.py +114 -62
- {emhass-0.11.1 → emhass-0.11.2}/src/emhass.egg-info/PKG-INFO +1 -4
- {emhass-0.11.1 → emhass-0.11.2}/tests/test_retrieve_hass.py +12 -6
- {emhass-0.11.1 → emhass-0.11.2}/tests/test_utils.py +1 -1
- {emhass-0.11.1 → emhass-0.11.2}/CODE_OF_CONDUCT.md +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/CONTRIBUTING.md +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/LICENSE +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/MANIFEST.in +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/data/data_load_cost_forecast.csv +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/data/data_load_forecast.csv +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/data/data_prod_price_forecast.csv +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/data/data_train_load_clustering.pkl +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/data/data_train_load_forecast.pkl +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/data/data_weather_forecast.csv +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/data/heating_prediction.csv +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/data/opt_res_latest.csv +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/data/opt_res_perfect_optim_cost.csv +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/data/opt_res_perfect_optim_profit.csv +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/data/opt_res_perfect_optim_self-consumption.csv +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/data/test_df_final.pkl +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/data/test_response_get_data_get_method.pbz2 +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/data/test_response_scrapper_get_method.pbz2 +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/data/test_response_solarforecast_get_method.pbz2 +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/data/test_response_solcast_get_method.pbz2 +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/pyproject.toml +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/setup.cfg +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/src/emhass/__init__.py +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/src/emhass/command_line.py +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/src/emhass/data/associations.csv +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/src/emhass/data/cec_inverters.pbz2 +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/src/emhass/data/cec_modules.pbz2 +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/src/emhass/forecast.py +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/src/emhass/machine_learning_forecaster.py +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/src/emhass/machine_learning_regressor.py +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/src/emhass/optimization.py +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/src/emhass/static/advanced.html +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/src/emhass/static/basic.html +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/src/emhass/static/configuration_list.html +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/src/emhass/static/data/param_definitions.json +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/src/emhass/static/img/emhass_icon.png +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/src/emhass/static/img/emhass_logo_short.svg +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/src/emhass/static/img/feather-sprite.svg +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/src/emhass/static/script.js +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/src/emhass/static/style.css +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/src/emhass/templates/configuration.html +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/src/emhass/templates/index.html +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/src/emhass/templates/template.html +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/src/emhass/web_server.py +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/src/emhass.egg-info/SOURCES.txt +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/src/emhass.egg-info/dependency_links.txt +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/src/emhass.egg-info/entry_points.txt +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/src/emhass.egg-info/requires.txt +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/src/emhass.egg-info/top_level.txt +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/tests/test_command_line_utils.py +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/tests/test_forecast.py +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/tests/test_machine_learning_forecaster.py +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/tests/test_machine_learning_regressor.py +0 -0
- {emhass-0.11.1 → emhass-0.11.2}/tests/test_optimization.py +0 -0
@@ -1,5 +1,12 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 0.11.2 - 2024-10-31
|
4
|
+
### Improvement
|
5
|
+
- Added support to retrieve HA configuration. This will be used in the future to automatically retrieve some parameters as the currency
|
6
|
+
### Fix
|
7
|
+
- utils fix runtime parameter merge bugs
|
8
|
+
- configuration_script.js fix placeholder value bug
|
9
|
+
|
3
10
|
## 0.11.1 - 2024-10-29
|
4
11
|
### Fix
|
5
12
|
- Fix parameter saving and duplicate battery bugs
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: emhass
|
3
|
-
Version: 0.11.
|
3
|
+
Version: 0.11.2
|
4
4
|
Summary: An Energy Management System for Home Assistant
|
5
5
|
Home-page: https://github.com/davidusb-geek/emhass
|
6
6
|
Author: David HERNANDEZ
|
@@ -47,9 +47,6 @@ Requires-Dist: plotly>=5.6.0
|
|
47
47
|
</a>
|
48
48
|
<a style="text-decoration:none" href="https://github.com/davidusb-geek/emhass/actions">
|
49
49
|
<img alt="EMHASS GitHub Workflow Status" src="https://github.com/davidusb-geek/emhass/actions/workflows/publish_docker.yaml/badge.svg?event=release">
|
50
|
-
</a>
|
51
|
-
<a style="text-decoration:none" href="https://github.com/davidusb-geek/emhass-add-on/actions">
|
52
|
-
<img alt="EMHASS-Add-on GitHub Workflow Status" src="https://github.com/davidusb-geek/emhass-add-on/actions/workflows/publish_docker.yaml/badge.svg?event=release">
|
53
50
|
</a>
|
54
51
|
<a hstyle="text-decoration:none" ref="https://codecov.io/github/davidusb-geek/emhass" >
|
55
52
|
<img src="https://codecov.io/github/davidusb-geek/emhass/branch/master/graph/badge.svg?token=BW7KSCHN90"/>
|
@@ -12,9 +12,6 @@
|
|
12
12
|
</a>
|
13
13
|
<a style="text-decoration:none" href="https://github.com/davidusb-geek/emhass/actions">
|
14
14
|
<img alt="EMHASS GitHub Workflow Status" src="https://github.com/davidusb-geek/emhass/actions/workflows/publish_docker.yaml/badge.svg?event=release">
|
15
|
-
</a>
|
16
|
-
<a style="text-decoration:none" href="https://github.com/davidusb-geek/emhass-add-on/actions">
|
17
|
-
<img alt="EMHASS-Add-on GitHub Workflow Status" src="https://github.com/davidusb-geek/emhass-add-on/actions/workflows/publish_docker.yaml/badge.svg?event=release">
|
18
15
|
</a>
|
19
16
|
<a hstyle="text-decoration:none" ref="https://codecov.io/github/davidusb-geek/emhass" >
|
20
17
|
<img src="https://codecov.io/github/davidusb-geek/emhass/branch/master/graph/badge.svg?token=BW7KSCHN90"/>
|
@@ -19,7 +19,7 @@ long_description = (here / 'README.md').read_text(encoding='utf-8')
|
|
19
19
|
|
20
20
|
setup(
|
21
21
|
name='emhass', # Required
|
22
|
-
version='0.11.
|
22
|
+
version='0.11.2', # Required
|
23
23
|
description='An Energy Management System for Home Assistant', # Optional
|
24
24
|
long_description=long_description, # Optional
|
25
25
|
long_description_content_type='text/markdown', # Optional (see note above)
|
@@ -19,8 +19,7 @@
|
|
19
19
|
"sensor_power_photovoltaics": "sensor.power_photovoltaics",
|
20
20
|
"sensor_power_load_no_var_loads": "sensor.power_load_no_var_loads",
|
21
21
|
"sensor_replace_zero": [
|
22
|
-
"sensor.power_photovoltaics"
|
23
|
-
"sensor.power_load_no_var_loads"
|
22
|
+
"sensor.power_photovoltaics"
|
24
23
|
],
|
25
24
|
"sensor_linear_interp": [
|
26
25
|
"sensor.power_photovoltaics",
|
@@ -72,6 +72,19 @@ class RetrieveHass:
|
|
72
72
|
self.logger = logger
|
73
73
|
self.get_data_from_file = get_data_from_file
|
74
74
|
|
75
|
+
def get_ha_config(self):
|
76
|
+
"""
|
77
|
+
Extract some configuration data from HA.
|
78
|
+
|
79
|
+
"""
|
80
|
+
headers = {
|
81
|
+
"Authorization": "Bearer " + self.long_lived_token,
|
82
|
+
"content-type": "application/json"
|
83
|
+
}
|
84
|
+
url = self.hass_url+"api/config"
|
85
|
+
response_config = get(url, headers=headers)
|
86
|
+
self.ha_config = response_config.json()
|
87
|
+
|
75
88
|
def get_data(self, days_list: pd.date_range, var_list: list,
|
76
89
|
minimal_response: Optional[bool] = False, significant_changes_only: Optional[bool] = False,
|
77
90
|
test_url: Optional[str] = "empty") -> None:
|
@@ -98,15 +111,17 @@ class RetrieveHass:
|
|
98
111
|
are experimental
|
99
112
|
"""
|
100
113
|
self.logger.info("Retrieve hass get data method initiated...")
|
114
|
+
headers = {
|
115
|
+
"Authorization": "Bearer " + self.long_lived_token,
|
116
|
+
"content-type": "application/json"
|
117
|
+
}
|
118
|
+
# Looping on each day from days list
|
101
119
|
self.df_final = pd.DataFrame()
|
102
120
|
x = 0 # iterate based on days
|
103
|
-
# Looping on each day from days list
|
104
121
|
for day in days_list:
|
105
122
|
for i, var in enumerate(var_list):
|
106
123
|
if test_url == "empty":
|
107
|
-
if (
|
108
|
-
self.hass_url == "http://supervisor/core/api"
|
109
|
-
): # If we are using the supervisor API
|
124
|
+
if (self.hass_url == "http://supervisor/core/api"): # If we are using the supervisor API
|
110
125
|
url = (
|
111
126
|
self.hass_url
|
112
127
|
+ "/history/period/"
|
@@ -124,16 +139,10 @@ class RetrieveHass:
|
|
124
139
|
)
|
125
140
|
if minimal_response: # A support for minimal response
|
126
141
|
url = url + "?minimal_response"
|
127
|
-
if (
|
128
|
-
significant_changes_only
|
129
|
-
): # And for signicant changes only (check the HASS restful API for more info)
|
142
|
+
if (significant_changes_only): # And for signicant changes only (check the HASS restful API for more info)
|
130
143
|
url = url + "?significant_changes_only"
|
131
144
|
else:
|
132
145
|
url = test_url
|
133
|
-
headers = {
|
134
|
-
"Authorization": "Bearer " + self.long_lived_token,
|
135
|
-
"content-type": "application/json",
|
136
|
-
}
|
137
146
|
try:
|
138
147
|
response = get(url, headers=headers)
|
139
148
|
except Exception:
|
@@ -407,7 +407,7 @@ function buildParamElement(
|
|
407
407
|
else {
|
408
408
|
return `
|
409
409
|
${type_specific_html}
|
410
|
-
<input class="param_input" type="${type}"
|
410
|
+
<input class="param_input" type="${type}" placeholder=${parameter_definition_object["default_value"]} value=${value} >
|
411
411
|
${type_specific_html_end}
|
412
412
|
`;
|
413
413
|
}
|
@@ -418,9 +418,9 @@ function buildParamElement(
|
|
418
418
|
if (typeof Object.values(value)[0] === "object") {
|
419
419
|
for (param of Object.values(value)) {
|
420
420
|
for (items of Object.values(param)) {
|
421
|
-
inputs += `<input class="param_input" type="${type}" value=${
|
421
|
+
inputs += `<input class="param_input" type="${type}" placeholder=${Object.values(items)[0]} value=${
|
422
422
|
Object.values(items)[0]
|
423
|
-
}
|
423
|
+
}>`;
|
424
424
|
}
|
425
425
|
inputs += `</br>`;
|
426
426
|
}
|
@@ -432,7 +432,7 @@ function buildParamElement(
|
|
432
432
|
for (param of value) {
|
433
433
|
inputs += `
|
434
434
|
${type_specific_html}
|
435
|
-
<input class="param_input" type="${type}"
|
435
|
+
<input class="param_input" type="${type}" placeholder=${parameter_definition_object["default_value"]} value=${param}>
|
436
436
|
${type_specific_html_end}
|
437
437
|
`;
|
438
438
|
}
|
@@ -288,7 +288,7 @@ def treat_runtimeparams(runtimeparams: str, params: str, retrieve_hass_conf: dic
|
|
288
288
|
else:
|
289
289
|
prediction_horizon = runtimeparams["prediction_horizon"]
|
290
290
|
params["passed_data"]["prediction_horizon"] = prediction_horizon
|
291
|
-
if
|
291
|
+
if 'soc_init' not in runtimeparams.keys():
|
292
292
|
soc_init = plant_conf['battery_target_state_of_charge']
|
293
293
|
else:
|
294
294
|
soc_init = runtimeparams["soc_init"]
|
@@ -298,23 +298,24 @@ def treat_runtimeparams(runtimeparams: str, params: str, retrieve_hass_conf: dic
|
|
298
298
|
else:
|
299
299
|
soc_final = runtimeparams["soc_final"]
|
300
300
|
params["passed_data"]["soc_final"] = soc_final
|
301
|
-
if 'operating_hours_of_each_deferrable_load' not in runtimeparams.keys():
|
302
|
-
def_total_hours = optim_conf
|
301
|
+
if 'operating_hours_of_each_deferrable_load' not in runtimeparams.keys() and 'def_total_hours' not in runtimeparams.keys():
|
302
|
+
def_total_hours = optim_conf.get('operating_hours_of_each_deferrable_load')
|
303
303
|
else:
|
304
|
-
def_total_hours = runtimeparams
|
304
|
+
def_total_hours = runtimeparams.get(
|
305
|
+
'operating_hours_of_each_deferrable_load', runtimeparams.get('def_total_hours'))
|
305
306
|
params["passed_data"]['operating_hours_of_each_deferrable_load'] = def_total_hours
|
306
|
-
if 'start_timesteps_of_each_deferrable_load' in runtimeparams.keys():
|
307
|
-
def_start_timestep =
|
308
|
-
else:
|
307
|
+
if 'start_timesteps_of_each_deferrable_load' not in runtimeparams.keys() and 'def_start_timestep' in runtimeparams.keys():
|
308
|
+
def_start_timestep = optim_conf.get('start_timesteps_of_each_deferrable_load')
|
309
|
+
else:
|
309
310
|
def_start_timestep = runtimeparams.get(
|
310
|
-
'
|
311
|
+
'start_timesteps_of_each_deferrable_load', runtimeparams.get('def_start_timestep'))
|
311
312
|
params["passed_data"]['start_timesteps_of_each_deferrable_load'] = def_start_timestep
|
312
|
-
if 'end_timesteps_of_each_deferrable_load' in runtimeparams.keys():
|
313
|
-
def_end_timestep =
|
313
|
+
if 'end_timesteps_of_each_deferrable_load' not in runtimeparams.keys() and 'def_end_timestep' not in runtimeparams.keys():
|
314
|
+
def_end_timestep = optim_conf.get('end_timesteps_of_each_deferrable_load')
|
314
315
|
else:
|
315
316
|
def_end_timestep = runtimeparams.get(
|
316
|
-
'
|
317
|
-
params["passed_data"][
|
317
|
+
'end_timesteps_of_each_deferrable_load', runtimeparams.get('def_end_timestep'))
|
318
|
+
params["passed_data"]['end_timesteps_of_each_deferrable_load'] = def_end_timestep
|
318
319
|
forecast_dates = copy.deepcopy(forecast_dates)[0:prediction_horizon]
|
319
320
|
# Load the default config
|
320
321
|
if "def_load_config" in optim_conf:
|
@@ -364,11 +365,16 @@ def treat_runtimeparams(runtimeparams: str, params: str, retrieve_hass_conf: dic
|
|
364
365
|
params['passed_data'][forecast_key] = None
|
365
366
|
|
366
367
|
# Treat passed data for forecast model fit/predict/tune at runtime
|
367
|
-
if 'historic_days_to_retrieve' in runtimeparams.keys():
|
368
|
-
|
368
|
+
if 'historic_days_to_retrieve' not in runtimeparams.keys() and 'days_to_retrieve' not in runtimeparams.keys():
|
369
|
+
historic_days_to_retrieve = retrieve_hass_conf.get('historic_days_to_retrieve')
|
369
370
|
else:
|
370
|
-
|
371
|
-
|
371
|
+
historic_days_to_retrieve = runtimeparams.get(
|
372
|
+
'historic_days_to_retrieve', runtimeparams.get('days_to_retrieve'))
|
373
|
+
if historic_days_to_retrieve < 9:
|
374
|
+
logger.warning("warning `days_to_retrieve` is set to a value less than 9, this could cause an error with the fit")
|
375
|
+
logger.warning("setting`passed_data:days_to_retrieve` to 9 for fit/predict/tune")
|
376
|
+
historic_days_to_retrieve = 9
|
377
|
+
params["passed_data"]['historic_days_to_retrieve'] = historic_days_to_retrieve
|
372
378
|
if "model_type" not in runtimeparams.keys():
|
373
379
|
model_type = "load_forecast"
|
374
380
|
else:
|
@@ -479,50 +485,35 @@ def treat_runtimeparams(runtimeparams: str, params: str, retrieve_hass_conf: dic
|
|
479
485
|
params["passed_data"]["publish_prefix"] = publish_prefix
|
480
486
|
|
481
487
|
# Treat optimization (optim_conf) configuration parameters passed at runtime
|
482
|
-
if 'number_of_deferrable_loads' in runtimeparams.keys():
|
483
|
-
optim_conf['number_of_deferrable_loads'] = runtimeparams
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
if '
|
489
|
-
optim_conf['
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
if '
|
495
|
-
optim_conf['
|
496
|
-
|
497
|
-
optim_conf['end_timesteps_of_each_deferrable_load'] = runtimeparams['end_timesteps_of_each_deferrable_load']
|
488
|
+
if 'number_of_deferrable_loads' in runtimeparams.keys() or 'num_def_loads' in runtimeparams.keys():
|
489
|
+
optim_conf['number_of_deferrable_loads'] = runtimeparams.get(
|
490
|
+
'number_of_deferrable_loads', runtimeparams.get('num_def_loads'))
|
491
|
+
if 'nominal_power_of_deferrable_loads' in runtimeparams.keys() or 'P_deferrable_nom' in runtimeparams.keys():
|
492
|
+
optim_conf['nominal_power_of_deferrable_loads'] = runtimeparams.get(
|
493
|
+
'nominal_power_of_deferrable_loads', runtimeparams.get('P_deferrable_nom'))
|
494
|
+
if 'operating_hours_of_each_deferrable_load' in runtimeparams.keys() or 'def_total_hours' in runtimeparams.keys():
|
495
|
+
optim_conf['operating_hours_of_each_deferrable_load'] = runtimeparams.get(
|
496
|
+
'operating_hours_of_each_deferrable_load', runtimeparams.get('def_total_hours'))
|
497
|
+
if 'start_timesteps_of_each_deferrable_load' in runtimeparams.keys() or 'def_start_timestep' in runtimeparams.keys():
|
498
|
+
optim_conf['start_timesteps_of_each_deferrable_load'] = runtimeparams.get(
|
499
|
+
'start_timesteps_of_each_deferrable_load', runtimeparams.get('def_start_timestep'))
|
500
|
+
if 'end_timesteps_of_each_deferrable_load' in runtimeparams.keys() or 'def_end_timestep' in runtimeparams.keys():
|
501
|
+
optim_conf['end_timesteps_of_each_deferrable_load'] = runtimeparams.get(
|
502
|
+
'end_timesteps_of_each_deferrable_load', runtimeparams.get('def_end_timestep'))
|
498
503
|
if "def_current_state" in runtimeparams.keys():
|
499
504
|
optim_conf["def_current_state"] = [
|
500
505
|
bool(s) for s in runtimeparams["def_current_state"]]
|
501
|
-
if 'treat_deferrable_load_as_semi_cont' in runtimeparams.keys():
|
502
|
-
optim_conf['treat_deferrable_load_as_semi_cont'] = [
|
503
|
-
ast.literal_eval(str(k).capitalize())
|
504
|
-
for k in runtimeparams['treat_deferrable_load_as_semi_cont']
|
505
|
-
]
|
506
|
-
if 'treat_def_as_semi_cont' in runtimeparams.keys():
|
506
|
+
if 'treat_deferrable_load_as_semi_cont' in runtimeparams.keys() or 'treat_def_as_semi_cont' in runtimeparams.keys():
|
507
507
|
optim_conf['treat_deferrable_load_as_semi_cont'] = [
|
508
|
-
ast.literal_eval(str(k).capitalize())
|
509
|
-
|
510
|
-
|
511
|
-
if 'set_deferrable_load_single_constant' in runtimeparams.keys():
|
508
|
+
ast.literal_eval(str(k).capitalize()) for k in runtimeparams.get('treat_deferrable_load_as_semi_cont',runtimeparams.get('treat_def_as_semi_cont'))
|
509
|
+
]
|
510
|
+
if 'set_deferrable_load_single_constant' in runtimeparams.keys() or 'set_def_constant' in runtimeparams.keys():
|
512
511
|
optim_conf['set_deferrable_load_single_constant'] = [
|
513
|
-
ast.literal_eval(str(k).capitalize()) for k in runtimeparams
|
512
|
+
ast.literal_eval(str(k).capitalize()) for k in runtimeparams.get('set_deferrable_load_single_constant',runtimeparams.get('set_def_constant'))
|
514
513
|
]
|
515
|
-
if '
|
516
|
-
optim_conf['set_deferrable_load_single_constant'] = [
|
517
|
-
ast.literal_eval(str(k).capitalize()) for k in runtimeparams['set_def_constant']
|
518
|
-
]
|
519
|
-
if 'set_deferrable_startup_penalty' in runtimeparams.keys():
|
520
|
-
optim_conf['set_deferrable_startup_penalty'] = [
|
521
|
-
ast.literal_eval(str(k).capitalize()) for k in runtimeparams['set_deferrable_startup_penalty']
|
522
|
-
]
|
523
|
-
if 'def_start_penalty' in runtimeparams.keys():
|
514
|
+
if 'set_deferrable_startup_penalty' in runtimeparams.keys() or 'def_start_penalty' in runtimeparams.keys():
|
524
515
|
optim_conf['set_deferrable_startup_penalty'] = [
|
525
|
-
ast.literal_eval(str(k).capitalize()) for k in runtimeparams
|
516
|
+
ast.literal_eval(str(k).capitalize()) for k in runtimeparams.get('set_deferrable_startup_penalty',runtimeparams.get('def_start_penalty'))
|
526
517
|
]
|
527
518
|
if 'def_load_config' in runtimeparams:
|
528
519
|
optim_conf["def_load_config"] = runtimeparams['def_load_config']
|
@@ -534,9 +525,9 @@ def treat_runtimeparams(runtimeparams: str, params: str, retrieve_hass_conf: dic
|
|
534
525
|
optim_conf['weight_battery_charge'] = runtimeparams['weight_battery_charge']
|
535
526
|
|
536
527
|
# Treat retrieve data from Home Assistant (retrieve_hass_conf) configuration parameters passed at runtime
|
537
|
-
if 'optimization_time_step' in runtimeparams.keys():
|
538
|
-
retrieve_hass_conf['optimization_time_step'] = pd.to_timedelta(
|
539
|
-
|
528
|
+
if 'optimization_time_step' in runtimeparams.keys() or 'freq' in runtimeparams.keys():
|
529
|
+
retrieve_hass_conf['optimization_time_step'] = pd.to_timedelta(runtimeparams.get(
|
530
|
+
'optimization_time_step', runtimeparams.get('freq')), "minutes")
|
540
531
|
if 'continual_publish' in runtimeparams.keys():
|
541
532
|
retrieve_hass_conf['continual_publish'] = bool(
|
542
533
|
runtimeparams['continual_publish'])
|
@@ -653,9 +644,7 @@ def get_yaml_parse(params: str, logger: logging.Logger) -> Tuple[dict, dict, dic
|
|
653
644
|
return False, False, False
|
654
645
|
|
655
646
|
optim_conf = input_conf.get("optim_conf", {})
|
656
|
-
|
657
647
|
retrieve_hass_conf = input_conf.get("retrieve_hass_conf", {})
|
658
|
-
|
659
648
|
plant_conf = input_conf.get("plant_conf", {})
|
660
649
|
|
661
650
|
# Format time parameters
|
@@ -668,6 +657,70 @@ def get_yaml_parse(params: str, logger: logging.Logger) -> Tuple[dict, dict, dic
|
|
668
657
|
|
669
658
|
return retrieve_hass_conf, optim_conf, plant_conf
|
670
659
|
|
660
|
+
def get_legacy_yaml_parse(emhass_conf: dict, use_secrets: Optional[bool] = True,
|
661
|
+
params: Optional[str] = None) -> Tuple[dict, dict, dict]:
|
662
|
+
"""
|
663
|
+
Perform parsing of the config.yaml file.
|
664
|
+
|
665
|
+
:param emhass_conf: Dictionary containing the needed emhass paths
|
666
|
+
:type emhass_conf: dict
|
667
|
+
:param use_secrets: Indicate if we should use a secrets file or not.
|
668
|
+
Set to False for unit tests.
|
669
|
+
:type use_secrets: bool, optional
|
670
|
+
:param params: Configuration parameters passed from data/options.json
|
671
|
+
:type params: str
|
672
|
+
:return: A tuple with the dictionaries containing the parsed data
|
673
|
+
:rtype: tuple(dict)
|
674
|
+
|
675
|
+
"""
|
676
|
+
if params is None:
|
677
|
+
with open(emhass_conf["config_path"], 'r') as file:
|
678
|
+
input_conf = yaml.load(file, Loader=yaml.FullLoader)
|
679
|
+
else:
|
680
|
+
input_conf = json.loads(params)
|
681
|
+
if use_secrets:
|
682
|
+
if params is None:
|
683
|
+
with open(emhass_conf["config_path"].parent / 'secrets_emhass.yaml', 'r') as file: # Assume secrets and config file paths are the same
|
684
|
+
input_secrets = yaml.load(file, Loader=yaml.FullLoader)
|
685
|
+
else:
|
686
|
+
input_secrets = input_conf.pop("params_secrets", None)
|
687
|
+
|
688
|
+
if type(input_conf["retrieve_hass_conf"]) == list: # if using old config version
|
689
|
+
retrieve_hass_conf = dict(
|
690
|
+
{key: d[key] for d in input_conf["retrieve_hass_conf"] for key in d}
|
691
|
+
)
|
692
|
+
else:
|
693
|
+
retrieve_hass_conf = input_conf.get("retrieve_hass_conf", {})
|
694
|
+
|
695
|
+
if use_secrets:
|
696
|
+
retrieve_hass_conf.update(input_secrets)
|
697
|
+
else:
|
698
|
+
retrieve_hass_conf["hass_url"] = "http://supervisor/core/api"
|
699
|
+
retrieve_hass_conf["long_lived_token"] = "${SUPERVISOR_TOKEN}"
|
700
|
+
retrieve_hass_conf["time_zone"] = "Europe/Paris"
|
701
|
+
retrieve_hass_conf["lat"] = 45.83
|
702
|
+
retrieve_hass_conf["lon"] = 6.86
|
703
|
+
retrieve_hass_conf["alt"] = 4807.8
|
704
|
+
retrieve_hass_conf["freq"] = pd.to_timedelta(retrieve_hass_conf["freq"], "minutes")
|
705
|
+
retrieve_hass_conf["time_zone"] = pytz.timezone(retrieve_hass_conf["time_zone"])
|
706
|
+
|
707
|
+
if type(input_conf["optim_conf"]) == list:
|
708
|
+
optim_conf = dict({key: d[key] for d in input_conf["optim_conf"] for key in d})
|
709
|
+
else:
|
710
|
+
optim_conf = input_conf.get("optim_conf", {})
|
711
|
+
|
712
|
+
optim_conf["list_hp_periods"] = dict(
|
713
|
+
(key, d[key]) for d in optim_conf["list_hp_periods"] for key in d
|
714
|
+
)
|
715
|
+
optim_conf["delta_forecast"] = pd.Timedelta(days=optim_conf["delta_forecast"])
|
716
|
+
|
717
|
+
if type(input_conf["plant_conf"]) == list:
|
718
|
+
plant_conf = dict({key: d[key] for d in input_conf["plant_conf"] for key in d})
|
719
|
+
else:
|
720
|
+
plant_conf = input_conf.get("plant_conf", {})
|
721
|
+
|
722
|
+
return retrieve_hass_conf, optim_conf, plant_conf
|
723
|
+
|
671
724
|
|
672
725
|
def get_injection_dict(df: pd.DataFrame, plot_size: Optional[int] = 1366) -> dict:
|
673
726
|
"""
|
@@ -867,7 +920,7 @@ def build_config(emhass_conf: dict, logger: logging.Logger, defaults_path: str,
|
|
867
920
|
|
868
921
|
|
869
922
|
def build_legacy_config_params(emhass_conf: dict, legacy_config: dict,
|
870
|
-
|
923
|
+
logger: logging.Logger) -> dict:
|
871
924
|
"""
|
872
925
|
Build a config dictionary with legacy config_emhass.yaml file.
|
873
926
|
Uses the associations file to convert parameter naming conventions (to config.json/config_defaults.json).
|
@@ -918,8 +971,7 @@ def build_legacy_config_params(emhass_conf: dict, legacy_config: dict,
|
|
918
971
|
return config
|
919
972
|
# params['associations_dict'] = associations_dict
|
920
973
|
|
921
|
-
def param_to_config(param: dict,
|
922
|
-
logger: logging.Logger) -> dict:
|
974
|
+
def param_to_config(param: dict, logger: logging.Logger) -> dict:
|
923
975
|
"""
|
924
976
|
A function that extracts the parameters from param back to the config.json format.
|
925
977
|
Extracts parameters from config catagories.
|
@@ -949,7 +1001,7 @@ def param_to_config(param: dict,
|
|
949
1001
|
return return_config
|
950
1002
|
|
951
1003
|
def build_secrets(emhass_conf: dict, logger: logging.Logger, argument: Optional[dict] = {}, options_path: Optional[str] = None,
|
952
|
-
|
1004
|
+
secrets_path: Optional[str] = None, no_response: Optional[bool] = False) -> Tuple[dict, dict]:
|
953
1005
|
"""
|
954
1006
|
Retrieve and build parameters from secrets locations (ENV, ARG, Secrets file (secrets_emhass.yaml/options.json) and/or Home Assistant (via API))
|
955
1007
|
priority order (lwo to high) = Defaults (written in function), ENV, Options json file, Home Assistant API, Secrets yaml file, Arguments
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: emhass
|
3
|
-
Version: 0.11.
|
3
|
+
Version: 0.11.2
|
4
4
|
Summary: An Energy Management System for Home Assistant
|
5
5
|
Home-page: https://github.com/davidusb-geek/emhass
|
6
6
|
Author: David HERNANDEZ
|
@@ -47,9 +47,6 @@ Requires-Dist: plotly>=5.6.0
|
|
47
47
|
</a>
|
48
48
|
<a style="text-decoration:none" href="https://github.com/davidusb-geek/emhass/actions">
|
49
49
|
<img alt="EMHASS GitHub Workflow Status" src="https://github.com/davidusb-geek/emhass/actions/workflows/publish_docker.yaml/badge.svg?event=release">
|
50
|
-
</a>
|
51
|
-
<a style="text-decoration:none" href="https://github.com/davidusb-geek/emhass-add-on/actions">
|
52
|
-
<img alt="EMHASS-Add-on GitHub Workflow Status" src="https://github.com/davidusb-geek/emhass-add-on/actions/workflows/publish_docker.yaml/badge.svg?event=release">
|
53
50
|
</a>
|
54
51
|
<a hstyle="text-decoration:none" ref="https://codecov.io/github/davidusb-geek/emhass" >
|
55
52
|
<img src="https://codecov.io/github/davidusb-geek/emhass/branch/master/graph/badge.svg?token=BW7KSCHN90"/>
|
@@ -34,10 +34,16 @@ class TestRetrieveHass(unittest.TestCase):
|
|
34
34
|
save_data_to_file = False
|
35
35
|
|
36
36
|
# Build params with default secrets (no config)
|
37
|
-
if emhass_conf['defaults_path'].exists():
|
38
|
-
|
39
|
-
|
40
|
-
|
37
|
+
if emhass_conf['defaults_path'].exists():
|
38
|
+
if get_data_from_file:
|
39
|
+
_,secrets = utils.build_secrets(emhass_conf,logger,no_response=True)
|
40
|
+
params = utils.build_params(emhass_conf,secrets,{},logger)
|
41
|
+
retrieve_hass_conf, _, _ = get_yaml_parse(params,logger)
|
42
|
+
else:
|
43
|
+
emhass_conf['secrets_path'] = root / 'secrets_emhass.yaml'
|
44
|
+
emhass_conf['config_path'] = pathlib.Path(root) / 'config_emhass.yaml'
|
45
|
+
retrieve_hass_conf, _, _ = utils.get_legacy_yaml_parse(emhass_conf)
|
46
|
+
params = None
|
41
47
|
else:
|
42
48
|
raise Exception("config_defaults. does not exist in path: "+str(emhass_conf['defaults_path'] ))
|
43
49
|
|
@@ -60,8 +66,8 @@ class TestRetrieveHass(unittest.TestCase):
|
|
60
66
|
self.rh.df_final, self.days_list, self.var_list = pickle.load(inp)
|
61
67
|
# Else obtain sensor values from HA
|
62
68
|
else:
|
63
|
-
self.days_list = get_days_list(self.retrieve_hass_conf['
|
64
|
-
self.var_list = [self.retrieve_hass_conf['
|
69
|
+
self.days_list = get_days_list(self.retrieve_hass_conf['days_to_retrieve'])
|
70
|
+
self.var_list = [self.retrieve_hass_conf['var_PV'], self.retrieve_hass_conf['var_load']]
|
65
71
|
self.rh.get_data(self.days_list, self.var_list,
|
66
72
|
minimal_response=False, significant_changes_only=False)
|
67
73
|
# Check to save updated data to file
|
@@ -67,7 +67,7 @@ class TestCommandLineUtils(unittest.TestCase):
|
|
67
67
|
self.assertTrue(params['optim_conf']['lp_solver'] == "default")
|
68
68
|
self.assertTrue(params['optim_conf']['lp_solver_path'] == "empty")
|
69
69
|
self.assertTrue(config['load_peak_hour_periods'] == {'period_hp_1': [{'start': '02:54'}, {'end': '15:24'}], 'period_hp_2': [{'start': '17:24'}, {'end': '20:24'}]})
|
70
|
-
self.assertTrue(params['retrieve_hass_conf']['sensor_replace_zero'] == ['sensor.power_photovoltaics'
|
70
|
+
self.assertTrue(params['retrieve_hass_conf']['sensor_replace_zero'] == ['sensor.power_photovoltaics'])
|
71
71
|
# Test with config.json
|
72
72
|
config = utils.build_config(emhass_conf,logger,emhass_conf['defaults_path'],emhass_conf['config_path'])
|
73
73
|
params = utils.build_params(emhass_conf,{},config,logger)
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|