1
|
|
|
import random |
2
|
|
|
import time |
3
|
|
|
from datetime import datetime, timedelta |
4
|
|
|
from decimal import Decimal |
5
|
|
|
from multiprocessing import Pool |
6
|
|
|
import mysql.connector |
7
|
|
|
from sympy import sympify |
8
|
|
|
import config |
9
|
|
|
|
10
|
|
|
|
11
|
|
|
######################################################################################################################## |
12
|
|
|
# PROCEDURES: |
13
|
|
|
# Step 1: Query all virtual meters |
14
|
|
|
# Step 2: Create multiprocessing pool to call worker in parallel |
15
|
|
|
######################################################################################################################## |
16
|
|
|
|
17
|
|
View Code Duplication |
def calculate_hourly(logger): |
|
|
|
|
18
|
|
|
|
19
|
|
|
while True: |
20
|
|
|
# the outermost while loop to reconnect server if there is a connection error |
21
|
|
|
cnx_system_db = None |
22
|
|
|
cursor_system_db = None |
23
|
|
|
try: |
24
|
|
|
cnx_system_db = mysql.connector.connect(**config.myems_system_db) |
25
|
|
|
cursor_system_db = cnx_system_db.cursor() |
26
|
|
|
except Exception as e: |
27
|
|
|
logger.error("Error in step 0 of virtual_meter.calculate_hourly " + str(e)) |
28
|
|
|
if cursor_system_db: |
29
|
|
|
cursor_system_db.close() |
30
|
|
|
if cnx_system_db: |
31
|
|
|
cnx_system_db.close() |
32
|
|
|
# sleep and continue the outer loop to reconnect the database |
33
|
|
|
time.sleep(60) |
34
|
|
|
continue |
35
|
|
|
|
36
|
|
|
print("Connected to MyEMS System Database") |
37
|
|
|
|
38
|
|
|
virtual_meter_list = list() |
39
|
|
|
try: |
40
|
|
|
cursor_system_db.execute(" SELECT id, name, equation " |
41
|
|
|
" FROM tbl_virtual_meters " |
42
|
|
|
" ORDER BY 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]} |
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 isn't time to calculate" + " for '" + virtual_meter['name'] + "'" |
149
|
|
|
elif time_difference_in_minutes > 60 * 24 * 30: |
150
|
|
|
# avoid to caculate records more than one month |
151
|
|
|
end_datetime_utc = start_datetime_utc + timedelta(minutes=60 * 24 * 30) |
152
|
|
|
|
153
|
|
|
# trim end_datetime_utc |
154
|
|
|
trimmed_end_datetime_utc = start_datetime_utc + timedelta(minutes=config.minutes_to_count) |
155
|
|
|
while trimmed_end_datetime_utc <= end_datetime_utc: |
156
|
|
|
trimmed_end_datetime_utc += timedelta(minutes=config.minutes_to_count) |
157
|
|
|
|
158
|
|
|
end_datetime_utc = trimmed_end_datetime_utc - timedelta(minutes=config.minutes_to_count) |
159
|
|
|
|
160
|
|
|
if end_datetime_utc <= start_datetime_utc: |
161
|
|
|
if cursor_energy_db: |
162
|
|
|
cursor_energy_db.close() |
163
|
|
|
if cnx_energy_db: |
164
|
|
|
cnx_energy_db.close() |
165
|
|
|
return "it isn't time to calculate" + " for '" + virtual_meter['name'] + "'" |
166
|
|
|
|
167
|
|
|
print("start_datetime_utc: " + start_datetime_utc.isoformat()[0:19] |
168
|
|
|
+ "end_datetime_utc: " + end_datetime_utc.isoformat()[0:19]) |
169
|
|
|
|
170
|
|
|
############################################################################################################ |
171
|
|
|
# Step 2: parse the expression and get all meters, virtual meters, and |
172
|
|
|
# offline meters associated with the expression |
173
|
|
|
############################################################################################################ |
174
|
|
|
cnx_system_db = None |
175
|
|
|
cursor_system_db = None |
176
|
|
|
try: |
177
|
|
|
cnx_system_db = mysql.connector.connect(**config.myems_system_db) |
178
|
|
|
cursor_system_db = cnx_system_db.cursor() |
179
|
|
|
except Exception as e: |
180
|
|
|
if cursor_system_db: |
181
|
|
|
cursor_system_db.close() |
182
|
|
|
if cnx_system_db: |
183
|
|
|
cnx_system_db.close() |
184
|
|
|
if cursor_energy_db: |
185
|
|
|
cursor_energy_db.close() |
186
|
|
|
if cnx_energy_db: |
187
|
|
|
cnx_energy_db.close() |
188
|
|
|
return "Error in step 2.1 of virtual meter worker " + str(e) + " for '" + virtual_meter['name'] + "'" |
189
|
|
|
|
190
|
|
|
meter_list_in_expression = list() |
191
|
|
|
virtual_meter_list_in_expression = list() |
192
|
|
|
offline_meter_list_in_expression = list() |
193
|
|
|
try: |
194
|
|
|
######################################################################################################## |
195
|
|
|
# get all meters associated with the expression |
196
|
|
|
######################################################################################################## |
197
|
|
|
|
198
|
|
|
cursor_system_db.execute(" SELECT m.id as meter_id, v.name as variable_name " |
199
|
|
|
" FROM tbl_meters m, tbl_variables v " |
200
|
|
|
" WHERE m.id = v.meter_id " |
201
|
|
|
" AND v.meter_type = 'meter' " |
202
|
|
|
" AND v.virtual_meter_id = %s ", |
203
|
|
|
(virtual_meter['id'], )) |
204
|
|
|
rows = cursor_system_db.fetchall() |
205
|
|
|
if rows is not None and len(rows) > 0: |
206
|
|
|
for row in rows: |
207
|
|
|
meter_list_in_expression.append({"meter_id": row[0], "variable_name": row[1].lower()}) |
208
|
|
|
|
209
|
|
|
######################################################################################################## |
210
|
|
|
# get all virtual meters associated with the expression |
211
|
|
|
######################################################################################################## |
212
|
|
|
|
213
|
|
|
cursor_system_db.execute(" SELECT m.id as virtual_meter_id, v.name as variable_name " |
214
|
|
|
" FROM tbl_virtual_meters m, tbl_variables v " |
215
|
|
|
" WHERE m.id = v.meter_id " |
216
|
|
|
" AND v.meter_type = 'virtual_meter' " |
217
|
|
|
" AND v.virtual_meter_id = %s ", |
218
|
|
|
(virtual_meter['id'],)) |
219
|
|
|
rows = cursor_system_db.fetchall() |
220
|
|
|
if rows is not None and len(rows) > 0: |
221
|
|
|
for row in rows: |
222
|
|
|
virtual_meter_list_in_expression.append({"virtual_meter_id": row[0], |
223
|
|
|
"variable_name": row[1].lower()}) |
224
|
|
|
|
225
|
|
|
######################################################################################################## |
226
|
|
|
# get all offline meters associated with the expression |
227
|
|
|
######################################################################################################## |
228
|
|
|
|
229
|
|
|
cursor_system_db.execute(" SELECT m.id as offline_meter_id, v.name as variable_name " |
230
|
|
|
" FROM tbl_offline_meters m, tbl_variables v " |
231
|
|
|
" WHERE m.id = v.meter_id " |
232
|
|
|
" AND v.meter_type = 'offline_meter' " |
233
|
|
|
" AND v.virtual_meter_id = %s ", |
234
|
|
|
(virtual_meter['id'],)) |
235
|
|
|
rows = cursor_system_db.fetchall() |
236
|
|
|
if rows is not None and len(rows) > 0: |
237
|
|
|
for row in rows: |
238
|
|
|
offline_meter_list_in_expression.append({"offline_meter_id": row[0], |
239
|
|
|
"variable_name": row[1].lower()}) |
240
|
|
|
except Exception as e: |
241
|
|
|
if cursor_energy_db: |
242
|
|
|
cursor_energy_db.close() |
243
|
|
|
if cnx_energy_db: |
244
|
|
|
cnx_energy_db.close() |
245
|
|
|
return "Error in step 2.2 of virtual meter worker " + str(e) + " for '" + virtual_meter['name'] + "'" |
246
|
|
|
finally: |
247
|
|
|
if cursor_system_db: |
248
|
|
|
cursor_system_db.close() |
249
|
|
|
if cnx_system_db: |
250
|
|
|
cnx_system_db.close() |
251
|
|
|
|
252
|
|
|
############################################################################################################ |
253
|
|
|
# Step 3: query energy consumption values from table meter hourly, virtual meter hourly |
254
|
|
|
# and offline meter hourly |
255
|
|
|
############################################################################################################ |
256
|
|
|
|
257
|
|
|
print("getting energy consumption values from myems_energy_db.tbl_meter_hourly...") |
258
|
|
|
energy_meter_hourly = dict() |
259
|
|
|
if meter_list_in_expression is not None and len(meter_list_in_expression) > 0: |
260
|
|
|
try: |
261
|
|
|
for meter_in_expression in meter_list_in_expression: |
262
|
|
|
meter_id = str(meter_in_expression['meter_id']) |
263
|
|
|
query = (" SELECT start_datetime_utc, actual_value " |
264
|
|
|
" FROM tbl_meter_hourly " |
265
|
|
|
" WHERE meter_id = %s AND start_datetime_utc >= %s AND start_datetime_utc < %s " |
266
|
|
|
" ORDER BY start_datetime_utc ") |
267
|
|
|
cursor_energy_db.execute(query, (meter_id, start_datetime_utc, end_datetime_utc, )) |
268
|
|
|
rows_energy_values = cursor_energy_db.fetchall() |
269
|
|
|
if rows_energy_values is None or len(rows_energy_values) == 0: |
270
|
|
|
energy_meter_hourly[meter_id] = None |
271
|
|
|
else: |
272
|
|
|
energy_meter_hourly[meter_id] = dict() |
273
|
|
|
for row_energy_value in rows_energy_values: |
274
|
|
|
energy_meter_hourly[meter_id][row_energy_value[0]] = row_energy_value[1] |
275
|
|
|
except Exception as e: |
276
|
|
|
if cursor_energy_db: |
277
|
|
|
cursor_energy_db.close() |
278
|
|
|
if cnx_energy_db: |
279
|
|
|
cnx_energy_db.close() |
280
|
|
|
return "Error in step 3.2 virtual meter worker " + str(e) + " for '" + virtual_meter['name'] + "'" |
281
|
|
|
|
282
|
|
|
print("getting energy consumption values from myems_energy_db.tbl_virtual_meter_hourly...") |
283
|
|
|
energy_virtual_meter_hourly = dict() |
284
|
|
|
if virtual_meter_list_in_expression is not None and len(virtual_meter_list_in_expression) > 0: |
285
|
|
|
try: |
286
|
|
|
for virtual_meter_in_expression in virtual_meter_list_in_expression: |
287
|
|
|
virtual_meter_id = str(virtual_meter_in_expression['virtual_meter_id']) |
288
|
|
|
query = (" SELECT start_datetime_utc, actual_value " |
289
|
|
|
" FROM tbl_virtual_meter_hourly " |
290
|
|
|
" WHERE virtual_meter_id = %s " |
291
|
|
|
" AND start_datetime_utc >= %s AND start_datetime_utc < %s " |
292
|
|
|
" ORDER BY start_datetime_utc ") |
293
|
|
|
cursor_energy_db.execute(query, (virtual_meter_id, start_datetime_utc, end_datetime_utc,)) |
294
|
|
|
rows_energy_values = cursor_energy_db.fetchall() |
295
|
|
|
if rows_energy_values is None or len(rows_energy_values) == 0: |
296
|
|
|
energy_virtual_meter_hourly[virtual_meter_id] = None |
297
|
|
|
else: |
298
|
|
|
energy_virtual_meter_hourly[virtual_meter_id] = dict() |
299
|
|
|
for row_energy_value in rows_energy_values: |
300
|
|
|
energy_virtual_meter_hourly[virtual_meter_id][row_energy_value[0]] = row_energy_value[1] |
301
|
|
|
except Exception as e: |
302
|
|
|
if cursor_energy_db: |
303
|
|
|
cursor_energy_db.close() |
304
|
|
|
if cnx_energy_db: |
305
|
|
|
cnx_energy_db.close() |
306
|
|
|
return "Error in step 3.3 virtual meter worker " + str(e) + " for '" + virtual_meter['name'] + "'" |
307
|
|
|
|
308
|
|
|
print("getting energy consumption values from myems_energy_db.tbl_offline_meter_hourly...") |
309
|
|
|
energy_offline_meter_hourly = dict() |
310
|
|
|
if offline_meter_list_in_expression is not None and len(offline_meter_list_in_expression) > 0: |
311
|
|
|
try: |
312
|
|
|
for offline_meter_in_expression in offline_meter_list_in_expression: |
313
|
|
|
offline_meter_id = str(offline_meter_in_expression['offline_meter_id']) |
314
|
|
|
query = (" SELECT start_datetime_utc, actual_value " |
315
|
|
|
" FROM tbl_offline_meter_hourly " |
316
|
|
|
" WHERE offline_meter_id = %s " |
317
|
|
|
" AND start_datetime_utc >= %s AND start_datetime_utc < %s " |
318
|
|
|
" ORDER BY start_datetime_utc ") |
319
|
|
|
cursor_energy_db.execute(query, (offline_meter_id, start_datetime_utc, end_datetime_utc,)) |
320
|
|
|
rows_energy_values = cursor_energy_db.fetchall() |
321
|
|
|
if rows_energy_values is None or len(rows_energy_values) == 0: |
322
|
|
|
energy_offline_meter_hourly[offline_meter_id] = None |
323
|
|
|
else: |
324
|
|
|
energy_offline_meter_hourly[offline_meter_id] = dict() |
325
|
|
|
for row_energy_value in rows_energy_values: |
326
|
|
|
energy_offline_meter_hourly[offline_meter_id][row_energy_value[0]] = row_energy_value[1] |
327
|
|
|
except Exception as e: |
328
|
|
|
if cursor_energy_db: |
329
|
|
|
cursor_energy_db.close() |
330
|
|
|
if cnx_energy_db: |
331
|
|
|
cnx_energy_db.close() |
332
|
|
|
return "Error in step 3.4 virtual meter worker " + str(e) + " for '" + virtual_meter['name'] + "'" |
333
|
|
|
|
334
|
|
|
############################################################################################################ |
335
|
|
|
# Step 4: evaluate the equation with variables values from previous step |
336
|
|
|
# and save to table virtual meter hourly |
337
|
|
|
############################################################################################################ |
338
|
|
|
|
339
|
|
|
print("getting common time slot of energy values for all meters...") |
340
|
|
|
common_start_datetime_utc = start_datetime_utc |
341
|
|
|
common_end_datetime_utc = end_datetime_utc |
342
|
|
|
if energy_meter_hourly is not None and len(energy_meter_hourly) > 0: |
343
|
|
|
for meter_id, energy_hourly in energy_meter_hourly.items(): |
344
|
|
|
if energy_hourly is None or len(energy_hourly) == 0: |
345
|
|
|
common_start_datetime_utc = None |
346
|
|
|
common_end_datetime_utc = None |
347
|
|
|
break |
348
|
|
|
else: |
349
|
|
|
if common_start_datetime_utc < min(energy_hourly.keys()): |
350
|
|
|
common_start_datetime_utc = min(energy_hourly.keys()) |
351
|
|
|
if common_end_datetime_utc > max(energy_hourly.keys()): |
352
|
|
|
common_end_datetime_utc = max(energy_hourly.keys()) |
353
|
|
|
|
354
|
|
|
print("getting common time slot of energy values for all virtual meters...") |
355
|
|
|
if common_start_datetime_utc is not None and common_end_datetime_utc is not None: |
356
|
|
|
if energy_virtual_meter_hourly is not None and len(energy_virtual_meter_hourly) > 0: |
357
|
|
|
for meter_id, energy_hourly in energy_virtual_meter_hourly.items(): |
358
|
|
|
if energy_hourly is None or len(energy_hourly) == 0: |
359
|
|
|
common_start_datetime_utc = None |
360
|
|
|
common_end_datetime_utc = None |
361
|
|
|
break |
362
|
|
|
else: |
363
|
|
|
if common_start_datetime_utc < min(energy_hourly.keys()): |
364
|
|
|
common_start_datetime_utc = min(energy_hourly.keys()) |
365
|
|
|
if common_end_datetime_utc > max(energy_hourly.keys()): |
366
|
|
|
common_end_datetime_utc = max(energy_hourly.keys()) |
367
|
|
|
|
368
|
|
|
print("getting common time slot of energy values for all offline meters...") |
369
|
|
|
if common_start_datetime_utc is not None and common_end_datetime_utc is not None: |
370
|
|
|
if energy_offline_meter_hourly is not None and len(energy_offline_meter_hourly) > 0: |
371
|
|
|
for meter_id, energy_hourly in energy_offline_meter_hourly.items(): |
372
|
|
|
if energy_hourly is None or len(energy_hourly) == 0: |
373
|
|
|
common_start_datetime_utc = None |
374
|
|
|
common_end_datetime_utc = None |
375
|
|
|
break |
376
|
|
|
else: |
377
|
|
|
if common_start_datetime_utc < min(energy_hourly.keys()): |
378
|
|
|
common_start_datetime_utc = min(energy_hourly.keys()) |
379
|
|
|
if common_end_datetime_utc > max(energy_hourly.keys()): |
380
|
|
|
common_end_datetime_utc = max(energy_hourly.keys()) |
381
|
|
|
|
382
|
|
|
print("evaluating the equation with SymPy...") |
383
|
|
|
normalized_values = list() |
384
|
|
|
|
385
|
|
|
############################################################################################################ |
386
|
|
|
# Converting Strings to SymPy Expressions |
387
|
|
|
# The sympify function(that’s sympify, not to be confused with simplify) can be used to |
388
|
|
|
# convert strings into SymPy expressions. |
389
|
|
|
############################################################################################################ |
390
|
|
|
try: |
391
|
|
|
expr = sympify(virtual_meter['equation'].lower()) |
392
|
|
|
print("the expression to be evaluated: " + str(expr)) |
393
|
|
|
current_datetime_utc = common_start_datetime_utc |
394
|
|
|
print("common_start_datetime_utc: " + str(common_start_datetime_utc)) |
395
|
|
|
print("common_end_datetime_utc: " + str(common_end_datetime_utc)) |
396
|
|
|
while common_start_datetime_utc is not None \ |
397
|
|
|
and common_end_datetime_utc is not None \ |
398
|
|
|
and current_datetime_utc <= common_end_datetime_utc: |
399
|
|
|
meta_data = dict() |
400
|
|
|
meta_data['start_datetime_utc'] = current_datetime_utc |
401
|
|
|
|
402
|
|
|
#################################################################################################### |
403
|
|
|
# create a dictionary of Symbol: point pairs |
404
|
|
|
#################################################################################################### |
405
|
|
|
|
406
|
|
|
subs = dict() |
407
|
|
|
|
408
|
|
|
#################################################################################################### |
409
|
|
|
# Evaluating the expression at current_datetime_utc |
410
|
|
|
#################################################################################################### |
411
|
|
|
|
412
|
|
|
if meter_list_in_expression is not None and len(meter_list_in_expression) > 0: |
413
|
|
|
for meter_in_expression in meter_list_in_expression: |
414
|
|
|
meter_id = str(meter_in_expression['meter_id']) |
415
|
|
|
actual_value = energy_meter_hourly[meter_id].get(current_datetime_utc, Decimal(0.0)) |
416
|
|
|
subs[meter_in_expression['variable_name']] = actual_value |
417
|
|
|
|
418
|
|
|
if virtual_meter_list_in_expression is not None and len(virtual_meter_list_in_expression) > 0: |
419
|
|
|
for virtual_meter_in_expression in virtual_meter_list_in_expression: |
420
|
|
|
virtual_meter_id = str(virtual_meter_in_expression['virtual_meter_id']) |
421
|
|
|
actual_value = energy_virtual_meter_hourly[virtual_meter_id].get(current_datetime_utc, Decimal(0.0)) |
422
|
|
|
subs[virtual_meter_in_expression['variable_name']] = actual_value |
423
|
|
|
|
424
|
|
|
if offline_meter_list_in_expression is not None and len(offline_meter_list_in_expression) > 0: |
425
|
|
|
for offline_meter_in_expression in offline_meter_list_in_expression: |
426
|
|
|
offline_meter_id = str(offline_meter_in_expression['offline_meter_id']) |
427
|
|
|
actual_value = energy_offline_meter_hourly[offline_meter_id].get(current_datetime_utc, Decimal(0.0)) |
428
|
|
|
subs[offline_meter_in_expression['variable_name']] = actual_value |
429
|
|
|
|
430
|
|
|
#################################################################################################### |
431
|
|
|
# To numerically evaluate an expression with a Symbol at a point, |
432
|
|
|
# we might use subs followed by evalf, |
433
|
|
|
# but it is more efficient and numerically stable to pass the substitution to evalf |
434
|
|
|
# using the subs flag, which takes a dictionary of Symbol: point pairs. |
435
|
|
|
#################################################################################################### |
436
|
|
|
|
437
|
|
|
meta_data['actual_value'] = expr.evalf(subs=subs) |
438
|
|
|
|
439
|
|
|
normalized_values.append(meta_data) |
440
|
|
|
|
441
|
|
|
current_datetime_utc += timedelta(minutes=config.minutes_to_count) |
442
|
|
|
|
443
|
|
|
except Exception as e: |
444
|
|
|
if cursor_energy_db: |
445
|
|
|
cursor_energy_db.close() |
446
|
|
|
if cnx_energy_db: |
447
|
|
|
cnx_energy_db.close() |
448
|
|
|
return "Error in step 4.1 virtual meter worker " + str(e) + " for '" + virtual_meter['name'] + "'" |
449
|
|
|
|
450
|
|
|
print("saving energy values to table energy virtual meter hourly...") |
451
|
|
|
|
452
|
|
View Code Duplication |
while len(normalized_values) > 0: |
|
|
|
|
453
|
|
|
insert_100 = normalized_values[:100] |
454
|
|
|
normalized_values = normalized_values[100:] |
455
|
|
|
try: |
456
|
|
|
add_values = (" INSERT INTO tbl_virtual_meter_hourly " |
457
|
|
|
" (virtual_meter_id, start_datetime_utc, actual_value) " |
458
|
|
|
" VALUES ") |
459
|
|
|
|
460
|
|
|
for meta_data in insert_100: |
461
|
|
|
add_values += " (" + str(virtual_meter['id']) + "," |
462
|
|
|
add_values += "'" + meta_data['start_datetime_utc'].isoformat()[0:19] + "'," |
463
|
|
|
add_values += str(meta_data['actual_value']) + "), " |
464
|
|
|
print("add_values:" + add_values) |
465
|
|
|
# trim ", " at the end of string and then execute |
466
|
|
|
cursor_energy_db.execute(add_values[:-2]) |
467
|
|
|
cnx_energy_db.commit() |
468
|
|
|
except Exception as e: |
469
|
|
|
if cursor_energy_db: |
470
|
|
|
cursor_energy_db.close() |
471
|
|
|
if cnx_energy_db: |
472
|
|
|
cnx_energy_db.close() |
473
|
|
|
return "Error in step 4.2 virtual meter worker " + str(e) + " for '" + virtual_meter['name'] + "'" |
474
|
|
|
|
475
|
|
|
if cursor_energy_db: |
476
|
|
|
cursor_energy_db.close() |
477
|
|
|
if cnx_energy_db: |
478
|
|
|
cnx_energy_db.close() |
479
|
|
|
|
480
|
|
|
return None |
481
|
|
|
|