1
|
|
|
import time |
2
|
|
|
from datetime import datetime, timedelta |
3
|
|
|
import mysql.connector |
4
|
|
|
from sympy import sympify |
5
|
|
|
from multiprocessing import Pool |
6
|
|
|
import random |
7
|
|
|
import config |
8
|
|
|
|
9
|
|
|
|
10
|
|
|
######################################################################################################################## |
11
|
|
|
# PROCEDURES: |
12
|
|
|
# Step 1: Query all virtual meters |
13
|
|
|
# Step 2: Create multiprocessing pool to call worker in parallel |
14
|
|
|
######################################################################################################################## |
15
|
|
|
|
16
|
|
|
def calculate_hourly(logger): |
17
|
|
|
|
18
|
|
|
while True: |
19
|
|
|
# outer loop to reconnect server if there is a connection error |
20
|
|
|
cnx_system_db = None |
21
|
|
|
cursor_system_db = None |
22
|
|
|
try: |
23
|
|
|
cnx_system_db = mysql.connector.connect(**config.myems_system_db) |
24
|
|
|
cursor_system_db = cnx_system_db.cursor() |
25
|
|
|
except Exception as e: |
26
|
|
|
logger.error("Error in step 0 of virtual_meter.calculate_hourly " + str(e)) |
27
|
|
|
if cursor_system_db: |
28
|
|
|
cursor_system_db.close() |
29
|
|
|
if cnx_system_db: |
30
|
|
|
cnx_system_db.close() |
31
|
|
|
# sleep and continue the outer loop to reconnect the database |
32
|
|
|
time.sleep(60) |
33
|
|
|
continue |
34
|
|
|
|
35
|
|
|
print("Connected to MyEMS System Database") |
36
|
|
|
|
37
|
|
|
virtual_meter_list = list() |
38
|
|
|
try: |
39
|
|
|
cursor_system_db.execute(" SELECT m.id, m.name, e.equation, e.id as expression_id " |
40
|
|
|
" FROM tbl_virtual_meters m, tbl_expressions e " |
41
|
|
|
" WHERE m.id = e.virtual_meter_id " |
42
|
|
|
" ORDER BY m.id ") |
43
|
|
|
rows_virtual_meters = cursor_system_db.fetchall() |
44
|
|
|
|
45
|
|
|
if rows_virtual_meters is None or len(rows_virtual_meters) == 0: |
46
|
|
|
# sleep several minutes and continue the outer loop to reconnect the database |
47
|
|
|
time.sleep(60) |
48
|
|
|
continue |
49
|
|
|
|
50
|
|
|
for row in rows_virtual_meters: |
51
|
|
|
meta_result = {"id": row[0], "name": row[1], "equation": row[2], "expression_id": row[3]} |
52
|
|
|
virtual_meter_list.append(meta_result) |
53
|
|
|
|
54
|
|
|
except Exception as e: |
55
|
|
|
logger.error("Error in step 1 of virtual meter calculate hourly " + str(e)) |
56
|
|
|
# sleep and continue the outer loop to reconnect the database |
57
|
|
|
time.sleep(60) |
58
|
|
|
continue |
59
|
|
|
finally: |
60
|
|
|
if cursor_system_db: |
61
|
|
|
cursor_system_db.close() |
62
|
|
|
if cnx_system_db: |
63
|
|
|
cnx_system_db.close() |
64
|
|
|
|
65
|
|
|
# shuffle the virtual meter list for randomly calculating the meter hourly value |
66
|
|
|
random.shuffle(virtual_meter_list) |
67
|
|
|
|
68
|
|
|
print("Got all virtual meters in MyEMS System Database") |
69
|
|
|
################################################################################################################ |
70
|
|
|
# Step 2: Create multiprocessing pool to call worker in parallel |
71
|
|
|
################################################################################################################ |
72
|
|
|
p = Pool(processes=config.pool_size) |
73
|
|
|
error_list = p.map(worker, virtual_meter_list) |
74
|
|
|
p.close() |
75
|
|
|
p.join() |
76
|
|
|
|
77
|
|
|
for error in error_list: |
78
|
|
|
if error is not None and len(error) > 0: |
79
|
|
|
logger.error(error) |
80
|
|
|
|
81
|
|
|
print("go to sleep ...") |
82
|
|
|
time.sleep(60) |
83
|
|
|
print("wake from sleep, and continue to work...") |
84
|
|
|
|
85
|
|
|
|
86
|
|
|
######################################################################################################################## |
87
|
|
|
# Step 1: get start datetime and end datetime |
88
|
|
|
# Step 2: parse the expression and get all meters, virtual meters, offline meters associated with the expression |
89
|
|
|
# Step 3: query energy consumption values from table meter hourly, virtual meter hourly and offline meter hourly |
90
|
|
|
# Step 4: evaluate the equation with variables values from previous step and save to table virtual meter hourly |
91
|
|
|
# returns the error string for logging or returns None |
92
|
|
|
######################################################################################################################## |
93
|
|
|
|
94
|
|
|
def worker(virtual_meter): |
95
|
|
|
cnx_energy_db = None |
96
|
|
|
cursor_energy_db = None |
97
|
|
|
|
98
|
|
|
try: |
99
|
|
|
cnx_energy_db = mysql.connector.connect(**config.myems_energy_db) |
100
|
|
|
cursor_energy_db = cnx_energy_db.cursor() |
101
|
|
|
except Exception as e: |
102
|
|
|
if cursor_energy_db: |
103
|
|
|
cursor_energy_db.close() |
104
|
|
|
if cnx_energy_db: |
105
|
|
|
cnx_energy_db.close() |
106
|
|
|
return "Error in step 1.1 of virtual meter worker " + str(e) + " for '" + virtual_meter['name'] + "'" |
107
|
|
|
|
108
|
|
|
print("Start to process virtual meter: " + "'" + virtual_meter['name']+"'") |
109
|
|
|
|
110
|
|
|
#################################################################################################################### |
111
|
|
|
# step 1: get start datetime and end datetime |
112
|
|
|
# get latest timestamp from energy database in tbl_virtual_meter_hourly |
113
|
|
|
#################################################################################################################### |
114
|
|
|
|
115
|
|
|
try: |
116
|
|
|
query = (" SELECT MAX(start_datetime_utc) " |
117
|
|
|
" FROM tbl_virtual_meter_hourly " |
118
|
|
|
" WHERE virtual_meter_id = %s ") |
119
|
|
|
cursor_energy_db.execute(query, (virtual_meter['id'],)) |
120
|
|
|
row_datetime = cursor_energy_db.fetchone() |
121
|
|
|
except Exception as e: |
122
|
|
|
if cursor_energy_db: |
123
|
|
|
cursor_energy_db.close() |
124
|
|
|
if cnx_energy_db: |
125
|
|
|
cnx_energy_db.close() |
126
|
|
|
return "Error in step 1.2 of virtual meter worker " + str(e) + " for '" + virtual_meter['name'] + "'" |
127
|
|
|
|
128
|
|
|
start_datetime_utc = datetime.strptime(config.start_datetime_utc, '%Y-%m-%d %H:%M:%S') |
129
|
|
|
start_datetime_utc = start_datetime_utc.replace(minute=0, second=0, microsecond=0, tzinfo=None) |
130
|
|
|
|
131
|
|
|
if row_datetime is not None and len(row_datetime) > 0 and isinstance(row_datetime[0], datetime): |
132
|
|
|
# replace second and microsecond with 0 |
133
|
|
|
# note: do not replace minute in case of calculating in half hourly |
134
|
|
|
start_datetime_utc = row_datetime[0].replace(second=0, microsecond=0, tzinfo=None) |
135
|
|
|
# start from the next time slot |
136
|
|
|
start_datetime_utc += timedelta(minutes=config.minutes_to_count) |
137
|
|
|
|
138
|
|
|
end_datetime_utc = datetime.utcnow().replace() |
139
|
|
|
end_datetime_utc = end_datetime_utc.replace(second=0, microsecond=0, tzinfo=None) |
140
|
|
|
|
141
|
|
|
time_difference = end_datetime_utc - start_datetime_utc |
142
|
|
|
time_difference_in_minutes = time_difference / timedelta(minutes=1) |
143
|
|
|
if time_difference_in_minutes < config.minutes_to_count: |
144
|
|
|
if cursor_energy_db: |
145
|
|
|
cursor_energy_db.close() |
146
|
|
|
if cnx_energy_db: |
147
|
|
|
cnx_energy_db.close() |
148
|
|
|
return "it's too early to calculate" + " for '" + virtual_meter['name'] + "'" |
149
|
|
|
|
150
|
|
|
# trim end_datetime_utc |
151
|
|
|
trimmed_end_datetime_utc = start_datetime_utc + timedelta(minutes=config.minutes_to_count) |
152
|
|
|
while trimmed_end_datetime_utc <= end_datetime_utc: |
153
|
|
|
trimmed_end_datetime_utc += timedelta(minutes=config.minutes_to_count) |
154
|
|
|
|
155
|
|
|
end_datetime_utc = trimmed_end_datetime_utc - timedelta(minutes=config.minutes_to_count) |
156
|
|
|
|
157
|
|
|
if end_datetime_utc <= start_datetime_utc: |
158
|
|
|
if cursor_energy_db: |
159
|
|
|
cursor_energy_db.close() |
160
|
|
|
if cnx_energy_db: |
161
|
|
|
cnx_energy_db.close() |
162
|
|
|
return "it's too early to calculate" + " for '" + virtual_meter['name'] + "'" |
163
|
|
|
|
164
|
|
|
print("start_datetime_utc: " + start_datetime_utc.isoformat()[0:19] |
165
|
|
|
+ "end_datetime_utc: " + end_datetime_utc.isoformat()[0:19]) |
166
|
|
|
|
167
|
|
|
############################################################################################################ |
168
|
|
|
# Step 2: parse the expression and get all meters, virtual meters, and |
169
|
|
|
# offline meters associated with the expression |
170
|
|
|
############################################################################################################ |
171
|
|
|
cnx_factory_db = None |
172
|
|
|
cursor_factory_db = None |
173
|
|
|
try: |
174
|
|
|
cnx_factory_db = mysql.connector.connect(**config.myems_system_db) |
175
|
|
|
cursor_factory_db = cnx_factory_db.cursor() |
176
|
|
|
except Exception as e: |
177
|
|
|
if cursor_factory_db: |
178
|
|
|
cursor_factory_db.close() |
179
|
|
|
if cnx_factory_db: |
180
|
|
|
cnx_factory_db.close() |
181
|
|
|
if cursor_energy_db: |
182
|
|
|
cursor_energy_db.close() |
183
|
|
|
if cnx_energy_db: |
184
|
|
|
cnx_energy_db.close() |
185
|
|
|
return "Error in step 2.1 of virtual meter worker " + str(e) + " for '" + virtual_meter['name'] + "'" |
186
|
|
|
|
187
|
|
|
meter_list_in_expression = list() |
188
|
|
|
virtual_meter_list_in_expression = list() |
189
|
|
|
offline_meter_list_in_expression = list() |
190
|
|
|
try: |
191
|
|
|
######################################################################################################## |
192
|
|
|
# get all meters associated with the expression |
193
|
|
|
######################################################################################################## |
194
|
|
|
|
195
|
|
|
cursor_factory_db.execute(" SELECT m.id as meter_id, v.name as variable_name " |
196
|
|
|
" FROM tbl_meters m, tbl_variables v " |
197
|
|
|
" WHERE m.id = v.meter_id " |
198
|
|
|
" AND v.meter_type = 'meter' " |
199
|
|
|
" AND v.expression_id = %s ", |
200
|
|
|
(virtual_meter['expression_id'], )) |
201
|
|
|
rows = cursor_factory_db.fetchall() |
202
|
|
|
if rows is not None and len(rows) > 0: |
203
|
|
|
for row in rows: |
204
|
|
|
meter_list_in_expression.append({"meter_id": row[0], "variable_name": row[1].lower()}) |
205
|
|
|
|
206
|
|
|
######################################################################################################## |
207
|
|
|
# get all virtual meters associated with the expression |
208
|
|
|
######################################################################################################## |
209
|
|
|
|
210
|
|
|
cursor_factory_db.execute(" SELECT m.id as virtual_meter_id, v.name as variable_name " |
211
|
|
|
" FROM tbl_virtual_meters m, tbl_variables v " |
212
|
|
|
" WHERE m.id = v.meter_id " |
213
|
|
|
" AND v.meter_type = 'virtual_meter' " |
214
|
|
|
" AND v.expression_id = %s ", |
215
|
|
|
(virtual_meter['expression_id'],)) |
216
|
|
|
rows = cursor_factory_db.fetchall() |
217
|
|
|
if rows is not None and len(rows) > 0: |
218
|
|
|
for row in rows: |
219
|
|
|
virtual_meter_list_in_expression.append({"virtual_meter_id": row[0], |
220
|
|
|
"variable_name": row[1].lower()}) |
221
|
|
|
|
222
|
|
|
######################################################################################################## |
223
|
|
|
# get all offline meters associated with the expression |
224
|
|
|
######################################################################################################## |
225
|
|
|
|
226
|
|
|
cursor_factory_db.execute(" SELECT m.id as offline_meter_id, v.name as variable_name " |
227
|
|
|
" FROM tbl_offline_meters m, tbl_variables v " |
228
|
|
|
" WHERE m.id = v.meter_id " |
229
|
|
|
" AND v.meter_type = 'offline_meter' " |
230
|
|
|
" AND v.expression_id = %s ", |
231
|
|
|
(virtual_meter['expression_id'],)) |
232
|
|
|
rows = cursor_factory_db.fetchall() |
233
|
|
|
if rows is not None and len(rows) > 0: |
234
|
|
|
for row in rows: |
235
|
|
|
offline_meter_list_in_expression.append({"offline_meter_id": row[0], |
236
|
|
|
"variable_name": row[1].lower()}) |
237
|
|
|
except Exception as e: |
238
|
|
|
if cursor_energy_db: |
239
|
|
|
cursor_energy_db.close() |
240
|
|
|
if cnx_energy_db: |
241
|
|
|
cnx_energy_db.close() |
242
|
|
|
return "Error in step 2.2 of virtual meter worker " + str(e) + " for '" + virtual_meter['name'] + "'" |
243
|
|
|
finally: |
244
|
|
|
if cursor_factory_db: |
245
|
|
|
cursor_factory_db.close() |
246
|
|
|
if cnx_factory_db: |
247
|
|
|
cnx_factory_db.close() |
248
|
|
|
|
249
|
|
|
############################################################################################################ |
250
|
|
|
# Step 3: query energy consumption values from table meter hourly, virtual meter hourly |
251
|
|
|
# and offline meter hourly |
252
|
|
|
############################################################################################################ |
253
|
|
|
|
254
|
|
|
print("getting energy consumption values from myems_energy_db.tbl_meter_hourly...") |
255
|
|
|
energy_meter_hourly = dict() |
256
|
|
|
if meter_list_in_expression is not None and len(meter_list_in_expression) > 0: |
257
|
|
|
try: |
258
|
|
|
for meter_in_expression in meter_list_in_expression: |
259
|
|
|
meter_id = str(meter_in_expression['meter_id']) |
260
|
|
|
query = (" SELECT start_datetime_utc, actual_value " |
261
|
|
|
" FROM tbl_meter_hourly " |
262
|
|
|
" WHERE meter_id = %s AND start_datetime_utc >= %s AND start_datetime_utc < %s " |
263
|
|
|
" ORDER BY start_datetime_utc ") |
264
|
|
|
cursor_energy_db.execute(query, (meter_id, start_datetime_utc, end_datetime_utc, )) |
265
|
|
|
rows_energy_values = cursor_energy_db.fetchall() |
266
|
|
|
if rows_energy_values is None or len(rows_energy_values) == 0: |
267
|
|
|
energy_meter_hourly[meter_id] = None |
268
|
|
|
else: |
269
|
|
|
energy_meter_hourly[meter_id] = dict() |
270
|
|
|
for row_energy_value in rows_energy_values: |
271
|
|
|
energy_meter_hourly[meter_id][row_energy_value[0]] = row_energy_value[1] |
272
|
|
|
except Exception as e: |
273
|
|
|
if cursor_energy_db: |
274
|
|
|
cursor_energy_db.close() |
275
|
|
|
if cnx_energy_db: |
276
|
|
|
cnx_energy_db.close() |
277
|
|
|
return "Error in step 3.2 virtual meter worker " + str(e) + " for '" + virtual_meter['name'] + "'" |
278
|
|
|
|
279
|
|
|
print("getting energy consumption values from myems_energy_db.tbl_virtual_meter_hourly...") |
280
|
|
|
energy_virtual_meter_hourly = dict() |
281
|
|
|
if virtual_meter_list_in_expression is not None and len(virtual_meter_list_in_expression) > 0: |
282
|
|
|
try: |
283
|
|
|
for virtual_meter_in_expression in virtual_meter_list_in_expression: |
284
|
|
|
virtual_meter_id = str(virtual_meter_in_expression['virtual_meter_id']) |
285
|
|
|
query = (" SELECT start_datetime_utc, actual_value " |
286
|
|
|
" FROM tbl_virtual_meter_hourly " |
287
|
|
|
" WHERE virtual_meter_id = %s " |
288
|
|
|
" AND start_datetime_utc >= %s AND start_datetime_utc < %s " |
289
|
|
|
" ORDER BY start_datetime_utc ") |
290
|
|
|
cursor_energy_db.execute(query, (virtual_meter_id, start_datetime_utc, end_datetime_utc,)) |
291
|
|
|
rows_energy_values = cursor_energy_db.fetchall() |
292
|
|
|
if rows_energy_values is None or len(rows_energy_values) == 0: |
293
|
|
|
energy_virtual_meter_hourly[virtual_meter_id] = None |
294
|
|
|
else: |
295
|
|
|
energy_virtual_meter_hourly[virtual_meter_id] = dict() |
296
|
|
|
for row_energy_value in rows_energy_values: |
297
|
|
|
energy_virtual_meter_hourly[virtual_meter_id][row_energy_value[0]] = row_energy_value[1] |
298
|
|
|
except Exception as e: |
299
|
|
|
if cursor_energy_db: |
300
|
|
|
cursor_energy_db.close() |
301
|
|
|
if cnx_energy_db: |
302
|
|
|
cnx_energy_db.close() |
303
|
|
|
return "Error in step 3.3 virtual meter worker " + str(e) + " for '" + virtual_meter['name'] + "'" |
304
|
|
|
|
305
|
|
|
print("getting energy consumption values from myems_energy_db.tbl_offline_meter_hourly...") |
306
|
|
|
energy_offline_meter_hourly = dict() |
307
|
|
|
if offline_meter_list_in_expression is not None and len(offline_meter_list_in_expression) > 0: |
308
|
|
|
try: |
309
|
|
|
for offline_meter_in_expression in offline_meter_list_in_expression: |
310
|
|
|
offline_meter_id = str(offline_meter_in_expression['offline_meter_id']) |
311
|
|
|
query = (" SELECT start_datetime_utc, actual_value " |
312
|
|
|
" FROM tbl_offline_meter_hourly " |
313
|
|
|
" WHERE offline_meter_id = %s " |
314
|
|
|
" AND start_datetime_utc >= %s AND start_datetime_utc < %s " |
315
|
|
|
" ORDER BY start_datetime_utc ") |
316
|
|
|
cursor_energy_db.execute(query, (offline_meter_id, start_datetime_utc, end_datetime_utc,)) |
317
|
|
|
rows_energy_values = cursor_energy_db.fetchall() |
318
|
|
|
if rows_energy_values is None or len(rows_energy_values) == 0: |
319
|
|
|
energy_offline_meter_hourly[offline_meter_id] = None |
320
|
|
|
else: |
321
|
|
|
energy_offline_meter_hourly[offline_meter_id] = dict() |
322
|
|
|
for row_energy_value in rows_energy_values: |
323
|
|
|
energy_offline_meter_hourly[offline_meter_id][row_energy_value[0]] = row_energy_value[1] |
324
|
|
|
except Exception as e: |
325
|
|
|
if cursor_energy_db: |
326
|
|
|
cursor_energy_db.close() |
327
|
|
|
if cnx_energy_db: |
328
|
|
|
cnx_energy_db.close() |
329
|
|
|
return "Error in step 3.4 virtual meter worker " + str(e) + " for '" + virtual_meter['name'] + "'" |
330
|
|
|
|
331
|
|
|
############################################################################################################ |
332
|
|
|
# Step 4: evaluate the equation with variables values from previous step |
333
|
|
|
# and save to table virtual meter hourly |
334
|
|
|
############################################################################################################ |
335
|
|
|
|
336
|
|
|
print("getting common time slot of energy values for all meters...") |
337
|
|
|
common_start_datetime_utc = start_datetime_utc |
338
|
|
|
common_end_datetime_utc = end_datetime_utc |
339
|
|
|
if energy_meter_hourly is not None and len(energy_meter_hourly) > 0: |
340
|
|
|
for meter_id, energy_hourly in energy_meter_hourly.items(): |
341
|
|
|
if energy_hourly is None or len(energy_hourly) == 0: |
342
|
|
|
common_start_datetime_utc = None |
343
|
|
|
common_end_datetime_utc = None |
344
|
|
|
break |
345
|
|
|
else: |
346
|
|
|
if common_start_datetime_utc < min(energy_hourly.keys()): |
347
|
|
|
common_start_datetime_utc = min(energy_hourly.keys()) |
348
|
|
|
if common_end_datetime_utc > max(energy_hourly.keys()): |
349
|
|
|
common_end_datetime_utc = max(energy_hourly.keys()) |
350
|
|
|
|
351
|
|
|
print("getting common time slot of energy values for all virtual meters...") |
352
|
|
View Code Duplication |
if common_start_datetime_utc is not None and common_start_datetime_utc is not None: |
|
|
|
|
353
|
|
|
if energy_virtual_meter_hourly is not None and len(energy_virtual_meter_hourly) > 0: |
354
|
|
|
for meter_id, energy_hourly in energy_virtual_meter_hourly.items(): |
355
|
|
|
if energy_hourly is None or len(energy_hourly) == 0: |
356
|
|
|
common_start_datetime_utc = None |
357
|
|
|
common_end_datetime_utc = None |
358
|
|
|
break |
359
|
|
|
else: |
360
|
|
|
if common_start_datetime_utc < min(energy_hourly.keys()): |
361
|
|
|
common_start_datetime_utc = min(energy_hourly.keys()) |
362
|
|
|
if common_end_datetime_utc > max(energy_hourly.keys()): |
363
|
|
|
common_end_datetime_utc = max(energy_hourly.keys()) |
364
|
|
|
|
365
|
|
|
print("getting common time slot of energy values for all offline meters...") |
366
|
|
View Code Duplication |
if common_start_datetime_utc is not None and common_start_datetime_utc is not None: |
|
|
|
|
367
|
|
|
if energy_offline_meter_hourly is not None and len(energy_offline_meter_hourly) > 0: |
368
|
|
|
for meter_id, energy_hourly in energy_offline_meter_hourly.items(): |
369
|
|
|
if energy_hourly is None or len(energy_hourly) == 0: |
370
|
|
|
common_start_datetime_utc = None |
371
|
|
|
common_end_datetime_utc = None |
372
|
|
|
break |
373
|
|
|
else: |
374
|
|
|
if common_start_datetime_utc < min(energy_hourly.keys()): |
375
|
|
|
common_start_datetime_utc = min(energy_hourly.keys()) |
376
|
|
|
if common_end_datetime_utc > max(energy_hourly.keys()): |
377
|
|
|
common_end_datetime_utc = max(energy_hourly.keys()) |
378
|
|
|
|
379
|
|
|
print("evaluating the equation with SymPy...") |
380
|
|
|
normalized_values = list() |
381
|
|
|
|
382
|
|
|
############################################################################################################ |
383
|
|
|
# Converting Strings to SymPy Expressions |
384
|
|
|
# The sympify function(that’s sympify, not to be confused with simplify) can be used to |
385
|
|
|
# convert strings into SymPy expressions. |
386
|
|
|
############################################################################################################ |
387
|
|
|
try: |
388
|
|
|
expr = sympify(virtual_meter['equation'].lower()) |
389
|
|
|
print("the expression to be evaluated: " + str(expr)) |
390
|
|
|
current_datetime_utc = common_start_datetime_utc |
391
|
|
|
print("common_start_datetime_utc: " + str(common_start_datetime_utc)) |
392
|
|
|
print("common_end_datetime_utc: " + str(common_end_datetime_utc)) |
393
|
|
|
while common_start_datetime_utc is not None \ |
394
|
|
|
and common_end_datetime_utc is not None \ |
395
|
|
|
and current_datetime_utc <= common_end_datetime_utc: |
396
|
|
|
meta_data = dict() |
397
|
|
|
meta_data['start_datetime_utc'] = current_datetime_utc |
398
|
|
|
|
399
|
|
|
#################################################################################################### |
400
|
|
|
# create a dictionary of Symbol: point pairs |
401
|
|
|
#################################################################################################### |
402
|
|
|
|
403
|
|
|
subs = dict() |
404
|
|
|
|
405
|
|
|
#################################################################################################### |
406
|
|
|
# Evaluating the expression at current_datetime_utc |
407
|
|
|
#################################################################################################### |
408
|
|
|
|
409
|
|
|
if meter_list_in_expression is not None and len(meter_list_in_expression) > 0: |
410
|
|
|
for meter_in_expression in meter_list_in_expression: |
411
|
|
|
meter_id = str(meter_in_expression['meter_id']) |
412
|
|
|
actual_value = energy_meter_hourly[meter_id].get(current_datetime_utc, 0.0) |
413
|
|
|
subs[meter_in_expression['variable_name']] = actual_value |
414
|
|
|
|
415
|
|
|
if virtual_meter_list_in_expression is not None and len(virtual_meter_list_in_expression) > 0: |
416
|
|
|
for virtual_meter_in_expression in virtual_meter_list_in_expression: |
417
|
|
|
virtual_meter_id = str(virtual_meter_in_expression['virtual_meter_id']) |
418
|
|
|
actual_value = energy_virtual_meter_hourly[virtual_meter_id].get(current_datetime_utc, 0.0) |
419
|
|
|
subs[virtual_meter_in_expression['variable_name']] = actual_value |
420
|
|
|
|
421
|
|
|
if offline_meter_list_in_expression is not None and len(offline_meter_list_in_expression) > 0: |
422
|
|
|
for offline_meter_in_expression in offline_meter_list_in_expression: |
423
|
|
|
offline_meter_id = str(offline_meter_in_expression['offline_meter_id']) |
424
|
|
|
actual_value = energy_offline_meter_hourly[offline_meter_id].get(current_datetime_utc, 0.0) |
425
|
|
|
subs[offline_meter_in_expression['variable_name']] = actual_value |
426
|
|
|
|
427
|
|
|
#################################################################################################### |
428
|
|
|
# To numerically evaluate an expression with a Symbol at a point, |
429
|
|
|
# we might use subs followed by evalf, |
430
|
|
|
# but it is more efficient and numerically stable to pass the substitution to evalf |
431
|
|
|
# using the subs flag, which takes a dictionary of Symbol: point pairs. |
432
|
|
|
#################################################################################################### |
433
|
|
|
|
434
|
|
|
meta_data['actual_value'] = expr.evalf(subs=subs) |
435
|
|
|
|
436
|
|
|
normalized_values.append(meta_data) |
437
|
|
|
|
438
|
|
|
current_datetime_utc += timedelta(minutes=config.minutes_to_count) |
439
|
|
|
|
440
|
|
|
except Exception as e: |
441
|
|
|
if cursor_energy_db: |
442
|
|
|
cursor_energy_db.close() |
443
|
|
|
if cnx_energy_db: |
444
|
|
|
cnx_energy_db.close() |
445
|
|
|
return "Error in step 4.1 virtual meter worker " + str(e) + " for '" + virtual_meter['name'] + "'" |
446
|
|
|
|
447
|
|
|
print("saving energy values to table virtual meter hourly...") |
448
|
|
|
|
449
|
|
View Code Duplication |
if len(normalized_values) > 0: |
|
|
|
|
450
|
|
|
try: |
451
|
|
|
add_values = (" INSERT INTO tbl_virtual_meter_hourly " |
452
|
|
|
" (virtual_meter_id, start_datetime_utc, actual_value) " |
453
|
|
|
" VALUES ") |
454
|
|
|
|
455
|
|
|
for meta_data in normalized_values: |
456
|
|
|
add_values += " (" + str(virtual_meter['id']) + "," |
457
|
|
|
add_values += "'" + meta_data['start_datetime_utc'].isoformat()[0:19] + "'," |
458
|
|
|
add_values += str(meta_data['actual_value']) + "), " |
459
|
|
|
print("add_values:" + add_values) |
460
|
|
|
# trim ", " at the end of string and then execute |
461
|
|
|
cursor_energy_db.execute(add_values[:-2]) |
462
|
|
|
cnx_energy_db.commit() |
463
|
|
|
except Exception as e: |
464
|
|
|
if cursor_energy_db: |
465
|
|
|
cursor_energy_db.close() |
466
|
|
|
if cnx_energy_db: |
467
|
|
|
cnx_energy_db.close() |
468
|
|
|
return "Error in step 4.2 virtual meter worker " + str(e) + " for '" + virtual_meter['name'] + "'" |
469
|
|
|
|
470
|
|
|
if cursor_energy_db: |
471
|
|
|
cursor_energy_db.close() |
472
|
|
|
if cnx_energy_db: |
473
|
|
|
cnx_energy_db.close() |
474
|
|
|
|
475
|
|
|
return None |
476
|
|
|
|