emhass 0.10.5__py3-none-any.whl → 0.11.0__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 +179 -86
- emhass/data/associations.csv +61 -0
- emhass/data/config_defaults.json +117 -0
- emhass/forecast.py +38 -36
- emhass/machine_learning_forecaster.py +2 -1
- emhass/machine_learning_regressor.py +7 -2
- emhass/optimization.py +62 -62
- emhass/retrieve_hass.py +9 -4
- emhass/static/advanced.html +2 -1
- emhass/static/basic.html +4 -2
- emhass/static/configuration_list.html +44 -0
- emhass/static/configuration_script.js +871 -0
- emhass/static/data/param_definitions.json +424 -0
- emhass/static/script.js +345 -322
- emhass/static/style.css +267 -8
- emhass/templates/configuration.html +75 -0
- emhass/templates/index.html +15 -8
- emhass/utils.py +620 -303
- emhass/web_server.py +323 -213
- {emhass-0.10.5.dist-info → emhass-0.11.0.dist-info}/METADATA +207 -169
- emhass-0.11.0.dist-info/RECORD +32 -0
- {emhass-0.10.5.dist-info → emhass-0.11.0.dist-info}/WHEEL +1 -1
- emhass-0.10.5.dist-info/RECORD +0 -26
- {emhass-0.10.5.dist-info → emhass-0.11.0.dist-info}/LICENSE +0 -0
- {emhass-0.10.5.dist-info → emhass-0.11.0.dist-info}/entry_points.txt +0 -0
- {emhass-0.10.5.dist-info → emhass-0.11.0.dist-info}/top_level.txt +0 -0
emhass/optimization.py
CHANGED
@@ -66,12 +66,12 @@ class Optimization:
|
|
66
66
|
self.retrieve_hass_conf = retrieve_hass_conf
|
67
67
|
self.optim_conf = optim_conf
|
68
68
|
self.plant_conf = plant_conf
|
69
|
-
self.freq = self.retrieve_hass_conf['
|
69
|
+
self.freq = self.retrieve_hass_conf['optimization_time_step']
|
70
70
|
self.time_zone = self.retrieve_hass_conf['time_zone']
|
71
71
|
self.timeStep = self.freq.seconds/3600 # in hours
|
72
72
|
self.time_delta = pd.to_timedelta(opt_time_delta, "hours") # The period of optimization
|
73
|
-
self.var_PV = self.retrieve_hass_conf['
|
74
|
-
self.var_load = self.retrieve_hass_conf['
|
73
|
+
self.var_PV = self.retrieve_hass_conf['sensor_power_photovoltaics']
|
74
|
+
self.var_load = self.retrieve_hass_conf['sensor_power_load_no_var_loads']
|
75
75
|
self.var_load_new = self.var_load+'_positive'
|
76
76
|
self.costfun = costfun
|
77
77
|
# self.emhass_conf = emhass_conf
|
@@ -143,18 +143,18 @@ class Optimization:
|
|
143
143
|
if soc_final is not None:
|
144
144
|
soc_init = soc_final
|
145
145
|
else:
|
146
|
-
soc_init = self.plant_conf['
|
146
|
+
soc_init = self.plant_conf['battery_target_state_of_charge']
|
147
147
|
if soc_final is None:
|
148
148
|
if soc_init is not None:
|
149
149
|
soc_final = soc_init
|
150
150
|
else:
|
151
|
-
soc_final = self.plant_conf['
|
151
|
+
soc_final = self.plant_conf['battery_target_state_of_charge']
|
152
152
|
if def_total_hours is None:
|
153
|
-
def_total_hours = self.optim_conf['
|
153
|
+
def_total_hours = self.optim_conf['operating_hours_of_each_deferrable_load']
|
154
154
|
if def_start_timestep is None:
|
155
|
-
def_start_timestep = self.optim_conf['
|
155
|
+
def_start_timestep = self.optim_conf['start_timesteps_of_each_deferrable_load']
|
156
156
|
if def_end_timestep is None:
|
157
|
-
def_end_timestep = self.optim_conf['
|
157
|
+
def_end_timestep = self.optim_conf['end_timesteps_of_each_deferrable_load']
|
158
158
|
type_self_conso = 'bigm' # maxmin
|
159
159
|
|
160
160
|
#### The LP problem using Pulp ####
|
@@ -166,19 +166,19 @@ class Optimization:
|
|
166
166
|
|
167
167
|
## Add decision variables
|
168
168
|
P_grid_neg = {(i):plp.LpVariable(cat='Continuous',
|
169
|
-
lowBound=-self.plant_conf['
|
169
|
+
lowBound=-self.plant_conf['maximum_power_to_grid'], upBound=0,
|
170
170
|
name="P_grid_neg{}".format(i)) for i in set_I}
|
171
171
|
P_grid_pos = {(i):plp.LpVariable(cat='Continuous',
|
172
|
-
lowBound=0, upBound=self.plant_conf['
|
172
|
+
lowBound=0, upBound=self.plant_conf['maximum_power_from_grid'],
|
173
173
|
name="P_grid_pos{}".format(i)) for i in set_I}
|
174
174
|
P_deferrable = []
|
175
175
|
P_def_bin1 = []
|
176
|
-
for k in range(self.optim_conf['
|
177
|
-
if type(self.optim_conf['
|
178
|
-
upBound = np.max(self.optim_conf['
|
176
|
+
for k in range(self.optim_conf['number_of_deferrable_loads']):
|
177
|
+
if type(self.optim_conf['nominal_power_of_deferrable_loads'][k]) == list:
|
178
|
+
upBound = np.max(self.optim_conf['nominal_power_of_deferrable_loads'][k])
|
179
179
|
else:
|
180
|
-
upBound = self.optim_conf['
|
181
|
-
if self.optim_conf['
|
180
|
+
upBound = self.optim_conf['nominal_power_of_deferrable_loads'][k]
|
181
|
+
if self.optim_conf['treat_deferrable_load_as_semi_cont'][k]:
|
182
182
|
P_deferrable.append({(i):plp.LpVariable(cat='Continuous',
|
183
183
|
name="P_deferrable{}_{}".format(k, i)) for i in set_I})
|
184
184
|
else:
|
@@ -189,7 +189,7 @@ class Optimization:
|
|
189
189
|
name="P_def{}_bin1_{}".format(k, i)) for i in set_I})
|
190
190
|
P_def_start = []
|
191
191
|
P_def_bin2 = []
|
192
|
-
for k in range(self.optim_conf['
|
192
|
+
for k in range(self.optim_conf['number_of_deferrable_loads']):
|
193
193
|
P_def_start.append({(i):plp.LpVariable(cat='Binary',
|
194
194
|
name="P_def{}_start_{}".format(k, i)) for i in set_I})
|
195
195
|
P_def_bin2.append({(i):plp.LpVariable(cat='Binary',
|
@@ -200,10 +200,10 @@ class Optimization:
|
|
200
200
|
name="E_{}".format(i)) for i in set_I}
|
201
201
|
if self.optim_conf['set_use_battery']:
|
202
202
|
P_sto_pos = {(i):plp.LpVariable(cat='Continuous',
|
203
|
-
lowBound=0, upBound=self.plant_conf['
|
203
|
+
lowBound=0, upBound=self.plant_conf['battery_discharge_power_max'],
|
204
204
|
name="P_sto_pos_{0}".format(i)) for i in set_I}
|
205
205
|
P_sto_neg = {(i):plp.LpVariable(cat='Continuous',
|
206
|
-
lowBound=-self.plant_conf['
|
206
|
+
lowBound=-self.plant_conf['battery_charge_power_max'], upBound=0,
|
207
207
|
name="P_sto_neg_{0}".format(i)) for i in set_I}
|
208
208
|
else:
|
209
209
|
P_sto_pos = {(i):i*0 for i in set_I}
|
@@ -221,7 +221,7 @@ class Optimization:
|
|
221
221
|
## Define objective
|
222
222
|
P_def_sum= []
|
223
223
|
for i in set_I:
|
224
|
-
P_def_sum.append(plp.lpSum(P_deferrable[k][i] for k in range(self.optim_conf['
|
224
|
+
P_def_sum.append(plp.lpSum(P_deferrable[k][i] for k in range(self.optim_conf['number_of_deferrable_loads'])))
|
225
225
|
if self.costfun == 'profit':
|
226
226
|
if self.optim_conf['set_total_pv_sell']:
|
227
227
|
objective = plp.lpSum(-0.001*self.timeStep*(unit_load_cost[i]*(P_load[i] + P_def_sum[i]) + \
|
@@ -252,12 +252,12 @@ class Optimization:
|
|
252
252
|
self.optim_conf['weight_battery_charge']*P_sto_neg[i]) for i in set_I)
|
253
253
|
|
254
254
|
# Add term penalizing each startup where configured
|
255
|
-
if (
|
256
|
-
for k in range(self.optim_conf[
|
257
|
-
if (len(self.optim_conf[
|
255
|
+
if ('set_deferrable_startup_penalty' in self.optim_conf and self.optim_conf['set_deferrable_startup_penalty']):
|
256
|
+
for k in range(self.optim_conf['number_of_deferrable_loads']):
|
257
|
+
if (len(self.optim_conf['set_deferrable_startup_penalty']) > k and self.optim_conf['set_deferrable_startup_penalty'][k]):
|
258
258
|
objective = objective + plp.lpSum(
|
259
|
-
-0.001 * self.timeStep * self.optim_conf[
|
260
|
-
unit_load_cost[i] * self.optim_conf['
|
259
|
+
-0.001 * self.timeStep * self.optim_conf['set_deferrable_startup_penalty'][k] * P_def_start[k][i] *\
|
260
|
+
unit_load_cost[i] * self.optim_conf['nominal_power_of_deferrable_loads'][k]
|
261
261
|
for i in set_I)
|
262
262
|
|
263
263
|
opt_model.setObjective(objective)
|
@@ -288,24 +288,24 @@ class Optimization:
|
|
288
288
|
for i in set_I}
|
289
289
|
|
290
290
|
# Constraint for hybrid inverter and curtailment cases
|
291
|
-
if type(self.plant_conf['
|
291
|
+
if type(self.plant_conf['pv_module_model']) == list:
|
292
292
|
P_nom_inverter = 0.0
|
293
|
-
for i in range(len(self.plant_conf['
|
294
|
-
if type(self.plant_conf['
|
293
|
+
for i in range(len(self.plant_conf['pv_inverter_model'])):
|
294
|
+
if type(self.plant_conf['pv_inverter_model'][i]) == str:
|
295
295
|
cec_inverters = bz2.BZ2File(pathlib.Path(__file__).parent / 'data/cec_inverters.pbz2', "rb")
|
296
296
|
cec_inverters = cPickle.load(cec_inverters)
|
297
|
-
inverter = cec_inverters[self.plant_conf['
|
297
|
+
inverter = cec_inverters[self.plant_conf['pv_inverter_model'][i]]
|
298
298
|
P_nom_inverter += inverter.Paco
|
299
299
|
else:
|
300
|
-
P_nom_inverter += self.plant_conf['
|
300
|
+
P_nom_inverter += self.plant_conf['pv_inverter_model'][i]
|
301
301
|
else:
|
302
|
-
if type(self.plant_conf['
|
302
|
+
if type(self.plant_conf['pv_inverter_model'][i]) == str:
|
303
303
|
cec_inverters = bz2.BZ2File(pathlib.Path(__file__).parent / 'data/cec_inverters.pbz2', "rb")
|
304
304
|
cec_inverters = cPickle.load(cec_inverters)
|
305
|
-
inverter = cec_inverters[self.plant_conf['
|
305
|
+
inverter = cec_inverters[self.plant_conf['pv_inverter_model']]
|
306
306
|
P_nom_inverter = inverter.Paco
|
307
307
|
else:
|
308
|
-
P_nom_inverter = self.plant_conf['
|
308
|
+
P_nom_inverter = self.plant_conf['pv_inverter_model']
|
309
309
|
if self.plant_conf['inverter_is_hybrid']:
|
310
310
|
constraints.update({"constraint_hybrid_inverter1_{}".format(i) :
|
311
311
|
plp.LpConstraint(
|
@@ -347,26 +347,26 @@ class Optimization:
|
|
347
347
|
# Avoid injecting and consuming from grid at the same time
|
348
348
|
constraints.update({"constraint_pgridpos_{}".format(i) :
|
349
349
|
plp.LpConstraint(
|
350
|
-
e = P_grid_pos[i] - self.plant_conf['
|
350
|
+
e = P_grid_pos[i] - self.plant_conf['maximum_power_from_grid']*D[i],
|
351
351
|
sense = plp.LpConstraintLE,
|
352
352
|
rhs = 0)
|
353
353
|
for i in set_I})
|
354
354
|
constraints.update({"constraint_pgridneg_{}".format(i) :
|
355
355
|
plp.LpConstraint(
|
356
|
-
e = -P_grid_neg[i] - self.plant_conf['
|
356
|
+
e = -P_grid_neg[i] - self.plant_conf['maximum_power_to_grid']*(1-D[i]),
|
357
357
|
sense = plp.LpConstraintLE,
|
358
358
|
rhs = 0)
|
359
359
|
for i in set_I})
|
360
360
|
|
361
361
|
# Treat deferrable loads constraints
|
362
362
|
predicted_temps = {}
|
363
|
-
for k in range(self.optim_conf['
|
363
|
+
for k in range(self.optim_conf['number_of_deferrable_loads']):
|
364
364
|
|
365
|
-
if type(self.optim_conf['
|
365
|
+
if type(self.optim_conf['nominal_power_of_deferrable_loads'][k]) == list:
|
366
366
|
# Constraint for sequence of deferrable
|
367
367
|
# WARNING: This is experimental, formulation seems correct but feasibility problems.
|
368
368
|
# Probably uncomptabile with other constraints
|
369
|
-
power_sequence = self.optim_conf['
|
369
|
+
power_sequence = self.optim_conf['nominal_power_of_deferrable_loads'][k]
|
370
370
|
sequence_length = len(power_sequence)
|
371
371
|
def create_matrix(input_list, n):
|
372
372
|
matrix = []
|
@@ -421,7 +421,7 @@ class Optimization:
|
|
421
421
|
continue
|
422
422
|
predicted_temp.append(
|
423
423
|
predicted_temp[I-1]
|
424
|
-
+ (P_deferrable[k][I-1] * (heating_rate * self.timeStep / self.optim_conf['
|
424
|
+
+ (P_deferrable[k][I-1] * (heating_rate * self.timeStep / self.optim_conf['nominal_power_of_deferrable_loads'][k]))
|
425
425
|
- (cooling_constant * (predicted_temp[I-1] - outdoor_temperature_forecast[I-1])))
|
426
426
|
if len(desired_temperatures) > I and desired_temperatures[I]:
|
427
427
|
constraints.update({"constraint_defload{}_temperature_{}".format(k, I):
|
@@ -448,7 +448,7 @@ class Optimization:
|
|
448
448
|
plp.LpConstraint(
|
449
449
|
e = plp.lpSum(P_deferrable[k][i]*self.timeStep for i in set_I),
|
450
450
|
sense = plp.LpConstraintEQ,
|
451
|
-
rhs = def_total_hours[k]*self.optim_conf['
|
451
|
+
rhs = def_total_hours[k]*self.optim_conf['nominal_power_of_deferrable_loads'][k])
|
452
452
|
})
|
453
453
|
|
454
454
|
# Ensure deferrable loads consume energy between def_start_timestep & def_end_timestep
|
@@ -516,7 +516,7 @@ class Optimization:
|
|
516
516
|
for i in set_I})
|
517
517
|
|
518
518
|
# Treat deferrable as a fixed value variable with just one startup
|
519
|
-
if self.optim_conf['
|
519
|
+
if self.optim_conf['set_deferrable_load_single_constant'][k]:
|
520
520
|
# P_def_start[i] must be 1 for exactly 1 value of i
|
521
521
|
constraints.update({"constraint_pdef{}_start4".format(k) :
|
522
522
|
plp.LpConstraint(
|
@@ -533,23 +533,23 @@ class Optimization:
|
|
533
533
|
})
|
534
534
|
|
535
535
|
# Treat deferrable load as a semi-continuous variable
|
536
|
-
if self.optim_conf['
|
536
|
+
if self.optim_conf['treat_deferrable_load_as_semi_cont'][k]:
|
537
537
|
constraints.update({"constraint_pdef{}_semicont1_{}".format(k, i) :
|
538
538
|
plp.LpConstraint(
|
539
|
-
e=P_deferrable[k][i] - self.optim_conf['
|
539
|
+
e=P_deferrable[k][i] - self.optim_conf['nominal_power_of_deferrable_loads'][k]*P_def_bin1[k][i],
|
540
540
|
sense=plp.LpConstraintGE,
|
541
541
|
rhs=0)
|
542
542
|
for i in set_I})
|
543
543
|
constraints.update({"constraint_pdef{}_semicont2_{}".format(k, i) :
|
544
544
|
plp.LpConstraint(
|
545
|
-
e=P_deferrable[k][i] - self.optim_conf['
|
545
|
+
e=P_deferrable[k][i] - self.optim_conf['nominal_power_of_deferrable_loads'][k]*P_def_bin1[k][i],
|
546
546
|
sense=plp.LpConstraintLE,
|
547
547
|
rhs=0)
|
548
548
|
for i in set_I})
|
549
549
|
|
550
550
|
|
551
551
|
# Treat the number of starts for a deferrable load (old method, kept here just in case)
|
552
|
-
# if self.optim_conf['
|
552
|
+
# if self.optim_conf['set_deferrable_load_single_constant'][k]:
|
553
553
|
# constraints.update({"constraint_pdef{}_start1_{}".format(k, i) :
|
554
554
|
# plp.LpConstraint(
|
555
555
|
# e=P_deferrable[k][i] - P_def_bin2[k][i]*M,
|
@@ -592,53 +592,53 @@ class Optimization:
|
|
592
592
|
constraints.update({"constraint_pos_batt_dynamic_max_{}".format(i) :
|
593
593
|
plp.LpConstraint(e = P_sto_pos[i+1] - P_sto_pos[i],
|
594
594
|
sense = plp.LpConstraintLE,
|
595
|
-
rhs = self.timeStep*self.optim_conf['battery_dynamic_max']*self.plant_conf['
|
595
|
+
rhs = self.timeStep*self.optim_conf['battery_dynamic_max']*self.plant_conf['battery_discharge_power_max'])
|
596
596
|
for i in range(n-1)})
|
597
597
|
constraints.update({"constraint_pos_batt_dynamic_min_{}".format(i) :
|
598
598
|
plp.LpConstraint(e = P_sto_pos[i+1] - P_sto_pos[i],
|
599
599
|
sense = plp.LpConstraintGE,
|
600
|
-
rhs = self.timeStep*self.optim_conf['battery_dynamic_min']*self.plant_conf['
|
600
|
+
rhs = self.timeStep*self.optim_conf['battery_dynamic_min']*self.plant_conf['battery_discharge_power_max'])
|
601
601
|
for i in range(n-1)})
|
602
602
|
constraints.update({"constraint_neg_batt_dynamic_max_{}".format(i) :
|
603
603
|
plp.LpConstraint(e = P_sto_neg[i+1] - P_sto_neg[i],
|
604
604
|
sense = plp.LpConstraintLE,
|
605
|
-
rhs = self.timeStep*self.optim_conf['battery_dynamic_max']*self.plant_conf['
|
605
|
+
rhs = self.timeStep*self.optim_conf['battery_dynamic_max']*self.plant_conf['battery_charge_power_max'])
|
606
606
|
for i in range(n-1)})
|
607
607
|
constraints.update({"constraint_neg_batt_dynamic_min_{}".format(i) :
|
608
608
|
plp.LpConstraint(e = P_sto_neg[i+1] - P_sto_neg[i],
|
609
609
|
sense = plp.LpConstraintGE,
|
610
|
-
rhs = self.timeStep*self.optim_conf['battery_dynamic_min']*self.plant_conf['
|
610
|
+
rhs = self.timeStep*self.optim_conf['battery_dynamic_min']*self.plant_conf['battery_charge_power_max'])
|
611
611
|
for i in range(n-1)})
|
612
612
|
# Then the classic battery constraints
|
613
613
|
constraints.update({"constraint_pstopos_{}".format(i) :
|
614
614
|
plp.LpConstraint(
|
615
|
-
e=P_sto_pos[i] - self.plant_conf['
|
615
|
+
e=P_sto_pos[i] - self.plant_conf['battery_discharge_efficiency']*self.plant_conf['battery_discharge_power_max']*E[i],
|
616
616
|
sense=plp.LpConstraintLE,
|
617
617
|
rhs=0)
|
618
618
|
for i in set_I})
|
619
619
|
constraints.update({"constraint_pstoneg_{}".format(i) :
|
620
620
|
plp.LpConstraint(
|
621
|
-
e=-P_sto_neg[i] - (1/self.plant_conf['
|
621
|
+
e=-P_sto_neg[i] - (1/self.plant_conf['battery_charge_efficiency'])*self.plant_conf['battery_charge_power_max']*(1-E[i]),
|
622
622
|
sense=plp.LpConstraintLE,
|
623
623
|
rhs=0)
|
624
624
|
for i in set_I})
|
625
625
|
constraints.update({"constraint_socmax_{}".format(i) :
|
626
626
|
plp.LpConstraint(
|
627
|
-
e=-plp.lpSum(P_sto_pos[j]*(1/self.plant_conf['
|
627
|
+
e=-plp.lpSum(P_sto_pos[j]*(1/self.plant_conf['battery_discharge_efficiency']) + self.plant_conf['battery_charge_efficiency']*P_sto_neg[j] for j in range(i)),
|
628
628
|
sense=plp.LpConstraintLE,
|
629
|
-
rhs=(self.plant_conf['
|
629
|
+
rhs=(self.plant_conf['battery_nominal_energy_capacity']/self.timeStep)*(self.plant_conf['battery_maximum_state_of_charge'] - soc_init))
|
630
630
|
for i in set_I})
|
631
631
|
constraints.update({"constraint_socmin_{}".format(i) :
|
632
632
|
plp.LpConstraint(
|
633
|
-
e=plp.lpSum(P_sto_pos[j]*(1/self.plant_conf['
|
633
|
+
e=plp.lpSum(P_sto_pos[j]*(1/self.plant_conf['battery_discharge_efficiency']) + self.plant_conf['battery_charge_efficiency']*P_sto_neg[j] for j in range(i)),
|
634
634
|
sense=plp.LpConstraintLE,
|
635
|
-
rhs=(self.plant_conf['
|
635
|
+
rhs=(self.plant_conf['battery_nominal_energy_capacity']/self.timeStep)*(soc_init - self.plant_conf['battery_minimum_state_of_charge']))
|
636
636
|
for i in set_I})
|
637
637
|
constraints.update({"constraint_socfinal_{}".format(0) :
|
638
638
|
plp.LpConstraint(
|
639
|
-
e=plp.lpSum(P_sto_pos[i]*(1/self.plant_conf['
|
639
|
+
e=plp.lpSum(P_sto_pos[i]*(1/self.plant_conf['battery_discharge_efficiency']) + self.plant_conf['battery_charge_efficiency']*P_sto_neg[i] for i in set_I),
|
640
640
|
sense=plp.LpConstraintEQ,
|
641
|
-
rhs=(soc_init - soc_final)*self.plant_conf['
|
641
|
+
rhs=(soc_init - soc_final)*self.plant_conf['battery_nominal_energy_capacity']/self.timeStep)
|
642
642
|
})
|
643
643
|
opt_model.constraints = constraints
|
644
644
|
|
@@ -667,16 +667,16 @@ class Optimization:
|
|
667
667
|
opt_tp = pd.DataFrame()
|
668
668
|
opt_tp["P_PV"] = [P_PV[i] for i in set_I]
|
669
669
|
opt_tp["P_Load"] = [P_load[i] for i in set_I]
|
670
|
-
for k in range(self.optim_conf['
|
670
|
+
for k in range(self.optim_conf['number_of_deferrable_loads']):
|
671
671
|
opt_tp["P_deferrable{}".format(k)] = [P_deferrable[k][i].varValue for i in set_I]
|
672
672
|
opt_tp["P_grid_pos"] = [P_grid_pos[i].varValue for i in set_I]
|
673
673
|
opt_tp["P_grid_neg"] = [P_grid_neg[i].varValue for i in set_I]
|
674
674
|
opt_tp["P_grid"] = [P_grid_pos[i].varValue + P_grid_neg[i].varValue for i in set_I]
|
675
675
|
if self.optim_conf['set_use_battery']:
|
676
676
|
opt_tp["P_batt"] = [P_sto_pos[i].varValue + P_sto_neg[i].varValue for i in set_I]
|
677
|
-
SOC_opt_delta = [(P_sto_pos[i].varValue*(1/self.plant_conf['
|
678
|
-
self.plant_conf['
|
679
|
-
self.timeStep/(self.plant_conf['
|
677
|
+
SOC_opt_delta = [(P_sto_pos[i].varValue*(1/self.plant_conf['battery_discharge_efficiency']) + \
|
678
|
+
self.plant_conf['battery_charge_efficiency']*P_sto_neg[i].varValue)*(
|
679
|
+
self.timeStep/(self.plant_conf['battery_nominal_energy_capacity'])) for i in set_I]
|
680
680
|
SOCinit = copy.copy(soc_init)
|
681
681
|
SOC_opt = []
|
682
682
|
for i in set_I:
|
@@ -692,7 +692,7 @@ class Optimization:
|
|
692
692
|
# Lets compute the optimal cost function
|
693
693
|
P_def_sum_tp = []
|
694
694
|
for i in set_I:
|
695
|
-
P_def_sum_tp.append(sum(P_deferrable[k][i].varValue for k in range(self.optim_conf['
|
695
|
+
P_def_sum_tp.append(sum(P_deferrable[k][i].varValue for k in range(self.optim_conf['number_of_deferrable_loads'])))
|
696
696
|
opt_tp["unit_load_cost"] = [unit_load_cost[i] for i in set_I]
|
697
697
|
opt_tp["unit_prod_price"] = [unit_prod_price[i] for i in set_I]
|
698
698
|
if self.optim_conf['set_total_pv_sell']:
|
@@ -728,7 +728,7 @@ class Optimization:
|
|
728
728
|
|
729
729
|
# Debug variables
|
730
730
|
if debug:
|
731
|
-
for k in range(self.optim_conf[
|
731
|
+
for k in range(self.optim_conf['number_of_deferrable_loads']):
|
732
732
|
opt_tp[f"P_def_start_{k}"] = [P_def_start[k][i].varValue for i in set_I]
|
733
733
|
opt_tp[f"P_def_bin2_{k}"] = [P_def_bin2[k][i].varValue for i in set_I]
|
734
734
|
for i, predicted_temp in predicted_temps.items():
|
emhass/retrieve_hass.py
CHANGED
@@ -62,7 +62,12 @@ class RetrieveHass:
|
|
62
62
|
self.long_lived_token = long_lived_token
|
63
63
|
self.freq = freq
|
64
64
|
self.time_zone = time_zone
|
65
|
-
|
65
|
+
if (params == None) or (params == "null"):
|
66
|
+
self.params = {}
|
67
|
+
elif type(params) is dict:
|
68
|
+
self.params = params
|
69
|
+
else:
|
70
|
+
self.params = json.loads(params)
|
66
71
|
self.emhass_conf = emhass_conf
|
67
72
|
self.logger = logger
|
68
73
|
self.get_data_from_file = get_data_from_file
|
@@ -450,11 +455,11 @@ class RetrieveHass:
|
|
450
455
|
metadata = {}
|
451
456
|
with open(entities_path / "metadata.json", "w") as file:
|
452
457
|
# Save entity metadata, key = entity_id
|
453
|
-
metadata[entity_id] = {'name': data_df.name, 'unit_of_measurement': unit_of_measurement,'friendly_name': friendly_name,'type_var': type_var, '
|
458
|
+
metadata[entity_id] = {'name': data_df.name, 'unit_of_measurement': unit_of_measurement,'friendly_name': friendly_name,'type_var': type_var, 'optimization_time_step': int(self.freq.seconds / 60)}
|
454
459
|
|
455
460
|
# Find lowest frequency to set for continual loop freq
|
456
|
-
if metadata.get("
|
457
|
-
metadata["
|
461
|
+
if metadata.get("lowest_time_step",None) == None or metadata["lowest_time_step"] > int(self.freq.seconds / 60):
|
462
|
+
metadata["lowest_time_step"] = int(self.freq.seconds / 60)
|
458
463
|
json.dump(metadata,file, indent=4)
|
459
464
|
|
460
465
|
self.logger.debug("Saved " + entity_id + " to json file")
|
emhass/static/advanced.html
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
<!-- advance div, dynamically appended inside of index.html -->
|
1
2
|
<!-- action button elements section -->
|
2
3
|
<div class="loading-div" id="advance">
|
3
4
|
<h4>Use the buttons below to manually launch different optimization tasks</h4>
|
@@ -18,7 +19,7 @@
|
|
18
19
|
<button type="button" id="regressor-model-fit" class="button button1">ML regressor model fit</button>
|
19
20
|
<button type="button" id="regressor-model-predict" class="button button2">ML regressor model predict</button>
|
20
21
|
<!-- -->
|
21
|
-
<!--dynamic input elements section -->
|
22
|
+
<!--dynamic runtime parameter input (list and box) elements section -->
|
22
23
|
<h4>Input Runtime Parameters</h4>
|
23
24
|
<div class="input-button-container">
|
24
25
|
<div class="input-buttons">
|
emhass/static/basic.html
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
<!-- basic div, dynamically appended inside of index.html -->
|
1
2
|
<!-- action button elements section -->
|
2
3
|
<div class="loading-div" id="basic">
|
3
4
|
<h4>Use the button below to manually launch optimization task</h4>
|
@@ -7,6 +8,7 @@
|
|
7
8
|
<div class="info">
|
8
9
|
<p>The day-ahead optimization button will run once, based on the values entered into the configuration page.
|
9
10
|
</br>
|
10
|
-
After a few seconds, the charts and table below should be updated to reflect the optimization plan for the next
|
11
|
+
After a few seconds, the charts and table below should be updated to reflect the optimization plan for the next
|
12
|
+
24 hours.
|
11
13
|
</p>
|
12
|
-
</div>
|
14
|
+
</div>
|
@@ -0,0 +1,44 @@
|
|
1
|
+
<!-- configuration list dynamically appended inside of configuration.html -->
|
2
|
+
<!-- configuration list view parameter sections -->
|
3
|
+
<div id="Local" class="section-card">
|
4
|
+
<div class="section-card-header">
|
5
|
+
<h4>Local</h4>
|
6
|
+
</div>
|
7
|
+
<div class="section-body"> </div> <!-- parameters will get generated here -->
|
8
|
+
</div>
|
9
|
+
<div id="System" class="section-card">
|
10
|
+
<div class="section-card-header">
|
11
|
+
<h4>System</h4>
|
12
|
+
</div>
|
13
|
+
<div class="section-body"> </div> <!-- parameters will get generated here -->
|
14
|
+
</div>
|
15
|
+
<div id="Tariff" class="section-card">
|
16
|
+
<div class="section-card-header">
|
17
|
+
<h4>Tariff</h4>
|
18
|
+
</div>
|
19
|
+
<div class="section-body"> </div> <!-- parameters will get generated here -->
|
20
|
+
</div>
|
21
|
+
<div id="Deferrable Loads" class="section-card">
|
22
|
+
<div class="section-card-header">
|
23
|
+
<h4>Deferrable Loads</h4>
|
24
|
+
<input id="number_of_deferrable_loads" min="1" type="number">
|
25
|
+
</label>
|
26
|
+
</div>
|
27
|
+
<div class="section-body"> </div> <!-- parameters will get generated here -->
|
28
|
+
</div>
|
29
|
+
<div id="Solar System (PV)" class="section-card">
|
30
|
+
<div class="section-card-header">
|
31
|
+
<h4>Solar System (PV)</h4>
|
32
|
+
</div>
|
33
|
+
<div class="section-body"> </div> <!-- parameters will get generated here -->
|
34
|
+
</div>
|
35
|
+
<div id="Battery" class="section-card">
|
36
|
+
<div class="section-card-header">
|
37
|
+
<h4>Battery</h4>
|
38
|
+
<label class="switch"> <!-- switch connected to set_use_battery -->
|
39
|
+
<input id="set_use_battery" type="checkbox">
|
40
|
+
<span class="slider"></span>
|
41
|
+
</label>
|
42
|
+
</div>
|
43
|
+
<div class="section-body"> </div> <!-- parameters will get generated here -->
|
44
|
+
</div>
|