emhass 0.4.3__py3-none-any.whl → 0.4.5__py3-none-any.whl
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/command_line.py +5 -4
- emhass/templates/index.html +54 -18
- emhass/utils.py +56 -57
- emhass/web_server.py +29 -12
- {emhass-0.4.3.dist-info → emhass-0.4.5.dist-info}/METADATA +1 -1
- emhass-0.4.5.dist-info/RECORD +15 -0
- emhass-0.4.3.dist-info/RECORD +0 -15
- {emhass-0.4.3.dist-info → emhass-0.4.5.dist-info}/WHEEL +0 -0
- {emhass-0.4.3.dist-info → emhass-0.4.5.dist-info}/entry_points.txt +0 -0
- {emhass-0.4.3.dist-info → emhass-0.4.5.dist-info}/top_level.txt +0 -0
emhass/command_line.py
CHANGED
@@ -383,7 +383,8 @@ def forecast_model_predict(input_data_dict: dict, logger: logging.Logger,
|
|
383
383
|
return predictions
|
384
384
|
|
385
385
|
def forecast_model_tune(input_data_dict: dict, logger: logging.Logger,
|
386
|
-
debug: Optional[bool] = False, mlf: Optional[mlforecaster] = None
|
386
|
+
debug: Optional[bool] = False, mlf: Optional[mlforecaster] = None
|
387
|
+
) -> Tuple[pd.DataFrame, mlforecaster]:
|
387
388
|
"""Tune a forecast model hyperparameters using bayesian optimization.
|
388
389
|
|
389
390
|
:param input_data_dict: A dictionnary with multiple data used by the action functions
|
@@ -417,7 +418,7 @@ def forecast_model_tune(input_data_dict: dict, logger: logging.Logger,
|
|
417
418
|
filename = model_type+'_mlf.pkl'
|
418
419
|
with open(pathlib.Path(root) / filename, 'wb') as outp:
|
419
420
|
pickle.dump(mlf, outp, pickle.HIGHEST_PROTOCOL)
|
420
|
-
return df_pred_optim
|
421
|
+
return df_pred_optim, mlf
|
421
422
|
|
422
423
|
def publish_data(input_data_dict: dict, logger: logging.Logger,
|
423
424
|
save_data_to_file: Optional[bool] = False,
|
@@ -590,7 +591,7 @@ def main():
|
|
590
591
|
_, _, mlf = forecast_model_fit(input_data_dict, logger, debug=args.debug)
|
591
592
|
else:
|
592
593
|
mlf = None
|
593
|
-
df_pred_optim = forecast_model_tune(input_data_dict, logger, debug=args.debug, mlf=mlf)
|
594
|
+
df_pred_optim, mlf = forecast_model_tune(input_data_dict, logger, debug=args.debug, mlf=mlf)
|
594
595
|
opt_res = None
|
595
596
|
elif args.action == 'publish-data':
|
596
597
|
opt_res = publish_data(input_data_dict, logger)
|
@@ -609,7 +610,7 @@ def main():
|
|
609
610
|
elif args.action == 'forecast-model-predict':
|
610
611
|
return df_pred
|
611
612
|
elif args.action == 'forecast-model-tune':
|
612
|
-
return df_pred_optim
|
613
|
+
return df_pred_optim, mlf
|
613
614
|
|
614
615
|
if __name__ == '__main__':
|
615
616
|
main()
|
emhass/templates/index.html
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
<head>
|
4
4
|
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
|
5
5
|
<title>EMHASS: Energy Management Optimization for Home Assistant</title>
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6
7
|
<link rel="stylesheet" type="text/css" href="../static/style.css">
|
7
8
|
</head>
|
8
9
|
<body>
|
@@ -15,9 +16,12 @@
|
|
15
16
|
<h4 style="font-family: Helvetica;color: darkblue;">Use the buttons below to manually launch different optimization tasks</h4>
|
16
17
|
<button type="button" id="perfect-optimization" class="button button1" >Perfect Optimization</button>
|
17
18
|
<button type="button" id="dayahead-optimization" class="button button2" >Day-ahead Optimization</button>
|
18
|
-
<!-- <button type="button" id="naive-mpc-optimization" class="button button3" >Naive MPC Optimization</button> -->
|
19
19
|
<h4 style="font-family: Helvetica;color: darkblue;">Use the button below to publish the optimized variables at the current timestamp</h4>
|
20
20
|
<button type="button" id="publish-data" class="button button1" >Publish Optimization Results</button>
|
21
|
+
<h4 style="font-family: Helvetica;color: darkblue;">Use the buttons below to fit, predict and tune a machine learning model for testing</h4>
|
22
|
+
<button type="button" id="forecast-model-fit" class="button button1" >ML forecast model fit</button>
|
23
|
+
<button type="button" id="forecast-model-predict" class="button button2" >ML forecast model predict</button>
|
24
|
+
<button type="button" id="forecast-model-tune" class="button button3" >ML forecast model tune</button>
|
21
25
|
<br>
|
22
26
|
</form>
|
23
27
|
<br><br>
|
@@ -30,7 +34,7 @@
|
|
30
34
|
{% endfor %}
|
31
35
|
<footer class="footer">
|
32
36
|
<center>
|
33
|
-
<p style="font-family: Helvetica;color: darkblue;">© MIT License | Copyright (c) 2021-
|
37
|
+
<p style="font-family: Helvetica;color: darkblue;">© MIT License | Copyright (c) 2021-2023 David HERNANDEZ</p>
|
34
38
|
</center>
|
35
39
|
</footer>
|
36
40
|
</body>
|
@@ -67,22 +71,6 @@
|
|
67
71
|
$.ajax(settings).done(function (response) {
|
68
72
|
});
|
69
73
|
});
|
70
|
-
// document.getElementById('naive-mpc-optimization').addEventListener('click', function() {
|
71
|
-
// var url = "/action/naive-mpc-optim"
|
72
|
-
// var settings = {
|
73
|
-
// "async": true,
|
74
|
-
// "crossDomain": true,
|
75
|
-
// "url": url,
|
76
|
-
// "method": "POST",
|
77
|
-
// "headers": {
|
78
|
-
// 'Content-Type':'application/json'
|
79
|
-
// },
|
80
|
-
// "dataType": 'json',
|
81
|
-
// "data": '{}'
|
82
|
-
// }
|
83
|
-
// $.ajax(settings).done(function (response) {
|
84
|
-
// });
|
85
|
-
// });
|
86
74
|
document.getElementById('publish-data').addEventListener('click', function() {
|
87
75
|
var url = "/action/publish-data"
|
88
76
|
var settings = {
|
@@ -99,5 +87,53 @@
|
|
99
87
|
$.ajax(settings).done(function (response) {
|
100
88
|
});
|
101
89
|
});
|
90
|
+
document.getElementById('forecast-model-fit').addEventListener('click', function() {
|
91
|
+
var url = "/action/forecast-model-fit"
|
92
|
+
var settings = {
|
93
|
+
"async": true,
|
94
|
+
"crossDomain": true,
|
95
|
+
"url": url,
|
96
|
+
"method": "POST",
|
97
|
+
"headers": {
|
98
|
+
'Content-Type':'application/json'
|
99
|
+
},
|
100
|
+
"dataType": 'json',
|
101
|
+
"data": '{}'
|
102
|
+
}
|
103
|
+
$.ajax(settings).done(function (response) {
|
104
|
+
});
|
105
|
+
});
|
106
|
+
document.getElementById('forecast-model-predict').addEventListener('click', function() {
|
107
|
+
var url = "/action/forecast-model-predict"
|
108
|
+
var settings = {
|
109
|
+
"async": true,
|
110
|
+
"crossDomain": true,
|
111
|
+
"url": url,
|
112
|
+
"method": "POST",
|
113
|
+
"headers": {
|
114
|
+
'Content-Type':'application/json'
|
115
|
+
},
|
116
|
+
"dataType": 'json',
|
117
|
+
"data": '{}'
|
118
|
+
}
|
119
|
+
$.ajax(settings).done(function (response) {
|
120
|
+
});
|
121
|
+
});
|
122
|
+
document.getElementById('forecast-model-tune').addEventListener('click', function() {
|
123
|
+
var url = "/action/forecast-model-tune"
|
124
|
+
var settings = {
|
125
|
+
"async": true,
|
126
|
+
"crossDomain": true,
|
127
|
+
"url": url,
|
128
|
+
"method": "POST",
|
129
|
+
"headers": {
|
130
|
+
'Content-Type':'application/json'
|
131
|
+
},
|
132
|
+
"dataType": 'json',
|
133
|
+
"data": '{}'
|
134
|
+
}
|
135
|
+
$.ajax(settings).done(function (response) {
|
136
|
+
});
|
137
|
+
});
|
102
138
|
</script>
|
103
139
|
</html>
|
emhass/utils.py
CHANGED
@@ -244,63 +244,62 @@ def treat_runtimeparams(runtimeparams: str, params: str, retrieve_hass_conf: dic
|
|
244
244
|
logger.warning("This value in prod_price_forecast was detected as non digits: "+str(x))
|
245
245
|
else:
|
246
246
|
params['passed_data']['prod_price_forecast'] = None
|
247
|
-
# Treat passed data for forecast model fit/predict/tune
|
248
|
-
if
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
params['passed_data']['model_predict_friendly_name'] = model_predict_friendly_name
|
247
|
+
# Treat passed data for forecast model fit/predict/tune at runtime
|
248
|
+
if 'days_to_retrieve' not in runtimeparams.keys():
|
249
|
+
days_to_retrieve = 30
|
250
|
+
else:
|
251
|
+
days_to_retrieve = runtimeparams['days_to_retrieve']
|
252
|
+
params['passed_data']['days_to_retrieve'] = days_to_retrieve
|
253
|
+
if 'model_type' not in runtimeparams.keys():
|
254
|
+
model_type = "load_forecast"
|
255
|
+
else:
|
256
|
+
model_type = runtimeparams['model_type']
|
257
|
+
params['passed_data']['model_type'] = model_type
|
258
|
+
if 'var_model' not in runtimeparams.keys():
|
259
|
+
var_model = "sensor.power_load_no_var_loads"
|
260
|
+
else:
|
261
|
+
var_model = runtimeparams['var_model']
|
262
|
+
params['passed_data']['var_model'] = var_model
|
263
|
+
if 'sklearn_model' not in runtimeparams.keys():
|
264
|
+
sklearn_model = "KNeighborsRegressor"
|
265
|
+
else:
|
266
|
+
sklearn_model = runtimeparams['sklearn_model']
|
267
|
+
params['passed_data']['sklearn_model'] = sklearn_model
|
268
|
+
if 'num_lags' not in runtimeparams.keys():
|
269
|
+
num_lags = 48
|
270
|
+
else:
|
271
|
+
num_lags = runtimeparams['num_lags']
|
272
|
+
params['passed_data']['num_lags'] = num_lags
|
273
|
+
if 'split_date_delta' not in runtimeparams.keys():
|
274
|
+
split_date_delta = '48h'
|
275
|
+
else:
|
276
|
+
split_date_delta = runtimeparams['split_date_delta']
|
277
|
+
params['passed_data']['split_date_delta'] = split_date_delta
|
278
|
+
if 'perform_backtest' not in runtimeparams.keys():
|
279
|
+
perform_backtest = False
|
280
|
+
else:
|
281
|
+
perform_backtest = runtimeparams['perform_backtest']
|
282
|
+
params['passed_data']['perform_backtest'] = perform_backtest
|
283
|
+
if 'model_predict_publish' not in runtimeparams.keys():
|
284
|
+
model_predict_publish = False
|
285
|
+
else:
|
286
|
+
model_predict_publish = runtimeparams['model_predict_publish']
|
287
|
+
params['passed_data']['model_predict_publish'] = model_predict_publish
|
288
|
+
if 'model_predict_entity_id' not in runtimeparams.keys():
|
289
|
+
model_predict_entity_id = "sensor.p_load_forecast_custom_model"
|
290
|
+
else:
|
291
|
+
model_predict_entity_id = runtimeparams['model_predict_entity_id']
|
292
|
+
params['passed_data']['model_predict_entity_id'] = model_predict_entity_id
|
293
|
+
if 'model_predict_unit_of_measurement' not in runtimeparams.keys():
|
294
|
+
model_predict_unit_of_measurement = "W"
|
295
|
+
else:
|
296
|
+
model_predict_unit_of_measurement = runtimeparams['model_predict_unit_of_measurement']
|
297
|
+
params['passed_data']['model_predict_unit_of_measurement'] = model_predict_unit_of_measurement
|
298
|
+
if 'model_predict_friendly_name' not in runtimeparams.keys():
|
299
|
+
model_predict_friendly_name = "Load Power Forecast custom ML model"
|
300
|
+
else:
|
301
|
+
model_predict_friendly_name = runtimeparams['model_predict_friendly_name']
|
302
|
+
params['passed_data']['model_predict_friendly_name'] = model_predict_friendly_name
|
304
303
|
# Treat optimization configuration parameters passed at runtime
|
305
304
|
if 'num_def_loads' in runtimeparams.keys():
|
306
305
|
optim_conf['num_def_loads'] = runtimeparams['num_def_loads']
|
emhass/web_server.py
CHANGED
@@ -11,6 +11,7 @@ import os, json, argparse, pickle, yaml, logging
|
|
11
11
|
from distutils.util import strtobool
|
12
12
|
import pandas as pd
|
13
13
|
import plotly.express as px
|
14
|
+
pd.options.plotting.backend = "plotly"
|
14
15
|
from emhass.command_line import set_input_data_dict
|
15
16
|
from emhass.command_line import perfect_forecast_optim, dayahead_forecast_optim, naive_mpc_optim
|
16
17
|
from emhass.command_line import forecast_model_fit, forecast_model_predict, forecast_model_tune
|
@@ -18,23 +19,27 @@ from emhass.command_line import publish_data
|
|
18
19
|
|
19
20
|
|
20
21
|
# Define the Flask instance
|
21
|
-
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(message)s')
|
22
22
|
app = Flask(__name__)
|
23
|
-
|
23
|
+
app.logger.setLevel(logging.DEBUG)
|
24
|
+
app.logger.propagate = False
|
25
|
+
ch = logging.StreamHandler()
|
26
|
+
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
27
|
+
ch.setFormatter(formatter)
|
28
|
+
app.logger.addHandler(ch)
|
24
29
|
|
25
30
|
def get_injection_dict(df, plot_size = 1366):
|
26
31
|
# Create plots
|
27
32
|
cols_p = [i for i in df.columns.to_list() if 'P_' in i]
|
28
33
|
fig_0 = px.line(df[cols_p], title='Systems powers schedule after optimization results',
|
29
|
-
template='
|
34
|
+
template='presentation', width=plot_size, height=0.5*plot_size, line_shape="hv")
|
30
35
|
fig_0.update_layout(xaxis_title='Timestamp', yaxis_title='System powers (W)')
|
31
36
|
if 'SOC_opt' in df.columns.to_list():
|
32
37
|
fig_1 = px.line(df['SOC_opt'], title='Battery state of charge schedule after optimization results',
|
33
|
-
template='
|
38
|
+
template='presentation', width=plot_size, height=0.5*plot_size, line_shape="hv")
|
34
39
|
fig_1.update_layout(xaxis_title='Timestamp', yaxis_title='Battery SOC (%)')
|
35
40
|
cols_cost = [i for i in df.columns.to_list() if 'cost_' in i or 'unit_' in i]
|
36
41
|
fig_2 = px.line(df[cols_cost], title='Systems costs obtained from optimization results',
|
37
|
-
template='
|
42
|
+
template='presentation', width=plot_size, height=0.5*plot_size, line_shape="hv")
|
38
43
|
fig_2.update_layout(xaxis_title='Timestamp', yaxis_title='System costs (currency)')
|
39
44
|
# Get full path to image
|
40
45
|
image_path_0 = fig_0.to_html(full_html=False, default_width='75%')
|
@@ -61,7 +66,7 @@ def get_injection_dict(df, plot_size = 1366):
|
|
61
66
|
|
62
67
|
def get_injection_dict_forecast_model_fit(df_fit_pred, mlf):
|
63
68
|
fig = df_fit_pred.plot()
|
64
|
-
fig.layout.template = '
|
69
|
+
fig.layout.template = 'presentation'
|
65
70
|
fig.update_yaxes(title_text = mlf.model_type)
|
66
71
|
fig.update_xaxes(title_text = "Time")
|
67
72
|
image_path_0 = fig.to_html(full_html=False, default_width='75%')
|
@@ -73,6 +78,20 @@ def get_injection_dict_forecast_model_fit(df_fit_pred, mlf):
|
|
73
78
|
injection_dict['figure_0'] = image_path_0
|
74
79
|
return injection_dict
|
75
80
|
|
81
|
+
def get_injection_dict_forecast_model_tune(df_pred_optim, mlf):
|
82
|
+
fig = df_pred_optim.plot()
|
83
|
+
fig.layout.template = 'presentation'
|
84
|
+
fig.update_yaxes(title_text = mlf.model_type)
|
85
|
+
fig.update_xaxes(title_text = "Time")
|
86
|
+
image_path_0 = fig.to_html(full_html=False, default_width='75%')
|
87
|
+
# The dict of plots
|
88
|
+
injection_dict = {}
|
89
|
+
injection_dict['title'] = '<h2>Custom machine learning forecast model tune</h2>'
|
90
|
+
injection_dict['subsubtitle0'] = '<h4>Performed a tuning routine using bayesian optimization for '+mlf.model_type+'</h4>'
|
91
|
+
injection_dict['subsubtitle0'] = '<h4>Forecasting variable '+mlf.var_model+'</h4>'
|
92
|
+
injection_dict['figure_0'] = image_path_0
|
93
|
+
return injection_dict
|
94
|
+
|
76
95
|
def build_params(params, options, addon):
|
77
96
|
if addon == 1:
|
78
97
|
# Updating variables in retrieve_hass_conf
|
@@ -90,6 +109,7 @@ def build_params(params, options, addon):
|
|
90
109
|
params['optim_conf'][4]['def_total_hours'] = [i['operating_hours_of_each_deferrable_load'] for i in options['list_operating_hours_of_each_deferrable_load']]
|
91
110
|
params['optim_conf'][5]['treat_def_as_semi_cont'] = [i['treat_deferrable_load_as_semi_cont'] for i in options['list_treat_deferrable_load_as_semi_cont']]
|
92
111
|
params['optim_conf'][6]['set_def_constant'] = [False for i in range(len(params['optim_conf'][3]['P_deferrable_nom']))]
|
112
|
+
params['optim_conf'][8]['load_forecast_method'] = options['load_forecast_method']
|
93
113
|
start_hours_list = [i['peak_hours_periods_start_hours'] for i in options['list_peak_hours_periods_start_hours']]
|
94
114
|
end_hours_list = [i['peak_hours_periods_end_hours'] for i in options['list_peak_hours_periods_end_hours']]
|
95
115
|
num_peak_hours = len(start_hours_list)
|
@@ -201,12 +221,9 @@ def action_call(action_name):
|
|
201
221
|
return make_response(msg, 201)
|
202
222
|
elif action_name == 'forecast-model-tune':
|
203
223
|
app.logger.info(" >> Performing a machine learning forecast model tune...")
|
204
|
-
df_pred_optim = forecast_model_tune(input_data_dict, app.logger)
|
205
|
-
|
206
|
-
|
207
|
-
injection_dict['title'] = '<h2>Custom machine learning forecast model tuning</h2>'
|
208
|
-
injection_dict['subsubtitle0'] = '<h4>Performed a tuning routine using bayesian optimization</h4>'
|
209
|
-
injection_dict['table1'] = table1
|
224
|
+
df_pred_optim, mlf = forecast_model_tune(input_data_dict, app.logger)
|
225
|
+
injection_dict = get_injection_dict_forecast_model_tune(
|
226
|
+
df_pred_optim, mlf)
|
210
227
|
with open(str(data_path / 'injection_dict.pkl'), "wb") as fid:
|
211
228
|
pickle.dump(injection_dict, fid)
|
212
229
|
msg = f'EMHASS >> Action forecast-model-tune executed... \n'
|
@@ -0,0 +1,15 @@
|
|
1
|
+
emhass/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
+
emhass/command_line.py,sha256=IbHexJGwDnqDVvRN1V07QXmE5sm1XtO8oHhBjp87Fi4,33594
|
3
|
+
emhass/forecast.py,sha256=FGpqMsomnwhcB3iJBV6feeFdRGlwN64qB9nZBvpliAE,42845
|
4
|
+
emhass/machine_learning_forecaster.py,sha256=FaWZv8aMS8ihx1Z6RhY6yuNkbkouZV8CujXAMmcFnAI,14966
|
5
|
+
emhass/optimization.py,sha256=QL9LpOhhpo_YgmF3_lvXWPGdz-ZeH62_zUCwm2swlyM,30582
|
6
|
+
emhass/retrieve_hass.py,sha256=lsLSiWB2XC1TTlAw_GR7YWjVXti4ZXKhICROST8UlTw,15888
|
7
|
+
emhass/utils.py,sha256=_EuITuTur7RwI3_oBRWEmEQk1F_Ke1wZ4pOSp57VRC4,22445
|
8
|
+
emhass/web_server.py,sha256=wQT0HD8N86zC2V28L4zVUqVfP6sj0U-ZmltoUc51rXs,18255
|
9
|
+
emhass/static/style.css,sha256=5qGJl0MZGSaSvr0HUcGQ9UgMtDKP2CiyE-1H-jbsLuU,6760
|
10
|
+
emhass/templates/index.html,sha256=1l0V3hrK-BvTmtRt4YN-3Wqvi-BrkT5oakMgWF2tQEA,5602
|
11
|
+
emhass-0.4.5.dist-info/METADATA,sha256=6bxTtY3oC4I7RTRrFagmLF9e_bYYhEDe8C7ijmlBkpg,24995
|
12
|
+
emhass-0.4.5.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
|
13
|
+
emhass-0.4.5.dist-info/entry_points.txt,sha256=tJULCm7mHGYb_IxyzPN_4KFYvhxv209_jq68jPiByy0,53
|
14
|
+
emhass-0.4.5.dist-info/top_level.txt,sha256=L7fIX4awfmxQbAePtSdVg2e6x_HhghfReHfsKSpKr9I,7
|
15
|
+
emhass-0.4.5.dist-info/RECORD,,
|
emhass-0.4.3.dist-info/RECORD
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
emhass/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
emhass/command_line.py,sha256=N32ULIn7McmwnNITdVNwz_jR4mIVwDHopOBn81mZm-s,33553
|
3
|
-
emhass/forecast.py,sha256=FGpqMsomnwhcB3iJBV6feeFdRGlwN64qB9nZBvpliAE,42845
|
4
|
-
emhass/machine_learning_forecaster.py,sha256=FaWZv8aMS8ihx1Z6RhY6yuNkbkouZV8CujXAMmcFnAI,14966
|
5
|
-
emhass/optimization.py,sha256=QL9LpOhhpo_YgmF3_lvXWPGdz-ZeH62_zUCwm2swlyM,30582
|
6
|
-
emhass/retrieve_hass.py,sha256=lsLSiWB2XC1TTlAw_GR7YWjVXti4ZXKhICROST8UlTw,15888
|
7
|
-
emhass/utils.py,sha256=ZLMTjNumyRfSY3Wjk3TQ1YDtCd_3hiLPnWJFyRIHE1w,22776
|
8
|
-
emhass/web_server.py,sha256=nUEKOn1OkvJA7m5wRhmlqdIZWTInckA6tzxX_CXG_dU,17505
|
9
|
-
emhass/static/style.css,sha256=5qGJl0MZGSaSvr0HUcGQ9UgMtDKP2CiyE-1H-jbsLuU,6760
|
10
|
-
emhass/templates/index.html,sha256=9iBgt1-K-WAeNUCzqyOsKDgkKaDwtz4mp2d5Q0OtABk,4099
|
11
|
-
emhass-0.4.3.dist-info/METADATA,sha256=WAgJp43KKyuIrsrmVxlsSvvOYNGaMC6JbzCNomft28U,24995
|
12
|
-
emhass-0.4.3.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
|
13
|
-
emhass-0.4.3.dist-info/entry_points.txt,sha256=tJULCm7mHGYb_IxyzPN_4KFYvhxv209_jq68jPiByy0,53
|
14
|
-
emhass-0.4.3.dist-info/top_level.txt,sha256=L7fIX4awfmxQbAePtSdVg2e6x_HhghfReHfsKSpKr9I,7
|
15
|
-
emhass-0.4.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|