Code Duplication    Length = 510-516 lines in 5 locations

myems-aggregation/combined_equipment_energy_input_item.py 1 location

@@ 110-625 (lines=516) @@
107
# NOTE: returns None or the error string because that the logger object cannot be passed in as parameter
108
########################################################################################################################
109
110
def worker(combined_equipment):
111
    ####################################################################################################################
112
    # Step 1: get all input meters associated with the combined equipment
113
    ####################################################################################################################
114
    print("Step 1: get all input meters associated with the combined equipment " + str(combined_equipment['name']))
115
116
    meter_list = list()
117
    cnx_system_db = None
118
    cursor_system_db = None
119
    try:
120
        cnx_system_db = mysql.connector.connect(**config.myems_system_db)
121
        cursor_system_db = cnx_system_db.cursor()
122
    except Exception as e:
123
        error_string = "Error in step 1.1 of combined_equipment_energy_input_item.worker " + str(e)
124
        if cursor_system_db:
125
            cursor_system_db.close()
126
        if cnx_system_db:
127
            cnx_system_db.close()
128
        print(error_string)
129
        return error_string
130
131
    try:
132
        cursor_system_db.execute(" SELECT m.id, m.name, m.energy_item_id "
133
                                 " FROM tbl_meters m, tbl_combined_equipments_meters em "
134
                                 " WHERE m.id = em.meter_id "
135
                                 "       AND m.is_counted = 1 "
136
                                 "       AND m.energy_item_id is NOT NULL "
137
                                 "       AND em.is_output = 0 "
138
                                 "       AND em.combined_equipment_id = %s ",
139
                                 (combined_equipment['id'],))
140
        rows_meters = cursor_system_db.fetchall()
141
142
        if rows_meters is not None and len(rows_meters) > 0:
143
            for row in rows_meters:
144
                meter_list.append({"id": row[0],
145
                                   "name": row[1],
146
                                   "energy_item_id": row[2]})
147
148
    except Exception as e:
149
        error_string = "Error in step 1.2 of combined_equipment_energy_input_item.worker " + str(e)
150
        if cursor_system_db:
151
            cursor_system_db.close()
152
        if cnx_system_db:
153
            cnx_system_db.close()
154
        print(error_string)
155
        return error_string
156
157
    ####################################################################################################################
158
    # Step 2: get all input virtual meters associated with the combined equipment
159
    ####################################################################################################################
160
    print("Step 2: get all input virtual meters associated with the combined equipment")
161
    virtual_meter_list = list()
162
163
    try:
164
        cursor_system_db.execute(" SELECT m.id, m.name, m.energy_item_id "
165
                                 " FROM tbl_virtual_meters m, tbl_combined_equipments_virtual_meters em "
166
                                 " WHERE m.id = em.virtual_meter_id "
167
                                 "       AND m.energy_item_id is NOT NULL "
168
                                 "       AND m.is_counted = 1 "
169
                                 "       AND em.is_output = 0 "
170
                                 "       AND em.combined_equipment_id = %s ",
171
                                 (combined_equipment['id'],))
172
        rows_virtual_meters = cursor_system_db.fetchall()
173
174
        if rows_virtual_meters is not None and len(rows_virtual_meters) > 0:
175
            for row in rows_virtual_meters:
176
                virtual_meter_list.append({"id": row[0],
177
                                           "name": row[1],
178
                                           "energy_item_id": row[2]})
179
180
    except Exception as e:
181
        error_string = "Error in step 2.1 of combined_equipment_energy_input_item.worker " + str(e)
182
        if cursor_system_db:
183
            cursor_system_db.close()
184
        if cnx_system_db:
185
            cnx_system_db.close()
186
        print(error_string)
187
        return error_string
188
189
    ####################################################################################################################
190
    # Step 3: get all input offline meters associated with the combined equipment
191
    ####################################################################################################################
192
    print("Step 3: get all input offline meters associated with the combined equipment")
193
194
    offline_meter_list = list()
195
196
    try:
197
        cursor_system_db.execute(" SELECT m.id, m.name, m.energy_item_id "
198
                                 " FROM tbl_offline_meters m, tbl_combined_equipments_offline_meters em "
199
                                 " WHERE m.id = em.offline_meter_id "
200
                                 "       AND m.energy_item_id is NOT NULL "
201
                                 "       AND m.is_counted = 1 "
202
                                 "       AND em.is_output = 0 "
203
                                 "       AND em.combined_equipment_id = %s ",
204
                                 (combined_equipment['id'],))
205
        rows_offline_meters = cursor_system_db.fetchall()
206
207
        if rows_offline_meters is not None and len(rows_offline_meters) > 0:
208
            for row in rows_offline_meters:
209
                offline_meter_list.append({"id": row[0],
210
                                           "name": row[1],
211
                                           "energy_item_id": row[2]})
212
213
    except Exception as e:
214
        error_string = "Error in step 3.1 of combined_equipment_energy_input_item.worker " + str(e)
215
        if cursor_system_db:
216
            cursor_system_db.close()
217
        if cnx_system_db:
218
            cnx_system_db.close()
219
        print(error_string)
220
        return error_string
221
222
    ####################################################################################################################
223
    # Step 4: get all equipments associated with the combined equipment
224
    ####################################################################################################################
225
    print("Step 4: get all equipments associated with the combined equipment")
226
227
    equipment_list = list()
228
229
    try:
230
        cursor_system_db.execute(" SELECT e.id, e.name "
231
                                 " FROM tbl_equipments e, tbl_combined_equipments_equipments ce "
232
                                 " WHERE e.id = ce.equipment_id "
233
                                 "       AND e.is_input_counted = 1 "
234
                                 "       AND ce.combined_equipment_id = %s ",
235
                                 (combined_equipment['id'],))
236
        rows_equipments = cursor_system_db.fetchall()
237
238
        if rows_equipments is not None and len(rows_equipments) > 0:
239
            for row in rows_equipments:
240
                equipment_list.append({"id": row[0],
241
                                       "name": row[1]})
242
243
    except Exception as e:
244
        error_string = "Error in step 4 of combined_equipment_energy_input_item.worker " + str(e)
245
        print(error_string)
246
        return error_string
247
    finally:
248
        if cursor_system_db:
249
            cursor_system_db.close()
250
        if cnx_system_db:
251
            cnx_system_db.close()
252
253
    ####################################################################################################################
254
    # stop to the next combined equipment if this combined equipment is empty
255
    ####################################################################################################################
256
    if (meter_list is None or len(meter_list) == 0) and \
257
            (virtual_meter_list is None or len(virtual_meter_list) == 0) and \
258
            (offline_meter_list is None or len(offline_meter_list) == 0) and \
259
            (equipment_list is None or len(equipment_list) == 0):
260
        print("This is an empty combined equipment ")
261
        return None
262
263
    ####################################################################################################################
264
    # Step 5: determine start datetime and end datetime to aggregate
265
    ####################################################################################################################
266
    print("Step 5: determine start datetime and end datetime to aggregate")
267
    cnx_energy_db = None
268
    cursor_energy_db = None
269
    try:
270
        cnx_energy_db = mysql.connector.connect(**config.myems_energy_db)
271
        cursor_energy_db = cnx_energy_db.cursor()
272
    except Exception as e:
273
        error_string = "Error in step 5.1 of combined_equipment_energy_input_item.worker " + str(e)
274
        if cursor_energy_db:
275
            cursor_energy_db.close()
276
        if cnx_energy_db:
277
            cnx_energy_db.close()
278
        print(error_string)
279
        return error_string
280
281
    try:
282
        query = (" SELECT MAX(start_datetime_utc) "
283
                 " FROM tbl_combined_equipment_input_item_hourly "
284
                 " WHERE combined_equipment_id = %s ")
285
        cursor_energy_db.execute(query, (combined_equipment['id'],))
286
        row_datetime = cursor_energy_db.fetchone()
287
        start_datetime_utc = datetime.strptime(config.start_datetime_utc, '%Y-%m-%d %H:%M:%S')
288
        start_datetime_utc = start_datetime_utc.replace(minute=0, second=0, microsecond=0, tzinfo=None)
289
290
        if row_datetime is not None and len(row_datetime) > 0 and isinstance(row_datetime[0], datetime):
291
            # replace second and microsecond with 0
292
            # note: do not replace minute in case of calculating in half hourly
293
            start_datetime_utc = row_datetime[0].replace(second=0, microsecond=0, tzinfo=None)
294
            # start from the next time slot
295
            start_datetime_utc += timedelta(minutes=config.minutes_to_count)
296
297
        end_datetime_utc = datetime.utcnow().replace(second=0, microsecond=0, tzinfo=None)
298
299
        print("start_datetime_utc: " + start_datetime_utc.isoformat()[0:19]
300
              + "end_datetime_utc: " + end_datetime_utc.isoformat()[0:19])
301
302
    except Exception as e:
303
        error_string = "Error in step 5.2 of combined_equipment_energy_input_item.worker " + str(e)
304
        if cursor_energy_db:
305
            cursor_energy_db.close()
306
        if cnx_energy_db:
307
            cnx_energy_db.close()
308
        print(error_string)
309
        return error_string
310
311
    ####################################################################################################################
312
    # Step 6: for each meter in list, get energy input data from energy database
313
    ####################################################################################################################
314
    energy_meter_hourly = dict()
315
    try:
316
        if meter_list is not None and len(meter_list) > 0:
317
            for meter in meter_list:
318
                meter_id = str(meter['id'])
319
320
                query = (" SELECT start_datetime_utc, actual_value "
321
                         " FROM tbl_meter_hourly "
322
                         " WHERE meter_id = %s "
323
                         "       AND start_datetime_utc >= %s "
324
                         "       AND start_datetime_utc < %s "
325
                         " ORDER BY start_datetime_utc ")
326
                cursor_energy_db.execute(query, (meter_id, start_datetime_utc, end_datetime_utc,))
327
                rows_energy_values = cursor_energy_db.fetchall()
328
                if rows_energy_values is None or len(rows_energy_values) == 0:
329
                    energy_meter_hourly[meter_id] = None
330
                else:
331
                    energy_meter_hourly[meter_id] = dict()
332
                    for row_energy_value in rows_energy_values:
333
                        energy_meter_hourly[meter_id][row_energy_value[0]] = row_energy_value[1]
334
    except Exception as e:
335
        error_string = "Error in step 6.1 of combined_equipment_energy_input_item.worker " + str(e)
336
        if cursor_energy_db:
337
            cursor_energy_db.close()
338
        if cnx_energy_db:
339
            cnx_energy_db.close()
340
        print(error_string)
341
        return error_string
342
343
    ####################################################################################################################
344
    # Step 7: for each virtual meter in list, get energy input data from energy database
345
    ####################################################################################################################
346
    energy_virtual_meter_hourly = dict()
347
    if virtual_meter_list is not None and len(virtual_meter_list) > 0:
348
        try:
349
            for virtual_meter in virtual_meter_list:
350
                virtual_meter_id = str(virtual_meter['id'])
351
352
                query = (" SELECT start_datetime_utc, actual_value "
353
                         " FROM tbl_virtual_meter_hourly "
354
                         " WHERE virtual_meter_id = %s "
355
                         "       AND start_datetime_utc >= %s "
356
                         "       AND start_datetime_utc < %s "
357
                         " ORDER BY start_datetime_utc ")
358
                cursor_energy_db.execute(query, (virtual_meter_id, start_datetime_utc, end_datetime_utc,))
359
                rows_energy_values = cursor_energy_db.fetchall()
360
                if rows_energy_values is None or len(rows_energy_values) == 0:
361
                    energy_virtual_meter_hourly[virtual_meter_id] = None
362
                else:
363
                    energy_virtual_meter_hourly[virtual_meter_id] = dict()
364
                    for row_energy_value in rows_energy_values:
365
                        energy_virtual_meter_hourly[virtual_meter_id][row_energy_value[0]] = row_energy_value[1]
366
        except Exception as e:
367
            error_string = "Error in step 7.1 of combined_equipment_energy_input_item.worker " + str(e)
368
            if cursor_energy_db:
369
                cursor_energy_db.close()
370
            if cnx_energy_db:
371
                cnx_energy_db.close()
372
            print(error_string)
373
            return error_string
374
375
    ####################################################################################################################
376
    # Step 8: for each offline meter in list, get energy input data from energy database
377
    ####################################################################################################################
378
    energy_offline_meter_hourly = dict()
379
    if offline_meter_list is not None and len(offline_meter_list) > 0:
380
        try:
381
            for offline_meter in offline_meter_list:
382
                offline_meter_id = str(offline_meter['id'])
383
384
                query = (" SELECT start_datetime_utc, actual_value "
385
                         " FROM tbl_offline_meter_hourly "
386
                         " WHERE offline_meter_id = %s "
387
                         "       AND start_datetime_utc >= %s "
388
                         "       AND start_datetime_utc < %s "
389
                         " ORDER BY start_datetime_utc ")
390
                cursor_energy_db.execute(query, (offline_meter_id, start_datetime_utc, end_datetime_utc,))
391
                rows_energy_values = cursor_energy_db.fetchall()
392
                if rows_energy_values is None or len(rows_energy_values) == 0:
393
                    energy_offline_meter_hourly[offline_meter_id] = None
394
                else:
395
                    energy_offline_meter_hourly[offline_meter_id] = dict()
396
                    for row_energy_value in rows_energy_values:
397
                        energy_offline_meter_hourly[offline_meter_id][row_energy_value[0]] = row_energy_value[1]
398
399
        except Exception as e:
400
            error_string = "Error in step 8.1 of combined_equipment_energy_input_item.worker " + str(e)
401
            if cursor_energy_db:
402
                cursor_energy_db.close()
403
            if cnx_energy_db:
404
                cnx_energy_db.close()
405
            print(error_string)
406
            return error_string
407
408
    ####################################################################################################################
409
    # Step 9: for each equipment in list, get energy input data from energy database
410
    ####################################################################################################################
411
    energy_equipment_hourly = dict()
412
    if equipment_list is not None and len(equipment_list) > 0:
413
        try:
414
            for equipment in equipment_list:
415
                equipment_id = str(equipment['id'])
416
                query = (" SELECT start_datetime_utc, energy_item_id, actual_value "
417
                         " FROM tbl_equipment_input_item_hourly "
418
                         " WHERE equipment_id = %s "
419
                         "       AND start_datetime_utc >= %s "
420
                         "       AND start_datetime_utc < %s "
421
                         " ORDER BY start_datetime_utc ")
422
                cursor_energy_db.execute(query, (equipment_id, start_datetime_utc, end_datetime_utc,))
423
                rows_energy_values = cursor_energy_db.fetchall()
424
                if rows_energy_values is None or len(rows_energy_values) == 0:
425
                    energy_equipment_hourly[equipment_id] = None
426
                else:
427
                    energy_equipment_hourly[equipment_id] = dict()
428
                    for row_value in rows_energy_values:
429
                        current_datetime_utc = row_value[0]
430
                        if current_datetime_utc not in energy_equipment_hourly[equipment_id]:
431
                            energy_equipment_hourly[equipment_id][current_datetime_utc] = dict()
432
                        energy_item_id = row_value[1]
433
                        actual_value = row_value[2]
434
                        energy_equipment_hourly[equipment_id][current_datetime_utc][energy_item_id] = \
435
                            actual_value
436
        except Exception as e:
437
            error_string = "Error in step 9 of combined_equipment_energy_input_item.worker " + str(e)
438
            if cursor_energy_db:
439
                cursor_energy_db.close()
440
            if cnx_energy_db:
441
                cnx_energy_db.close()
442
            print(error_string)
443
            return error_string
444
445
    ####################################################################################################################
446
    # Step 10: determine common time slot to aggregate
447
    ####################################################################################################################
448
449
    common_start_datetime_utc = start_datetime_utc
450
    common_end_datetime_utc = end_datetime_utc
451
452
    print("Getting common time slot of energy values for all meters")
453
    if energy_meter_hourly is not None and len(energy_meter_hourly) > 0:
454
        for meter_id, energy_hourly in energy_meter_hourly.items():
455
            if energy_hourly is None or len(energy_hourly) == 0:
456
                common_start_datetime_utc = None
457
                common_end_datetime_utc = None
458
                break
459
            else:
460
                if common_start_datetime_utc < min(energy_hourly.keys()):
461
                    common_start_datetime_utc = min(energy_hourly.keys())
462
                if common_end_datetime_utc > max(energy_hourly.keys()):
463
                    common_end_datetime_utc = max(energy_hourly.keys())
464
465
    print("Getting common time slot of energy values for all virtual meters")
466
    if common_start_datetime_utc is not None and common_end_datetime_utc is not None:
467
        if energy_virtual_meter_hourly is not None and len(energy_virtual_meter_hourly) > 0:
468
            for meter_id, energy_hourly in energy_virtual_meter_hourly.items():
469
                if energy_hourly is None or len(energy_hourly) == 0:
470
                    common_start_datetime_utc = None
471
                    common_end_datetime_utc = None
472
                    break
473
                else:
474
                    if common_start_datetime_utc < min(energy_hourly.keys()):
475
                        common_start_datetime_utc = min(energy_hourly.keys())
476
                    if common_end_datetime_utc > max(energy_hourly.keys()):
477
                        common_end_datetime_utc = max(energy_hourly.keys())
478
479
    print("Getting common time slot of energy values for all offline meters")
480
    if common_start_datetime_utc is not None and common_end_datetime_utc is not None:
481
        if energy_offline_meter_hourly is not None and len(energy_offline_meter_hourly) > 0:
482
            for meter_id, energy_hourly in energy_offline_meter_hourly.items():
483
                if energy_hourly is None or len(energy_hourly) == 0:
484
                    common_start_datetime_utc = None
485
                    common_end_datetime_utc = None
486
                    break
487
                else:
488
                    if common_start_datetime_utc < min(energy_hourly.keys()):
489
                        common_start_datetime_utc = min(energy_hourly.keys())
490
                    if common_end_datetime_utc > max(energy_hourly.keys()):
491
                        common_end_datetime_utc = max(energy_hourly.keys())
492
493
    print("Getting common time slot of energy values for all equipments")
494
    if common_start_datetime_utc is not None and common_end_datetime_utc is not None:
495
        if energy_equipment_hourly is not None and len(energy_equipment_hourly) > 0:
496
            for equipment_id, energy_hourly in energy_equipment_hourly.items():
497
                if energy_hourly is None or len(energy_hourly) == 0:
498
                    common_start_datetime_utc = None
499
                    common_end_datetime_utc = None
500
                    break
501
                else:
502
                    if common_start_datetime_utc < min(energy_hourly.keys()):
503
                        common_start_datetime_utc = min(energy_hourly.keys())
504
                    if common_end_datetime_utc > max(energy_hourly.keys()):
505
                        common_end_datetime_utc = max(energy_hourly.keys())
506
507
    if (energy_meter_hourly is None or len(energy_meter_hourly) == 0) and \
508
            (energy_virtual_meter_hourly is None or len(energy_virtual_meter_hourly) == 0) and \
509
            (energy_offline_meter_hourly is None or len(energy_offline_meter_hourly) == 0) and \
510
            (energy_equipment_hourly is None or len(energy_equipment_hourly) == 0):
511
        # There isn't any energy data
512
        print("There isn't any energy data")
513
        # continue the for combined equipment loop to the next combined equipment
514
        print("continue the for combined equipment loop to the next combined equipment")
515
        if cursor_energy_db:
516
            cursor_energy_db.close()
517
        if cnx_energy_db:
518
            cnx_energy_db.close()
519
        return None
520
521
    print("common_start_datetime_utc: " + str(common_start_datetime_utc))
522
    print("common_end_datetime_utc: " + str(common_end_datetime_utc))
523
524
    ####################################################################################################################
525
    # Step 11: aggregate energy data in the common time slot by energy items and hourly
526
    ####################################################################################################################
527
528
    print("Step 11: aggregate energy data in the common time slot by energy items and hourly")
529
    aggregated_values = list()
530
    try:
531
        current_datetime_utc = common_start_datetime_utc
532
        while common_start_datetime_utc is not None \
533
                and common_end_datetime_utc is not None \
534
                and current_datetime_utc <= common_end_datetime_utc:
535
            aggregated_value = dict()
536
            aggregated_value['start_datetime_utc'] = current_datetime_utc
537
            aggregated_value['meta_data'] = dict()
538
539
            if meter_list is not None and len(meter_list) > 0:
540
                for meter in meter_list:
541
                    meter_id = str(meter['id'])
542
                    energy_item_id = meter['energy_item_id']
543
                    actual_value = energy_meter_hourly[meter_id].get(current_datetime_utc, Decimal(0.0))
544
                    aggregated_value['meta_data'][energy_item_id] = \
545
                        aggregated_value['meta_data'].get(energy_item_id, Decimal(0.0)) + actual_value
546
547
            if virtual_meter_list is not None and len(virtual_meter_list) > 0:
548
                for virtual_meter in virtual_meter_list:
549
                    virtual_meter_id = str(virtual_meter['id'])
550
                    energy_item_id = virtual_meter['energy_item_id']
551
                    actual_value = energy_virtual_meter_hourly[virtual_meter_id].get(current_datetime_utc, Decimal(0.0))
552
                    aggregated_value['meta_data'][energy_item_id] = \
553
                        aggregated_value['meta_data'].get(energy_item_id, Decimal(0.0)) + actual_value
554
555
            if offline_meter_list is not None and len(offline_meter_list) > 0:
556
                for offline_meter in offline_meter_list:
557
                    offline_meter_id = str(offline_meter['id'])
558
                    energy_item_id = offline_meter['energy_item_id']
559
                    actual_value = energy_offline_meter_hourly[offline_meter_id].get(current_datetime_utc, Decimal(0.0))
560
                    aggregated_value['meta_data'][energy_item_id] = \
561
                        aggregated_value['meta_data'].get(energy_item_id, Decimal(0.0)) + actual_value
562
563
            if equipment_list is not None and len(equipment_list) > 0:
564
                for equipment in equipment_list:
565
                    equipment_id = str(equipment['id'])
566
                    meta_data_dict = energy_equipment_hourly[equipment_id].get(current_datetime_utc, None)
567
                    if meta_data_dict is not None and len(meta_data_dict) > 0:
568
                        for energy_item_id, actual_value in meta_data_dict.items():
569
                            aggregated_value['meta_data'][energy_item_id] = \
570
                                aggregated_value['meta_data'].get(energy_item_id, Decimal(0.0)) + actual_value
571
572
            aggregated_values.append(aggregated_value)
573
574
            current_datetime_utc += timedelta(minutes=config.minutes_to_count)
575
576
    except Exception as e:
577
        error_string = "Error in step 11 of combined_equipment_energy_input_item.worker " + str(e)
578
        if cursor_energy_db:
579
            cursor_energy_db.close()
580
        if cnx_energy_db:
581
            cnx_energy_db.close()
582
        print(error_string)
583
        return error_string
584
585
    ####################################################################################################################
586
    # Step 12: save energy data to energy database
587
    ####################################################################################################################
588
    print("Step 12: save energy data to energy database")
589
590
    while len(aggregated_values) > 0:
591
        insert_100 = aggregated_values[:100]
592
        aggregated_values = aggregated_values[100:]
593
        try:
594
            add_values = (" INSERT INTO tbl_combined_equipment_input_item_hourly "
595
                          "             (combined_equipment_id, "
596
                          "              energy_item_id, "
597
                          "              start_datetime_utc, "
598
                          "              actual_value) "
599
                          " VALUES  ")
600
601
            for aggregated_value in insert_100:
602
                for energy_item_id, actual_value in aggregated_value['meta_data'].items():
603
                    add_values += " (" + str(combined_equipment['id']) + ","
604
                    add_values += " " + str(energy_item_id) + ","
605
                    add_values += "'" + aggregated_value['start_datetime_utc'].isoformat()[0:19] + "',"
606
                    add_values += str(actual_value) + "), "
607
            # print("add_values:" + add_values)
608
            # trim ", " at the end of string and then execute
609
            cursor_energy_db.execute(add_values[:-2])
610
            cnx_energy_db.commit()
611
612
        except Exception as e:
613
            error_string = "Error in step 12.1 of combined_equipment_energy_input_item.worker " + str(e)
614
            print(error_string)
615
            if cursor_energy_db:
616
                cursor_energy_db.close()
617
            if cnx_energy_db:
618
                cnx_energy_db.close()
619
            return error_string
620
621
    if cursor_energy_db:
622
        cursor_energy_db.close()
623
    if cnx_energy_db:
624
        cnx_energy_db.close()
625
    return None
626

myems-aggregation/combined_equipment_energy_input_category.py 1 location

@@ 110-622 (lines=513) @@
107
# NOTE: returns None or the error string because that the logger object cannot be passed in as parameter
108
########################################################################################################################
109
110
def worker(combined_equipment):
111
    ####################################################################################################################
112
    # Step 1: get all input meters associated with the combined equipment
113
    ####################################################################################################################
114
    print("Step 1: get all input meters associated with the combined equipment " + str(combined_equipment['name']))
115
116
    meter_list = list()
117
    cnx_system_db = None
118
    cursor_system_db = None
119
    try:
120
        cnx_system_db = mysql.connector.connect(**config.myems_system_db)
121
        cursor_system_db = cnx_system_db.cursor()
122
    except Exception as e:
123
        error_string = "Error in step 1.1 of combined_equipment_energy_input_category.worker " + str(e)
124
        if cursor_system_db:
125
            cursor_system_db.close()
126
        if cnx_system_db:
127
            cnx_system_db.close()
128
        print(error_string)
129
        return error_string
130
131
    try:
132
        cursor_system_db.execute(" SELECT m.id, m.name, m.energy_category_id "
133
                                 " FROM tbl_meters m, tbl_combined_equipments_meters em "
134
                                 " WHERE m.id = em.meter_id "
135
                                 "       AND m.is_counted = 1 "
136
                                 "       AND em.is_output = 0 "
137
                                 "       AND em.combined_equipment_id = %s ",
138
                                 (combined_equipment['id'],))
139
        rows_meters = cursor_system_db.fetchall()
140
141
        if rows_meters is not None and len(rows_meters) > 0:
142
            for row in rows_meters:
143
                meter_list.append({"id": row[0],
144
                                   "name": row[1],
145
                                   "energy_category_id": row[2]})
146
147
    except Exception as e:
148
        error_string = "Error in step 1.2 of combined_equipment_energy_input_category.worker " + str(e)
149
        if cursor_system_db:
150
            cursor_system_db.close()
151
        if cnx_system_db:
152
            cnx_system_db.close()
153
        print(error_string)
154
        return error_string
155
156
    ####################################################################################################################
157
    # Step 2: get all input virtual meters associated with the combined equipment
158
    ####################################################################################################################
159
    print("Step 2: get all input virtual meters associated with the combined equipment")
160
    virtual_meter_list = list()
161
162
    try:
163
        cursor_system_db.execute(" SELECT m.id, m.name, m.energy_category_id "
164
                                 " FROM tbl_virtual_meters m, tbl_combined_equipments_virtual_meters em "
165
                                 " WHERE m.id = em.virtual_meter_id "
166
                                 "       AND m.is_counted = 1 "
167
                                 "       AND em.is_output = 0 "
168
                                 "       AND em.combined_equipment_id = %s ",
169
                                 (combined_equipment['id'],))
170
        rows_virtual_meters = cursor_system_db.fetchall()
171
172
        if rows_virtual_meters is not None and len(rows_virtual_meters) > 0:
173
            for row in rows_virtual_meters:
174
                virtual_meter_list.append({"id": row[0],
175
                                           "name": row[1],
176
                                           "energy_category_id": row[2]})
177
178
    except Exception as e:
179
        error_string = "Error in step 2.1 of combined_equipment_energy_input_category.worker " + str(e)
180
        if cursor_system_db:
181
            cursor_system_db.close()
182
        if cnx_system_db:
183
            cnx_system_db.close()
184
        print(error_string)
185
        return error_string
186
187
    ####################################################################################################################
188
    # Step 3: get all input offline meters associated with the combined equipment
189
    ####################################################################################################################
190
    print("Step 3: get all input offline meters associated with the combined equipment")
191
192
    offline_meter_list = list()
193
194
    try:
195
        cursor_system_db.execute(" SELECT m.id, m.name, m.energy_category_id "
196
                                 " FROM tbl_offline_meters m, tbl_combined_equipments_offline_meters em "
197
                                 " WHERE m.id = em.offline_meter_id "
198
                                 "       AND m.is_counted = 1 "
199
                                 "       AND em.is_output = 0 "
200
                                 "       AND em.combined_equipment_id = %s ",
201
                                 (combined_equipment['id'],))
202
        rows_offline_meters = cursor_system_db.fetchall()
203
204
        if rows_offline_meters is not None and len(rows_offline_meters) > 0:
205
            for row in rows_offline_meters:
206
                offline_meter_list.append({"id": row[0],
207
                                           "name": row[1],
208
                                           "energy_category_id": row[2]})
209
210
    except Exception as e:
211
        error_string = "Error in step 3.1 of combined_equipment_energy_input_category.worker " + str(e)
212
        if cursor_system_db:
213
            cursor_system_db.close()
214
        if cnx_system_db:
215
            cnx_system_db.close()
216
        print(error_string)
217
        return error_string
218
219
    ####################################################################################################################
220
    # Step 4: get all equipments associated with the combined equipment
221
    ####################################################################################################################
222
    print("Step 4: get all equipments associated with the combined equipment")
223
224
    equipment_list = list()
225
226
    try:
227
        cursor_system_db.execute(" SELECT e.id, e.name "
228
                                 " FROM tbl_equipments e, tbl_combined_equipments_equipments ce "
229
                                 " WHERE e.id = ce.equipment_id "
230
                                 "       AND e.is_input_counted = 1 "
231
                                 "       AND ce.combined_equipment_id = %s ",
232
                                 (combined_equipment['id'],))
233
        rows_equipments = cursor_system_db.fetchall()
234
235
        if rows_equipments is not None and len(rows_equipments) > 0:
236
            for row in rows_equipments:
237
                equipment_list.append({"id": row[0],
238
                                       "name": row[1]})
239
240
    except Exception as e:
241
        error_string = "Error in step 4 of combined_equipment_energy_input_category.worker " + str(e)
242
        print(error_string)
243
        return error_string
244
    finally:
245
        if cursor_system_db:
246
            cursor_system_db.close()
247
        if cnx_system_db:
248
            cnx_system_db.close()
249
250
    ####################################################################################################################
251
    # stop to the next combined equipment if this combined equipment is empty
252
    ####################################################################################################################
253
    if (meter_list is None or len(meter_list) == 0) and \
254
            (virtual_meter_list is None or len(virtual_meter_list) == 0) and \
255
            (offline_meter_list is None or len(offline_meter_list) == 0) and \
256
            (equipment_list is None or len(equipment_list) == 0):
257
        print("This is an empty combined equipment ")
258
        return None
259
260
    ####################################################################################################################
261
    # Step 5: determine start datetime and end datetime to aggregate
262
    ####################################################################################################################
263
    print("Step 5: determine start datetime and end datetime to aggregate")
264
    cnx_energy_db = None
265
    cursor_energy_db = None
266
    try:
267
        cnx_energy_db = mysql.connector.connect(**config.myems_energy_db)
268
        cursor_energy_db = cnx_energy_db.cursor()
269
    except Exception as e:
270
        error_string = "Error in step 5.1 of combined_equipment_energy_input_category.worker " + str(e)
271
        if cursor_energy_db:
272
            cursor_energy_db.close()
273
        if cnx_energy_db:
274
            cnx_energy_db.close()
275
        print(error_string)
276
        return error_string
277
278
    try:
279
        query = (" SELECT MAX(start_datetime_utc) "
280
                 " FROM tbl_combined_equipment_input_category_hourly "
281
                 " WHERE combined_equipment_id = %s ")
282
        cursor_energy_db.execute(query, (combined_equipment['id'],))
283
        row_datetime = cursor_energy_db.fetchone()
284
        start_datetime_utc = datetime.strptime(config.start_datetime_utc, '%Y-%m-%d %H:%M:%S')
285
        start_datetime_utc = start_datetime_utc.replace(minute=0, second=0, microsecond=0, tzinfo=None)
286
287
        if row_datetime is not None and len(row_datetime) > 0 and isinstance(row_datetime[0], datetime):
288
            # replace second and microsecond with 0
289
            # note: do not replace minute in case of calculating in half hourly
290
            start_datetime_utc = row_datetime[0].replace(second=0, microsecond=0, tzinfo=None)
291
            # start from the next time slot
292
            start_datetime_utc += timedelta(minutes=config.minutes_to_count)
293
294
        end_datetime_utc = datetime.utcnow().replace(second=0, microsecond=0, tzinfo=None)
295
296
        print("start_datetime_utc: " + start_datetime_utc.isoformat()[0:19]
297
              + "end_datetime_utc: " + end_datetime_utc.isoformat()[0:19])
298
299
    except Exception as e:
300
        error_string = "Error in step 5.2 of combined_equipment_energy_input_category.worker " + str(e)
301
        if cursor_energy_db:
302
            cursor_energy_db.close()
303
        if cnx_energy_db:
304
            cnx_energy_db.close()
305
        print(error_string)
306
        return error_string
307
308
    ####################################################################################################################
309
    # Step 6: for each meter in list, get energy input data from energy database
310
    ####################################################################################################################
311
    energy_meter_hourly = dict()
312
    try:
313
        if meter_list is not None and len(meter_list) > 0:
314
            for meter in meter_list:
315
                meter_id = str(meter['id'])
316
317
                query = (" SELECT start_datetime_utc, actual_value "
318
                         " FROM tbl_meter_hourly "
319
                         " WHERE meter_id = %s "
320
                         "       AND start_datetime_utc >= %s "
321
                         "       AND start_datetime_utc < %s "
322
                         " ORDER BY start_datetime_utc ")
323
                cursor_energy_db.execute(query, (meter_id, start_datetime_utc, end_datetime_utc,))
324
                rows_energy_values = cursor_energy_db.fetchall()
325
                if rows_energy_values is None or len(rows_energy_values) == 0:
326
                    energy_meter_hourly[meter_id] = None
327
                else:
328
                    energy_meter_hourly[meter_id] = dict()
329
                    for row_energy_value in rows_energy_values:
330
                        energy_meter_hourly[meter_id][row_energy_value[0]] = row_energy_value[1]
331
    except Exception as e:
332
        error_string = "Error in step 6.1 of combined_equipment_energy_input_category.worker " + str(e)
333
        if cursor_energy_db:
334
            cursor_energy_db.close()
335
        if cnx_energy_db:
336
            cnx_energy_db.close()
337
        print(error_string)
338
        return error_string
339
340
    ####################################################################################################################
341
    # Step 7: for each virtual meter in list, get energy input data from energy database
342
    ####################################################################################################################
343
    energy_virtual_meter_hourly = dict()
344
    if virtual_meter_list is not None and len(virtual_meter_list) > 0:
345
        try:
346
            for virtual_meter in virtual_meter_list:
347
                virtual_meter_id = str(virtual_meter['id'])
348
349
                query = (" SELECT start_datetime_utc, actual_value "
350
                         " FROM tbl_virtual_meter_hourly "
351
                         " WHERE virtual_meter_id = %s "
352
                         "       AND start_datetime_utc >= %s "
353
                         "       AND start_datetime_utc < %s "
354
                         " ORDER BY start_datetime_utc ")
355
                cursor_energy_db.execute(query, (virtual_meter_id, start_datetime_utc, end_datetime_utc,))
356
                rows_energy_values = cursor_energy_db.fetchall()
357
                if rows_energy_values is None or len(rows_energy_values) == 0:
358
                    energy_virtual_meter_hourly[virtual_meter_id] = None
359
                else:
360
                    energy_virtual_meter_hourly[virtual_meter_id] = dict()
361
                    for row_energy_value in rows_energy_values:
362
                        energy_virtual_meter_hourly[virtual_meter_id][row_energy_value[0]] = row_energy_value[1]
363
        except Exception as e:
364
            error_string = "Error in step 7.1 of combined_equipment_energy_input_category.worker " + str(e)
365
            if cursor_energy_db:
366
                cursor_energy_db.close()
367
            if cnx_energy_db:
368
                cnx_energy_db.close()
369
            print(error_string)
370
            return error_string
371
372
    ####################################################################################################################
373
    # Step 8: for each offline meter in list, get energy input data from energy database
374
    ####################################################################################################################
375
    energy_offline_meter_hourly = dict()
376
    if offline_meter_list is not None and len(offline_meter_list) > 0:
377
        try:
378
            for offline_meter in offline_meter_list:
379
                offline_meter_id = str(offline_meter['id'])
380
381
                query = (" SELECT start_datetime_utc, actual_value "
382
                         " FROM tbl_offline_meter_hourly "
383
                         " WHERE offline_meter_id = %s "
384
                         "       AND start_datetime_utc >= %s "
385
                         "       AND start_datetime_utc < %s "
386
                         " ORDER BY start_datetime_utc ")
387
                cursor_energy_db.execute(query, (offline_meter_id, start_datetime_utc, end_datetime_utc,))
388
                rows_energy_values = cursor_energy_db.fetchall()
389
                if rows_energy_values is None or len(rows_energy_values) == 0:
390
                    energy_offline_meter_hourly[offline_meter_id] = None
391
                else:
392
                    energy_offline_meter_hourly[offline_meter_id] = dict()
393
                    for row_energy_value in rows_energy_values:
394
                        energy_offline_meter_hourly[offline_meter_id][row_energy_value[0]] = row_energy_value[1]
395
396
        except Exception as e:
397
            error_string = "Error in step 8.1 of combined_equipment_energy_input_category.worker " + str(e)
398
            if cursor_energy_db:
399
                cursor_energy_db.close()
400
            if cnx_energy_db:
401
                cnx_energy_db.close()
402
            print(error_string)
403
            return error_string
404
405
    ####################################################################################################################
406
    # Step 9: for each equipment in list, get energy input data from energy database
407
    ####################################################################################################################
408
    energy_equipment_hourly = dict()
409
    if equipment_list is not None and len(equipment_list) > 0:
410
        try:
411
            for equipment in equipment_list:
412
                equipment_id = str(equipment['id'])
413
                query = (" SELECT start_datetime_utc, energy_category_id, actual_value "
414
                         " FROM tbl_equipment_input_category_hourly "
415
                         " WHERE equipment_id = %s "
416
                         "       AND start_datetime_utc >= %s "
417
                         "       AND start_datetime_utc < %s "
418
                         " ORDER BY start_datetime_utc ")
419
                cursor_energy_db.execute(query, (equipment_id, start_datetime_utc, end_datetime_utc,))
420
                rows_energy_values = cursor_energy_db.fetchall()
421
                if rows_energy_values is None or len(rows_energy_values) == 0:
422
                    energy_equipment_hourly[equipment_id] = None
423
                else:
424
                    energy_equipment_hourly[equipment_id] = dict()
425
                    for row_value in rows_energy_values:
426
                        current_datetime_utc = row_value[0]
427
                        if current_datetime_utc not in energy_equipment_hourly[equipment_id]:
428
                            energy_equipment_hourly[equipment_id][current_datetime_utc] = dict()
429
                        energy_category_id = row_value[1]
430
                        actual_value = row_value[2]
431
                        energy_equipment_hourly[equipment_id][current_datetime_utc][energy_category_id] = \
432
                            actual_value
433
        except Exception as e:
434
            error_string = "Error in step 9 of combined_equipment_energy_input_category.worker " + str(e)
435
            if cursor_energy_db:
436
                cursor_energy_db.close()
437
            if cnx_energy_db:
438
                cnx_energy_db.close()
439
            print(error_string)
440
            return error_string
441
442
    ####################################################################################################################
443
    # Step 10: determine common time slot to aggregate
444
    ####################################################################################################################
445
446
    common_start_datetime_utc = start_datetime_utc
447
    common_end_datetime_utc = end_datetime_utc
448
449
    print("Getting common time slot of energy values for all meters")
450
    if energy_meter_hourly is not None and len(energy_meter_hourly) > 0:
451
        for meter_id, energy_hourly in energy_meter_hourly.items():
452
            if energy_hourly is None or len(energy_hourly) == 0:
453
                common_start_datetime_utc = None
454
                common_end_datetime_utc = None
455
                break
456
            else:
457
                if common_start_datetime_utc < min(energy_hourly.keys()):
458
                    common_start_datetime_utc = min(energy_hourly.keys())
459
                if common_end_datetime_utc > max(energy_hourly.keys()):
460
                    common_end_datetime_utc = max(energy_hourly.keys())
461
462
    print("Getting common time slot of energy values for all virtual meters")
463
    if common_start_datetime_utc is not None and common_end_datetime_utc is not None:
464
        if energy_virtual_meter_hourly is not None and len(energy_virtual_meter_hourly) > 0:
465
            for meter_id, energy_hourly in energy_virtual_meter_hourly.items():
466
                if energy_hourly is None or len(energy_hourly) == 0:
467
                    common_start_datetime_utc = None
468
                    common_end_datetime_utc = None
469
                    break
470
                else:
471
                    if common_start_datetime_utc < min(energy_hourly.keys()):
472
                        common_start_datetime_utc = min(energy_hourly.keys())
473
                    if common_end_datetime_utc > max(energy_hourly.keys()):
474
                        common_end_datetime_utc = max(energy_hourly.keys())
475
476
    print("Getting common time slot of energy values for all offline meters")
477
    if common_start_datetime_utc is not None and common_end_datetime_utc is not None:
478
        if energy_offline_meter_hourly is not None and len(energy_offline_meter_hourly) > 0:
479
            for meter_id, energy_hourly in energy_offline_meter_hourly.items():
480
                if energy_hourly is None or len(energy_hourly) == 0:
481
                    common_start_datetime_utc = None
482
                    common_end_datetime_utc = None
483
                    break
484
                else:
485
                    if common_start_datetime_utc < min(energy_hourly.keys()):
486
                        common_start_datetime_utc = min(energy_hourly.keys())
487
                    if common_end_datetime_utc > max(energy_hourly.keys()):
488
                        common_end_datetime_utc = max(energy_hourly.keys())
489
490
    print("Getting common time slot of energy values for all equipments...")
491
    if common_start_datetime_utc is not None and common_end_datetime_utc is not None:
492
        if energy_equipment_hourly is not None and len(energy_equipment_hourly) > 0:
493
            for equipment_id, energy_hourly in energy_equipment_hourly.items():
494
                if energy_hourly is None or len(energy_hourly) == 0:
495
                    common_start_datetime_utc = None
496
                    common_end_datetime_utc = None
497
                    break
498
                else:
499
                    if common_start_datetime_utc < min(energy_hourly.keys()):
500
                        common_start_datetime_utc = min(energy_hourly.keys())
501
                    if common_end_datetime_utc > max(energy_hourly.keys()):
502
                        common_end_datetime_utc = max(energy_hourly.keys())
503
504
    if (energy_meter_hourly is None or len(energy_meter_hourly) == 0) and \
505
            (energy_virtual_meter_hourly is None or len(energy_virtual_meter_hourly) == 0) and \
506
            (energy_offline_meter_hourly is None or len(energy_offline_meter_hourly) == 0) and \
507
            (energy_equipment_hourly is None or len(energy_equipment_hourly) == 0):
508
        # There isn't any energy data
509
        print("There isn't any energy data")
510
        # continue the for combined equipment loop to the next combined equipment
511
        print("continue the for combined equipment loop to the next combined equipment")
512
        if cursor_energy_db:
513
            cursor_energy_db.close()
514
        if cnx_energy_db:
515
            cnx_energy_db.close()
516
        return None
517
518
    print("common_start_datetime_utc: " + str(common_start_datetime_utc))
519
    print("common_end_datetime_utc: " + str(common_end_datetime_utc))
520
521
    ####################################################################################################################
522
    # Step 11: aggregate energy data in the common time slot by energy categories and hourly
523
    ####################################################################################################################
524
525
    print("Step 11: aggregate energy data in the common time slot by energy categories and hourly")
526
    aggregated_values = list()
527
    try:
528
        current_datetime_utc = common_start_datetime_utc
529
        while common_start_datetime_utc is not None \
530
                and common_end_datetime_utc is not None \
531
                and current_datetime_utc <= common_end_datetime_utc:
532
            aggregated_value = dict()
533
            aggregated_value['start_datetime_utc'] = current_datetime_utc
534
            aggregated_value['meta_data'] = dict()
535
536
            if meter_list is not None and len(meter_list) > 0:
537
                for meter in meter_list:
538
                    meter_id = str(meter['id'])
539
                    energy_category_id = meter['energy_category_id']
540
                    actual_value = energy_meter_hourly[meter_id].get(current_datetime_utc, Decimal(0.0))
541
                    aggregated_value['meta_data'][energy_category_id] = \
542
                        aggregated_value['meta_data'].get(energy_category_id, Decimal(0.0)) + actual_value
543
544
            if virtual_meter_list is not None and len(virtual_meter_list) > 0:
545
                for virtual_meter in virtual_meter_list:
546
                    virtual_meter_id = str(virtual_meter['id'])
547
                    energy_category_id = virtual_meter['energy_category_id']
548
                    actual_value = energy_virtual_meter_hourly[virtual_meter_id].get(current_datetime_utc, Decimal(0.0))
549
                    aggregated_value['meta_data'][energy_category_id] = \
550
                        aggregated_value['meta_data'].get(energy_category_id, Decimal(0.0)) + actual_value
551
552
            if offline_meter_list is not None and len(offline_meter_list) > 0:
553
                for offline_meter in offline_meter_list:
554
                    offline_meter_id = str(offline_meter['id'])
555
                    energy_category_id = offline_meter['energy_category_id']
556
                    actual_value = energy_offline_meter_hourly[offline_meter_id].get(current_datetime_utc, Decimal(0.0))
557
                    aggregated_value['meta_data'][energy_category_id] = \
558
                        aggregated_value['meta_data'].get(energy_category_id, Decimal(0.0)) + actual_value
559
560
            if equipment_list is not None and len(equipment_list) > 0:
561
                for equipment in equipment_list:
562
                    equipment_id = str(equipment['id'])
563
                    meta_data_dict = energy_equipment_hourly[equipment_id].get(current_datetime_utc, None)
564
                    if meta_data_dict is not None and len(meta_data_dict) > 0:
565
                        for energy_category_id, actual_value in meta_data_dict.items():
566
                            aggregated_value['meta_data'][energy_category_id] = \
567
                                aggregated_value['meta_data'].get(energy_category_id, Decimal(0.0)) + actual_value
568
569
            aggregated_values.append(aggregated_value)
570
571
            current_datetime_utc += timedelta(minutes=config.minutes_to_count)
572
573
    except Exception as e:
574
        error_string = "Error in step 11 of combined_equipment_energy_input_category.worker " + str(e)
575
        if cursor_energy_db:
576
            cursor_energy_db.close()
577
        if cnx_energy_db:
578
            cnx_energy_db.close()
579
        print(error_string)
580
        return error_string
581
582
    ####################################################################################################################
583
    # Step 12: save energy data to energy database
584
    ####################################################################################################################
585
    print("Step 12: save energy data to energy database")
586
587
    while len(aggregated_values) > 0:
588
        insert_100 = aggregated_values[:100]
589
        aggregated_values = aggregated_values[100:]
590
        try:
591
            add_values = (" INSERT INTO tbl_combined_equipment_input_category_hourly "
592
                          "             (combined_equipment_id, "
593
                          "              energy_category_id, "
594
                          "              start_datetime_utc, "
595
                          "              actual_value) "
596
                          " VALUES  ")
597
598
            for aggregated_value in insert_100:
599
                for energy_category_id, actual_value in aggregated_value['meta_data'].items():
600
                    add_values += " (" + str(combined_equipment['id']) + ","
601
                    add_values += " " + str(energy_category_id) + ","
602
                    add_values += "'" + aggregated_value['start_datetime_utc'].isoformat()[0:19] + "',"
603
                    add_values += str(actual_value) + "), "
604
            # print("add_values:" + add_values)
605
            # trim ", " at the end of string and then execute
606
            cursor_energy_db.execute(add_values[:-2])
607
            cnx_energy_db.commit()
608
609
        except Exception as e:
610
            error_string = "Error in step 12.1 of combined_equipment_energy_input_category.worker " + str(e)
611
            print(error_string)
612
            if cursor_energy_db:
613
                cursor_energy_db.close()
614
            if cnx_energy_db:
615
                cnx_energy_db.close()
616
            return error_string
617
618
    if cursor_energy_db:
619
        cursor_energy_db.close()
620
    if cnx_energy_db:
621
        cnx_energy_db.close()
622
    return None
623

myems-aggregation/combined_equipment_energy_output_category.py 1 location

@@ 110-622 (lines=513) @@
107
# NOTE: returns None or the error string because that the logger object cannot be passed in as parameter
108
########################################################################################################################
109
110
def worker(combined_equipment):
111
    ####################################################################################################################
112
    # Step 1: get all output meters associated with the combined equipment
113
    ####################################################################################################################
114
    print("Step 1: get all output meters associated with the combined equipment " + str(combined_equipment['name']))
115
116
    meter_list = list()
117
    cnx_system_db = None
118
    cursor_system_db = None
119
    try:
120
        cnx_system_db = mysql.connector.connect(**config.myems_system_db)
121
        cursor_system_db = cnx_system_db.cursor()
122
    except Exception as e:
123
        error_string = "Error in step 1.1 of combined_equipment_energy_output_category.worker " + str(e)
124
        if cursor_system_db:
125
            cursor_system_db.close()
126
        if cnx_system_db:
127
            cnx_system_db.close()
128
        print(error_string)
129
        return error_string
130
131
    try:
132
        cursor_system_db.execute(" SELECT m.id, m.name, m.energy_category_id "
133
                                 " FROM tbl_meters m, tbl_combined_equipments_meters em "
134
                                 " WHERE m.id = em.meter_id "
135
                                 "       AND m.is_counted = 1 "
136
                                 "       AND em.is_output = 1 "
137
                                 "       AND em.combined_equipment_id = %s ",
138
                                 (combined_equipment['id'],))
139
        rows_meters = cursor_system_db.fetchall()
140
141
        if rows_meters is not None and len(rows_meters) > 0:
142
            for row in rows_meters:
143
                meter_list.append({"id": row[0],
144
                                   "name": row[1],
145
                                   "energy_category_id": row[2]})
146
147
    except Exception as e:
148
        error_string = "Error in step 1.2 of combined_equipment_energy_output_category.worker " + str(e)
149
        if cursor_system_db:
150
            cursor_system_db.close()
151
        if cnx_system_db:
152
            cnx_system_db.close()
153
        print(error_string)
154
        return error_string
155
156
    ####################################################################################################################
157
    # Step 2: get all output virtual meters associated with the combined equipment
158
    ####################################################################################################################
159
    print("Step 2: get all output virtual meters associated with the combined equipment")
160
    virtual_meter_list = list()
161
162
    try:
163
        cursor_system_db.execute(" SELECT m.id, m.name, m.energy_category_id "
164
                                 " FROM tbl_virtual_meters m, tbl_combined_equipments_virtual_meters em "
165
                                 " WHERE m.id = em.virtual_meter_id "
166
                                 "       AND m.is_counted = 1 "
167
                                 "       AND em.is_output = 1 "
168
                                 "       AND em.combined_equipment_id = %s ",
169
                                 (combined_equipment['id'],))
170
        rows_virtual_meters = cursor_system_db.fetchall()
171
172
        if rows_virtual_meters is not None and len(rows_virtual_meters) > 0:
173
            for row in rows_virtual_meters:
174
                virtual_meter_list.append({"id": row[0],
175
                                           "name": row[1],
176
                                           "energy_category_id": row[2]})
177
178
    except Exception as e:
179
        error_string = "Error in step 2.1 of combined_equipment_energy_output_category.worker " + str(e)
180
        if cursor_system_db:
181
            cursor_system_db.close()
182
        if cnx_system_db:
183
            cnx_system_db.close()
184
        print(error_string)
185
        return error_string
186
187
    ####################################################################################################################
188
    # Step 3: get all output offline meters associated with the combined equipment
189
    ####################################################################################################################
190
    print("Step 3: get all output offline meters associated with the combined equipment")
191
192
    offline_meter_list = list()
193
194
    try:
195
        cursor_system_db.execute(" SELECT m.id, m.name, m.energy_category_id "
196
                                 " FROM tbl_offline_meters m, tbl_combined_equipments_offline_meters em "
197
                                 " WHERE m.id = em.offline_meter_id "
198
                                 "       AND m.is_counted = 1 "
199
                                 "       AND em.is_output = 1 "
200
                                 "       AND em.combined_equipment_id = %s ",
201
                                 (combined_equipment['id'],))
202
        rows_offline_meters = cursor_system_db.fetchall()
203
204
        if rows_offline_meters is not None and len(rows_offline_meters) > 0:
205
            for row in rows_offline_meters:
206
                offline_meter_list.append({"id": row[0],
207
                                           "name": row[1],
208
                                           "energy_category_id": row[2]})
209
210
    except Exception as e:
211
        error_string = "Error in step 3.1 of combined_equipment_energy_output_category.worker " + str(e)
212
        if cursor_system_db:
213
            cursor_system_db.close()
214
        if cnx_system_db:
215
            cnx_system_db.close()
216
        print(error_string)
217
        return error_string
218
219
    ####################################################################################################################
220
    # Step 4: get all equipments associated with the combined equipment
221
    ####################################################################################################################
222
    print("Step 4: get all equipments associated with the combined equipment")
223
224
    equipment_list = list()
225
226
    try:
227
        cursor_system_db.execute(" SELECT e.id, e.name "
228
                                 " FROM tbl_equipments e, tbl_combined_equipments_equipments ce "
229
                                 " WHERE e.id = ce.equipment_id "
230
                                 "       AND e.is_output_counted = 1 "
231
                                 "       AND ce.combined_equipment_id = %s ",
232
                                 (combined_equipment['id'],))
233
        rows_equipments = cursor_system_db.fetchall()
234
235
        if rows_equipments is not None and len(rows_equipments) > 0:
236
            for row in rows_equipments:
237
                equipment_list.append({"id": row[0],
238
                                       "name": row[1]})
239
240
    except Exception as e:
241
        error_string = "Error in step 4 of combined_equipment_energy_output_category.worker " + str(e)
242
        print(error_string)
243
        return error_string
244
    finally:
245
        if cursor_system_db:
246
            cursor_system_db.close()
247
        if cnx_system_db:
248
            cnx_system_db.close()
249
250
    ####################################################################################################################
251
    # stop to the next combined equipment if this combined 3equipment is empty
252
    ####################################################################################################################
253
    if (meter_list is None or len(meter_list) == 0) and \
254
            (virtual_meter_list is None or len(virtual_meter_list) == 0) and \
255
            (offline_meter_list is None or len(offline_meter_list) == 0) and \
256
            (equipment_list is None or len(equipment_list) == 0):
257
        print("This is an empty combined equipment ")
258
        return None
259
260
    ####################################################################################################################
261
    # Step 5: determine start datetime and end datetime to aggregate
262
    ####################################################################################################################
263
    print("Step 5: determine start datetime and end datetime to aggregate")
264
    cnx_energy_db = None
265
    cursor_energy_db = None
266
    try:
267
        cnx_energy_db = mysql.connector.connect(**config.myems_energy_db)
268
        cursor_energy_db = cnx_energy_db.cursor()
269
    except Exception as e:
270
        error_string = "Error in step 5.1 of combined_equipment_energy_output_category.worker " + str(e)
271
        if cursor_energy_db:
272
            cursor_energy_db.close()
273
        if cnx_energy_db:
274
            cnx_energy_db.close()
275
        print(error_string)
276
        return error_string
277
278
    try:
279
        query = (" SELECT MAX(start_datetime_utc) "
280
                 " FROM tbl_combined_equipment_output_category_hourly "
281
                 " WHERE combined_equipment_id = %s ")
282
        cursor_energy_db.execute(query, (combined_equipment['id'],))
283
        row_datetime = cursor_energy_db.fetchone()
284
        start_datetime_utc = datetime.strptime(config.start_datetime_utc, '%Y-%m-%d %H:%M:%S')
285
        start_datetime_utc = start_datetime_utc.replace(minute=0, second=0, microsecond=0, tzinfo=None)
286
287
        if row_datetime is not None and len(row_datetime) > 0 and isinstance(row_datetime[0], datetime):
288
            # replace second and microsecond with 0
289
            # note: do not replace minute in case of calculating in half hourly
290
            start_datetime_utc = row_datetime[0].replace(second=0, microsecond=0, tzinfo=None)
291
            # start from the next time slot
292
            start_datetime_utc += timedelta(minutes=config.minutes_to_count)
293
294
        end_datetime_utc = datetime.utcnow().replace(second=0, microsecond=0, tzinfo=None)
295
296
        print("start_datetime_utc: " + start_datetime_utc.isoformat()[0:19]
297
              + "end_datetime_utc: " + end_datetime_utc.isoformat()[0:19])
298
299
    except Exception as e:
300
        error_string = "Error in step 5.2 of combined_equipment_energy_output_category.worker " + str(e)
301
        if cursor_energy_db:
302
            cursor_energy_db.close()
303
        if cnx_energy_db:
304
            cnx_energy_db.close()
305
        print(error_string)
306
        return error_string
307
308
    ####################################################################################################################
309
    # Step 6: for each meter in list, get energy output data from energy database
310
    ####################################################################################################################
311
    energy_meter_hourly = dict()
312
    try:
313
        if meter_list is not None and len(meter_list) > 0:
314
            for meter in meter_list:
315
                meter_id = str(meter['id'])
316
317
                query = (" SELECT start_datetime_utc, actual_value "
318
                         " FROM tbl_meter_hourly "
319
                         " WHERE meter_id = %s "
320
                         "       AND start_datetime_utc >= %s "
321
                         "       AND start_datetime_utc < %s "
322
                         " ORDER BY start_datetime_utc ")
323
                cursor_energy_db.execute(query, (meter_id, start_datetime_utc, end_datetime_utc,))
324
                rows_energy_values = cursor_energy_db.fetchall()
325
                if rows_energy_values is None or len(rows_energy_values) == 0:
326
                    energy_meter_hourly[meter_id] = None
327
                else:
328
                    energy_meter_hourly[meter_id] = dict()
329
                    for row_energy_value in rows_energy_values:
330
                        energy_meter_hourly[meter_id][row_energy_value[0]] = row_energy_value[1]
331
    except Exception as e:
332
        error_string = "Error in step 6.1 of combined_equipment_energy_output_category.worker " + str(e)
333
        if cursor_energy_db:
334
            cursor_energy_db.close()
335
        if cnx_energy_db:
336
            cnx_energy_db.close()
337
        print(error_string)
338
        return error_string
339
340
    ####################################################################################################################
341
    # Step 7: for each virtual meter in list, get energy output data from energy database
342
    ####################################################################################################################
343
    energy_virtual_meter_hourly = dict()
344
    if virtual_meter_list is not None and len(virtual_meter_list) > 0:
345
        try:
346
            for virtual_meter in virtual_meter_list:
347
                virtual_meter_id = str(virtual_meter['id'])
348
349
                query = (" SELECT start_datetime_utc, actual_value "
350
                         " FROM tbl_virtual_meter_hourly "
351
                         " WHERE virtual_meter_id = %s "
352
                         "       AND start_datetime_utc >= %s "
353
                         "       AND start_datetime_utc < %s "
354
                         " ORDER BY start_datetime_utc ")
355
                cursor_energy_db.execute(query, (virtual_meter_id, start_datetime_utc, end_datetime_utc,))
356
                rows_energy_values = cursor_energy_db.fetchall()
357
                if rows_energy_values is None or len(rows_energy_values) == 0:
358
                    energy_virtual_meter_hourly[virtual_meter_id] = None
359
                else:
360
                    energy_virtual_meter_hourly[virtual_meter_id] = dict()
361
                    for row_energy_value in rows_energy_values:
362
                        energy_virtual_meter_hourly[virtual_meter_id][row_energy_value[0]] = row_energy_value[1]
363
        except Exception as e:
364
            error_string = "Error in step 7.1 of combined_equipment_energy_output_category.worker " + str(e)
365
            if cursor_energy_db:
366
                cursor_energy_db.close()
367
            if cnx_energy_db:
368
                cnx_energy_db.close()
369
            print(error_string)
370
            return error_string
371
372
    ####################################################################################################################
373
    # Step 8: for each offline meter in list, get energy output data from energy database
374
    ####################################################################################################################
375
    energy_offline_meter_hourly = dict()
376
    if offline_meter_list is not None and len(offline_meter_list) > 0:
377
        try:
378
            for offline_meter in offline_meter_list:
379
                offline_meter_id = str(offline_meter['id'])
380
381
                query = (" SELECT start_datetime_utc, actual_value "
382
                         " FROM tbl_offline_meter_hourly "
383
                         " WHERE offline_meter_id = %s "
384
                         "       AND start_datetime_utc >= %s "
385
                         "       AND start_datetime_utc < %s "
386
                         " ORDER BY start_datetime_utc ")
387
                cursor_energy_db.execute(query, (offline_meter_id, start_datetime_utc, end_datetime_utc,))
388
                rows_energy_values = cursor_energy_db.fetchall()
389
                if rows_energy_values is None or len(rows_energy_values) == 0:
390
                    energy_offline_meter_hourly[offline_meter_id] = None
391
                else:
392
                    energy_offline_meter_hourly[offline_meter_id] = dict()
393
                    for row_energy_value in rows_energy_values:
394
                        energy_offline_meter_hourly[offline_meter_id][row_energy_value[0]] = row_energy_value[1]
395
396
        except Exception as e:
397
            error_string = "Error in step 8.1 of combined_equipment_energy_output_category.worker " + str(e)
398
            if cursor_energy_db:
399
                cursor_energy_db.close()
400
            if cnx_energy_db:
401
                cnx_energy_db.close()
402
            print(error_string)
403
            return error_string
404
405
    ####################################################################################################################
406
    # Step 9: for each equipment in list, get energy output data from energy database
407
    ####################################################################################################################
408
    energy_equipment_hourly = dict()
409
    if equipment_list is not None and len(equipment_list) > 0:
410
        try:
411
            for equipment in equipment_list:
412
                equipment_id = str(equipment['id'])
413
                query = (" SELECT start_datetime_utc, energy_category_id, actual_value "
414
                         " FROM tbl_equipment_output_category_hourly "
415
                         " WHERE equipment_id = %s "
416
                         "       AND start_datetime_utc >= %s "
417
                         "       AND start_datetime_utc < %s "
418
                         " ORDER BY start_datetime_utc ")
419
                cursor_energy_db.execute(query, (equipment_id, start_datetime_utc, end_datetime_utc,))
420
                rows_energy_values = cursor_energy_db.fetchall()
421
                if rows_energy_values is None or len(rows_energy_values) == 0:
422
                    energy_equipment_hourly[equipment_id] = None
423
                else:
424
                    energy_equipment_hourly[equipment_id] = dict()
425
                    for row_value in rows_energy_values:
426
                        current_datetime_utc = row_value[0]
427
                        if current_datetime_utc not in energy_equipment_hourly[equipment_id]:
428
                            energy_equipment_hourly[equipment_id][current_datetime_utc] = dict()
429
                        energy_category_id = row_value[1]
430
                        actual_value = row_value[2]
431
                        energy_equipment_hourly[equipment_id][current_datetime_utc][energy_category_id] = \
432
                            actual_value
433
        except Exception as e:
434
            error_string = "Error in step 9 of combined_equipment_energy_output_category.worker " + str(e)
435
            if cursor_energy_db:
436
                cursor_energy_db.close()
437
            if cnx_energy_db:
438
                cnx_energy_db.close()
439
            print(error_string)
440
            return error_string
441
442
    ####################################################################################################################
443
    # Step 10: determine common time slot to aggregate
444
    ####################################################################################################################
445
446
    common_start_datetime_utc = start_datetime_utc
447
    common_end_datetime_utc = end_datetime_utc
448
449
    print("Getting common time slot of energy values for all meters")
450
    if energy_meter_hourly is not None and len(energy_meter_hourly) > 0:
451
        for meter_id, energy_hourly in energy_meter_hourly.items():
452
            if energy_hourly is None or len(energy_hourly) == 0:
453
                common_start_datetime_utc = None
454
                common_end_datetime_utc = None
455
                break
456
            else:
457
                if common_start_datetime_utc < min(energy_hourly.keys()):
458
                    common_start_datetime_utc = min(energy_hourly.keys())
459
                if common_end_datetime_utc > max(energy_hourly.keys()):
460
                    common_end_datetime_utc = max(energy_hourly.keys())
461
462
    print("Getting common time slot of energy values for all virtual meters")
463
    if common_start_datetime_utc is not None and common_end_datetime_utc is not None:
464
        if energy_virtual_meter_hourly is not None and len(energy_virtual_meter_hourly) > 0:
465
            for meter_id, energy_hourly in energy_virtual_meter_hourly.items():
466
                if energy_hourly is None or len(energy_hourly) == 0:
467
                    common_start_datetime_utc = None
468
                    common_end_datetime_utc = None
469
                    break
470
                else:
471
                    if common_start_datetime_utc < min(energy_hourly.keys()):
472
                        common_start_datetime_utc = min(energy_hourly.keys())
473
                    if common_end_datetime_utc > max(energy_hourly.keys()):
474
                        common_end_datetime_utc = max(energy_hourly.keys())
475
476
    print("Getting common time slot of energy values for all offline meters")
477
    if common_start_datetime_utc is not None and common_end_datetime_utc is not None:
478
        if energy_offline_meter_hourly is not None and len(energy_offline_meter_hourly) > 0:
479
            for meter_id, energy_hourly in energy_offline_meter_hourly.items():
480
                if energy_hourly is None or len(energy_hourly) == 0:
481
                    common_start_datetime_utc = None
482
                    common_end_datetime_utc = None
483
                    break
484
                else:
485
                    if common_start_datetime_utc < min(energy_hourly.keys()):
486
                        common_start_datetime_utc = min(energy_hourly.keys())
487
                    if common_end_datetime_utc > max(energy_hourly.keys()):
488
                        common_end_datetime_utc = max(energy_hourly.keys())
489
490
    print("Getting common time slot of energy values for all equipments...")
491
    if common_start_datetime_utc is not None and common_end_datetime_utc is not None:
492
        if energy_equipment_hourly is not None and len(energy_equipment_hourly) > 0:
493
            for equipment_id, energy_hourly in energy_equipment_hourly.items():
494
                if energy_hourly is None or len(energy_hourly) == 0:
495
                    common_start_datetime_utc = None
496
                    common_end_datetime_utc = None
497
                    break
498
                else:
499
                    if common_start_datetime_utc < min(energy_hourly.keys()):
500
                        common_start_datetime_utc = min(energy_hourly.keys())
501
                    if common_end_datetime_utc > max(energy_hourly.keys()):
502
                        common_end_datetime_utc = max(energy_hourly.keys())
503
504
    if (energy_meter_hourly is None or len(energy_meter_hourly) == 0) and \
505
            (energy_virtual_meter_hourly is None or len(energy_virtual_meter_hourly) == 0) and \
506
            (energy_offline_meter_hourly is None or len(energy_offline_meter_hourly) == 0) and \
507
            (energy_equipment_hourly is None or len(energy_equipment_hourly) == 0):
508
        # There isn't any energy data
509
        print("There isn't any energy data")
510
        # continue the for combined equipment loop to the next combined equipment
511
        print("continue the for combined equipment loop to the next combined equipment")
512
        if cursor_energy_db:
513
            cursor_energy_db.close()
514
        if cnx_energy_db:
515
            cnx_energy_db.close()
516
        return None
517
518
    print("common_start_datetime_utc: " + str(common_start_datetime_utc))
519
    print("common_end_datetime_utc: " + str(common_end_datetime_utc))
520
521
    ####################################################################################################################
522
    # Step 11: aggregate energy data in the common time slot by energy categories and hourly
523
    ####################################################################################################################
524
525
    print("Step 11: aggregate energy data in the common time slot by energy categories and hourly")
526
    aggregated_values = list()
527
    try:
528
        current_datetime_utc = common_start_datetime_utc
529
        while common_start_datetime_utc is not None \
530
                and common_end_datetime_utc is not None \
531
                and current_datetime_utc <= common_end_datetime_utc:
532
            aggregated_value = dict()
533
            aggregated_value['start_datetime_utc'] = current_datetime_utc
534
            aggregated_value['meta_data'] = dict()
535
536
            if meter_list is not None and len(meter_list) > 0:
537
                for meter in meter_list:
538
                    meter_id = str(meter['id'])
539
                    energy_category_id = meter['energy_category_id']
540
                    actual_value = energy_meter_hourly[meter_id].get(current_datetime_utc, Decimal(0.0))
541
                    aggregated_value['meta_data'][energy_category_id] = \
542
                        aggregated_value['meta_data'].get(energy_category_id, Decimal(0.0)) + actual_value
543
544
            if virtual_meter_list is not None and len(virtual_meter_list) > 0:
545
                for virtual_meter in virtual_meter_list:
546
                    virtual_meter_id = str(virtual_meter['id'])
547
                    energy_category_id = virtual_meter['energy_category_id']
548
                    actual_value = energy_virtual_meter_hourly[virtual_meter_id].get(current_datetime_utc, Decimal(0.0))
549
                    aggregated_value['meta_data'][energy_category_id] = \
550
                        aggregated_value['meta_data'].get(energy_category_id, Decimal(0.0)) + actual_value
551
552
            if offline_meter_list is not None and len(offline_meter_list) > 0:
553
                for offline_meter in offline_meter_list:
554
                    offline_meter_id = str(offline_meter['id'])
555
                    energy_category_id = offline_meter['energy_category_id']
556
                    actual_value = energy_offline_meter_hourly[offline_meter_id].get(current_datetime_utc, Decimal(0.0))
557
                    aggregated_value['meta_data'][energy_category_id] = \
558
                        aggregated_value['meta_data'].get(energy_category_id, Decimal(0.0)) + actual_value
559
560
            if equipment_list is not None and len(equipment_list) > 0:
561
                for equipment in equipment_list:
562
                    equipment_id = str(equipment['id'])
563
                    meta_data_dict = energy_equipment_hourly[equipment_id].get(current_datetime_utc, None)
564
                    if meta_data_dict is not None and len(meta_data_dict) > 0:
565
                        for energy_category_id, actual_value in meta_data_dict.items():
566
                            aggregated_value['meta_data'][energy_category_id] = \
567
                                aggregated_value['meta_data'].get(energy_category_id, Decimal(0.0)) + actual_value
568
569
            aggregated_values.append(aggregated_value)
570
571
            current_datetime_utc += timedelta(minutes=config.minutes_to_count)
572
573
    except Exception as e:
574
        error_string = "Error in step 11 of combined_equipment_energy_output_category.worker " + str(e)
575
        if cursor_energy_db:
576
            cursor_energy_db.close()
577
        if cnx_energy_db:
578
            cnx_energy_db.close()
579
        print(error_string)
580
        return error_string
581
582
    ####################################################################################################################
583
    # Step 12: save energy data to energy database
584
    ####################################################################################################################
585
    print("Step 12: save energy data to energy database")
586
587
    while len(aggregated_values) > 0:
588
        insert_100 = aggregated_values[:100]
589
        aggregated_values = aggregated_values[100:]
590
        try:
591
            add_values = (" INSERT INTO tbl_combined_equipment_output_category_hourly "
592
                          "             (combined_equipment_id, "
593
                          "              energy_category_id, "
594
                          "              start_datetime_utc, "
595
                          "              actual_value) "
596
                          " VALUES  ")
597
598
            for aggregated_value in insert_100:
599
                for energy_category_id, actual_value in aggregated_value['meta_data'].items():
600
                    add_values += " (" + str(combined_equipment['id']) + ","
601
                    add_values += " " + str(energy_category_id) + ","
602
                    add_values += "'" + aggregated_value['start_datetime_utc'].isoformat()[0:19] + "',"
603
                    add_values += str(actual_value) + "), "
604
            # print("add_values:" + add_values)
605
            # trim ", " at the end of string and then execute
606
            cursor_energy_db.execute(add_values[:-2])
607
            cnx_energy_db.commit()
608
609
        except Exception as e:
610
            error_string = "Error in step 12.1 of combined_equipment_energy_output_category.worker " + str(e)
611
            print(error_string)
612
            if cursor_energy_db:
613
                cursor_energy_db.close()
614
            if cnx_energy_db:
615
                cnx_energy_db.close()
616
            return error_string
617
618
    if cursor_energy_db:
619
        cursor_energy_db.close()
620
    if cnx_energy_db:
621
        cnx_energy_db.close()
622
    return None
623

myems-aggregation/shopfloor_energy_input_item.py 1 location

@@ 110-622 (lines=513) @@
107
# NOTE: returns None or the error string because that the logger object cannot be passed in as parameter
108
########################################################################################################################
109
110
def worker(shopfloor):
111
    ####################################################################################################################
112
    # Step 1: get all input meters associated with the shopfloor
113
    ####################################################################################################################
114
    print("Step 1: get all input meters associated with the shopfloor " + str(shopfloor['name']))
115
116
    meter_list = list()
117
    cnx_system_db = None
118
    cursor_system_db = None
119
    try:
120
        cnx_system_db = mysql.connector.connect(**config.myems_system_db)
121
        cursor_system_db = cnx_system_db.cursor()
122
    except Exception as e:
123
        error_string = "Error in step 1.1 of shopfloor_energy_input_item.worker " + str(e)
124
        if cursor_system_db:
125
            cursor_system_db.close()
126
        if cnx_system_db:
127
            cnx_system_db.close()
128
        print(error_string)
129
        return error_string
130
131
    try:
132
        cursor_system_db.execute(" SELECT m.id, m.name, m.energy_item_id "
133
                                 " FROM tbl_meters m, tbl_shopfloors_meters tm "
134
                                 " WHERE m.id = tm.meter_id "
135
                                 "       AND m.is_counted = 1 "
136
                                 "       AND m.energy_item_id is NOT NULL "
137
                                 "       AND tm.shopfloor_id = %s ",
138
                                 (shopfloor['id'],))
139
        rows_meters = cursor_system_db.fetchall()
140
141
        if rows_meters is not None and len(rows_meters) > 0:
142
            for row in rows_meters:
143
                meter_list.append({"id": row[0],
144
                                   "name": row[1],
145
                                   "energy_item_id": row[2]})
146
147
    except Exception as e:
148
        error_string = "Error in step 1.2 of shopfloor_energy_input_item.worker " + str(e)
149
        if cursor_system_db:
150
            cursor_system_db.close()
151
        if cnx_system_db:
152
            cnx_system_db.close()
153
        print(error_string)
154
        return error_string
155
156
    ####################################################################################################################
157
    # Step 2: get all input virtual meters associated with the shopfloor
158
    ####################################################################################################################
159
    print("Step 2: get all input virtual meters associated with the shopfloor")
160
    virtual_meter_list = list()
161
162
    try:
163
        cursor_system_db.execute(" SELECT m.id, m.name, m.energy_item_id "
164
                                 " FROM tbl_virtual_meters m, tbl_shopfloors_virtual_meters tm "
165
                                 " WHERE m.id = tm.virtual_meter_id "
166
                                 "       AND m.energy_item_id is NOT NULL "
167
                                 "       AND m.is_counted = 1 "
168
                                 "       AND tm.shopfloor_id = %s ",
169
                                 (shopfloor['id'],))
170
        rows_virtual_meters = cursor_system_db.fetchall()
171
172
        if rows_virtual_meters is not None and len(rows_virtual_meters) > 0:
173
            for row in rows_virtual_meters:
174
                virtual_meter_list.append({"id": row[0],
175
                                           "name": row[1],
176
                                           "energy_item_id": row[2]})
177
178
    except Exception as e:
179
        error_string = "Error in step 2.1 of shopfloor_energy_input_item.worker " + str(e)
180
        if cursor_system_db:
181
            cursor_system_db.close()
182
        if cnx_system_db:
183
            cnx_system_db.close()
184
        print(error_string)
185
        return error_string
186
187
    ####################################################################################################################
188
    # Step 3: get all input offline meters associated with the shopfloor
189
    ####################################################################################################################
190
    print("Step 3: get all input offline meters associated with the shopfloor")
191
192
    offline_meter_list = list()
193
194
    try:
195
        cursor_system_db.execute(" SELECT m.id, m.name, m.energy_item_id "
196
                                 " FROM tbl_offline_meters m, tbl_shopfloors_offline_meters tm "
197
                                 " WHERE m.id = tm.offline_meter_id "
198
                                 "       AND m.energy_item_id is NOT NULL "
199
                                 "       AND m.is_counted = 1 "
200
                                 "       AND tm.shopfloor_id = %s ",
201
                                 (shopfloor['id'],))
202
        rows_offline_meters = cursor_system_db.fetchall()
203
204
        if rows_offline_meters is not None and len(rows_offline_meters) > 0:
205
            for row in rows_offline_meters:
206
                offline_meter_list.append({"id": row[0],
207
                                           "name": row[1],
208
                                           "energy_item_id": row[2]})
209
210
    except Exception as e:
211
        error_string = "Error in step 3.1 of shopfloor_energy_input_item.worker " + str(e)
212
        if cursor_system_db:
213
            cursor_system_db.close()
214
        if cnx_system_db:
215
            cnx_system_db.close()
216
        print(error_string)
217
        return error_string
218
219
    ####################################################################################################################
220
    # Step 4: get all equipments associated with the shopfloor
221
    ####################################################################################################################
222
    print("Step 4: get all equipments associated with the shopfloor")
223
224
    equipment_list = list()
225
226
    try:
227
        cursor_system_db.execute(" SELECT e.id, e.name "
228
                                 " FROM tbl_equipments e, tbl_shopfloors_equipments se "
229
                                 " WHERE e.id = se.equipment_id "
230
                                 "       AND e.is_input_counted = 1 "
231
                                 "       AND se.shopfloor_id = %s ",
232
                                 (shopfloor['id'],))
233
        rows_equipments = cursor_system_db.fetchall()
234
235
        if rows_equipments is not None and len(rows_equipments) > 0:
236
            for row in rows_equipments:
237
                equipment_list.append({"id": row[0],
238
                                       "name": row[1]})
239
240
    except Exception as e:
241
        error_string = "Error in step 4 of shopfloor_energy_input_item.worker " + str(e)
242
        print(error_string)
243
        return error_string
244
    finally:
245
        if cursor_system_db:
246
            cursor_system_db.close()
247
        if cnx_system_db:
248
            cnx_system_db.close()
249
250
    ####################################################################################################################
251
    # stop to the next shopfloor if this shopfloor is empty
252
    ####################################################################################################################
253
    if (meter_list is None or len(meter_list) == 0) and \
254
            (virtual_meter_list is None or len(virtual_meter_list) == 0) and \
255
            (offline_meter_list is None or len(offline_meter_list) == 0) and \
256
            (equipment_list is None or len(equipment_list) == 0):
257
        print("This is an empty shopfloor ")
258
        return None
259
260
    ####################################################################################################################
261
    # Step 5: determine start datetime and end datetime to aggregate
262
    ####################################################################################################################
263
    print("Step 5: determine start datetime and end datetime to aggregate")
264
    cnx_energy_db = None
265
    cursor_energy_db = None
266
    try:
267
        cnx_energy_db = mysql.connector.connect(**config.myems_energy_db)
268
        cursor_energy_db = cnx_energy_db.cursor()
269
    except Exception as e:
270
        error_string = "Error in step 5.1 of shopfloor_energy_input_item.worker " + str(e)
271
        if cursor_energy_db:
272
            cursor_energy_db.close()
273
        if cnx_energy_db:
274
            cnx_energy_db.close()
275
        print(error_string)
276
        return error_string
277
278
    try:
279
        query = (" SELECT MAX(start_datetime_utc) "
280
                 " FROM tbl_shopfloor_input_item_hourly "
281
                 " WHERE shopfloor_id = %s ")
282
        cursor_energy_db.execute(query, (shopfloor['id'],))
283
        row_datetime = cursor_energy_db.fetchone()
284
        start_datetime_utc = datetime.strptime(config.start_datetime_utc, '%Y-%m-%d %H:%M:%S')
285
        start_datetime_utc = start_datetime_utc.replace(minute=0, second=0, microsecond=0, tzinfo=None)
286
287
        if row_datetime is not None and len(row_datetime) > 0 and isinstance(row_datetime[0], datetime):
288
            # replace second and microsecond with 0
289
            # note: do not replace minute in case of calculating in half hourly
290
            start_datetime_utc = row_datetime[0].replace(second=0, microsecond=0, tzinfo=None)
291
            # start from the next time slot
292
            start_datetime_utc += timedelta(minutes=config.minutes_to_count)
293
294
        end_datetime_utc = datetime.utcnow().replace(second=0, microsecond=0, tzinfo=None)
295
296
        print("start_datetime_utc: " + start_datetime_utc.isoformat()[0:19]
297
              + "end_datetime_utc: " + end_datetime_utc.isoformat()[0:19])
298
299
    except Exception as e:
300
        error_string = "Error in step 5.2 of shopfloor_energy_input_item.worker " + str(e)
301
        if cursor_energy_db:
302
            cursor_energy_db.close()
303
        if cnx_energy_db:
304
            cnx_energy_db.close()
305
        print(error_string)
306
        return error_string
307
308
    ####################################################################################################################
309
    # Step 6: for each meter in list, get energy input data from energy database
310
    ####################################################################################################################
311
    energy_meter_hourly = dict()
312
    try:
313
        if meter_list is not None and len(meter_list) > 0:
314
            for meter in meter_list:
315
                meter_id = str(meter['id'])
316
317
                query = (" SELECT start_datetime_utc, actual_value "
318
                         " FROM tbl_meter_hourly "
319
                         " WHERE meter_id = %s "
320
                         "       AND start_datetime_utc >= %s "
321
                         "       AND start_datetime_utc < %s "
322
                         " ORDER BY start_datetime_utc ")
323
                cursor_energy_db.execute(query, (meter_id, start_datetime_utc, end_datetime_utc,))
324
                rows_energy_values = cursor_energy_db.fetchall()
325
                if rows_energy_values is None or len(rows_energy_values) == 0:
326
                    energy_meter_hourly[meter_id] = None
327
                else:
328
                    energy_meter_hourly[meter_id] = dict()
329
                    for row_energy_value in rows_energy_values:
330
                        energy_meter_hourly[meter_id][row_energy_value[0]] = row_energy_value[1]
331
    except Exception as e:
332
        error_string = "Error in step 6.1 of shopfloor_energy_input_item.worker " + str(e)
333
        if cursor_energy_db:
334
            cursor_energy_db.close()
335
        if cnx_energy_db:
336
            cnx_energy_db.close()
337
        print(error_string)
338
        return error_string
339
340
    ####################################################################################################################
341
    # Step 7: for each virtual meter in list, get energy input data from energy database
342
    ####################################################################################################################
343
    energy_virtual_meter_hourly = dict()
344
    if virtual_meter_list is not None and len(virtual_meter_list) > 0:
345
        try:
346
            for virtual_meter in virtual_meter_list:
347
                virtual_meter_id = str(virtual_meter['id'])
348
349
                query = (" SELECT start_datetime_utc, actual_value "
350
                         " FROM tbl_virtual_meter_hourly "
351
                         " WHERE virtual_meter_id = %s "
352
                         "       AND start_datetime_utc >= %s "
353
                         "       AND start_datetime_utc < %s "
354
                         " ORDER BY start_datetime_utc ")
355
                cursor_energy_db.execute(query, (virtual_meter_id, start_datetime_utc, end_datetime_utc,))
356
                rows_energy_values = cursor_energy_db.fetchall()
357
                if rows_energy_values is None or len(rows_energy_values) == 0:
358
                    energy_virtual_meter_hourly[virtual_meter_id] = None
359
                else:
360
                    energy_virtual_meter_hourly[virtual_meter_id] = dict()
361
                    for row_energy_value in rows_energy_values:
362
                        energy_virtual_meter_hourly[virtual_meter_id][row_energy_value[0]] = row_energy_value[1]
363
        except Exception as e:
364
            error_string = "Error in step 7.1 of shopfloor_energy_input_item.worker " + str(e)
365
            if cursor_energy_db:
366
                cursor_energy_db.close()
367
            if cnx_energy_db:
368
                cnx_energy_db.close()
369
            print(error_string)
370
            return error_string
371
372
    ####################################################################################################################
373
    # Step 8: for each offline meter in list, get energy input data from energy database
374
    ####################################################################################################################
375
    energy_offline_meter_hourly = dict()
376
    if offline_meter_list is not None and len(offline_meter_list) > 0:
377
        try:
378
            for offline_meter in offline_meter_list:
379
                offline_meter_id = str(offline_meter['id'])
380
381
                query = (" SELECT start_datetime_utc, actual_value "
382
                         " FROM tbl_offline_meter_hourly "
383
                         " WHERE offline_meter_id = %s "
384
                         "       AND start_datetime_utc >= %s "
385
                         "       AND start_datetime_utc < %s "
386
                         " ORDER BY start_datetime_utc ")
387
                cursor_energy_db.execute(query, (offline_meter_id, start_datetime_utc, end_datetime_utc,))
388
                rows_energy_values = cursor_energy_db.fetchall()
389
                if rows_energy_values is None or len(rows_energy_values) == 0:
390
                    energy_offline_meter_hourly[offline_meter_id] = None
391
                else:
392
                    energy_offline_meter_hourly[offline_meter_id] = dict()
393
                    for row_energy_value in rows_energy_values:
394
                        energy_offline_meter_hourly[offline_meter_id][row_energy_value[0]] = row_energy_value[1]
395
396
        except Exception as e:
397
            error_string = "Error in step 8.1 of shopfloor_energy_input_item.worker " + str(e)
398
            if cursor_energy_db:
399
                cursor_energy_db.close()
400
            if cnx_energy_db:
401
                cnx_energy_db.close()
402
            print(error_string)
403
            return error_string
404
405
    ####################################################################################################################
406
    # Step 9: for each equipment in list, get energy input data from energy database
407
    ####################################################################################################################
408
    energy_equipment_hourly = dict()
409
    if equipment_list is not None and len(equipment_list) > 0:
410
        try:
411
            for equipment in equipment_list:
412
                equipment_id = str(equipment['id'])
413
                query = (" SELECT start_datetime_utc, energy_item_id, actual_value "
414
                         " FROM tbl_equipment_input_item_hourly "
415
                         " WHERE equipment_id = %s "
416
                         "       AND start_datetime_utc >= %s "
417
                         "       AND start_datetime_utc < %s "
418
                         " ORDER BY start_datetime_utc ")
419
                cursor_energy_db.execute(query, (equipment_id, start_datetime_utc, end_datetime_utc,))
420
                rows_energy_values = cursor_energy_db.fetchall()
421
                if rows_energy_values is None or len(rows_energy_values) == 0:
422
                    energy_equipment_hourly[equipment_id] = None
423
                else:
424
                    energy_equipment_hourly[equipment_id] = dict()
425
                    for row_value in rows_energy_values:
426
                        current_datetime_utc = row_value[0]
427
                        if current_datetime_utc not in energy_equipment_hourly[equipment_id]:
428
                            energy_equipment_hourly[equipment_id][current_datetime_utc] = dict()
429
                        energy_item_id = row_value[1]
430
                        actual_value = row_value[2]
431
                        energy_equipment_hourly[equipment_id][current_datetime_utc][energy_item_id] = \
432
                            actual_value
433
        except Exception as e:
434
            error_string = "Error in step 9 of shopfloor_energy_input_item.worker " + str(e)
435
            if cursor_energy_db:
436
                cursor_energy_db.close()
437
            if cnx_energy_db:
438
                cnx_energy_db.close()
439
            print(error_string)
440
            return error_string
441
442
    ####################################################################################################################
443
    # Step 10: determine common time slot to aggregate
444
    ####################################################################################################################
445
446
    common_start_datetime_utc = start_datetime_utc
447
    common_end_datetime_utc = end_datetime_utc
448
449
    print("Getting common time slot of energy values for all meters")
450
    if energy_meter_hourly is not None and len(energy_meter_hourly) > 0:
451
        for meter_id, energy_hourly in energy_meter_hourly.items():
452
            if energy_hourly is None or len(energy_hourly) == 0:
453
                common_start_datetime_utc = None
454
                common_end_datetime_utc = None
455
                break
456
            else:
457
                if common_start_datetime_utc < min(energy_hourly.keys()):
458
                    common_start_datetime_utc = min(energy_hourly.keys())
459
                if common_end_datetime_utc > max(energy_hourly.keys()):
460
                    common_end_datetime_utc = max(energy_hourly.keys())
461
462
    print("Getting common time slot of energy values for all virtual meters")
463
    if common_start_datetime_utc is not None and common_end_datetime_utc is not None:
464
        if energy_virtual_meter_hourly is not None and len(energy_virtual_meter_hourly) > 0:
465
            for meter_id, energy_hourly in energy_virtual_meter_hourly.items():
466
                if energy_hourly is None or len(energy_hourly) == 0:
467
                    common_start_datetime_utc = None
468
                    common_end_datetime_utc = None
469
                    break
470
                else:
471
                    if common_start_datetime_utc < min(energy_hourly.keys()):
472
                        common_start_datetime_utc = min(energy_hourly.keys())
473
                    if common_end_datetime_utc > max(energy_hourly.keys()):
474
                        common_end_datetime_utc = max(energy_hourly.keys())
475
476
    print("Getting common time slot of energy values for all offline meters")
477
    if common_start_datetime_utc is not None and common_end_datetime_utc is not None:
478
        if energy_offline_meter_hourly is not None and len(energy_offline_meter_hourly) > 0:
479
            for meter_id, energy_hourly in energy_offline_meter_hourly.items():
480
                if energy_hourly is None or len(energy_hourly) == 0:
481
                    common_start_datetime_utc = None
482
                    common_end_datetime_utc = None
483
                    break
484
                else:
485
                    if common_start_datetime_utc < min(energy_hourly.keys()):
486
                        common_start_datetime_utc = min(energy_hourly.keys())
487
                    if common_end_datetime_utc > max(energy_hourly.keys()):
488
                        common_end_datetime_utc = max(energy_hourly.keys())
489
490
    print("Getting common time slot of energy values for all equipments...")
491
    if common_start_datetime_utc is not None and common_end_datetime_utc is not None:
492
        if energy_equipment_hourly is not None and len(energy_equipment_hourly) > 0:
493
            for equipment_id, energy_hourly in energy_equipment_hourly.items():
494
                if energy_hourly is None or len(energy_hourly) == 0:
495
                    common_start_datetime_utc = None
496
                    common_end_datetime_utc = None
497
                    break
498
                else:
499
                    if common_start_datetime_utc < min(energy_hourly.keys()):
500
                        common_start_datetime_utc = min(energy_hourly.keys())
501
                    if common_end_datetime_utc > max(energy_hourly.keys()):
502
                        common_end_datetime_utc = max(energy_hourly.keys())
503
504
    if (energy_meter_hourly is None or len(energy_meter_hourly) == 0) and \
505
            (energy_virtual_meter_hourly is None or len(energy_virtual_meter_hourly) == 0) and \
506
            (energy_offline_meter_hourly is None or len(energy_offline_meter_hourly) == 0) and \
507
            (energy_equipment_hourly is None or len(energy_equipment_hourly) == 0):
508
        # There isn't any energy data
509
        print("There isn't any energy data")
510
        # continue the for shopfloor loop to the next shopfloor
511
        print("continue the for shopfloor loop to the next shopfloor")
512
        if cursor_energy_db:
513
            cursor_energy_db.close()
514
        if cnx_energy_db:
515
            cnx_energy_db.close()
516
        return None
517
518
    print("common_start_datetime_utc: " + str(common_start_datetime_utc))
519
    print("common_end_datetime_utc: " + str(common_end_datetime_utc))
520
521
    ####################################################################################################################
522
    # Step 11: aggregate energy data in the common time slot by energy items and hourly
523
    ####################################################################################################################
524
525
    print("Step 11: aggregate energy data in the common time slot by energy items and hourly")
526
    aggregated_values = list()
527
    try:
528
        current_datetime_utc = common_start_datetime_utc
529
        while common_start_datetime_utc is not None \
530
                and common_end_datetime_utc is not None \
531
                and current_datetime_utc <= common_end_datetime_utc:
532
            aggregated_value = dict()
533
            aggregated_value['start_datetime_utc'] = current_datetime_utc
534
            aggregated_value['meta_data'] = dict()
535
536
            if meter_list is not None and len(meter_list) > 0:
537
                for meter in meter_list:
538
                    meter_id = str(meter['id'])
539
                    energy_item_id = meter['energy_item_id']
540
                    actual_value = energy_meter_hourly[meter_id].get(current_datetime_utc, Decimal(0.0))
541
                    aggregated_value['meta_data'][energy_item_id] = \
542
                        aggregated_value['meta_data'].get(energy_item_id, Decimal(0.0)) + actual_value
543
544
            if virtual_meter_list is not None and len(virtual_meter_list) > 0:
545
                for virtual_meter in virtual_meter_list:
546
                    virtual_meter_id = str(virtual_meter['id'])
547
                    energy_item_id = virtual_meter['energy_item_id']
548
                    actual_value = energy_virtual_meter_hourly[virtual_meter_id].get(current_datetime_utc, Decimal(0.0))
549
                    aggregated_value['meta_data'][energy_item_id] = \
550
                        aggregated_value['meta_data'].get(energy_item_id, Decimal(0.0)) + actual_value
551
552
            if offline_meter_list is not None and len(offline_meter_list) > 0:
553
                for offline_meter in offline_meter_list:
554
                    offline_meter_id = str(offline_meter['id'])
555
                    energy_item_id = offline_meter['energy_item_id']
556
                    actual_value = energy_offline_meter_hourly[offline_meter_id].get(current_datetime_utc, Decimal(0.0))
557
                    aggregated_value['meta_data'][energy_item_id] = \
558
                        aggregated_value['meta_data'].get(energy_item_id, Decimal(0.0)) + actual_value
559
560
            if equipment_list is not None and len(equipment_list) > 0:
561
                for equipment in equipment_list:
562
                    equipment_id = str(equipment['id'])
563
                    meta_data_dict = energy_equipment_hourly[equipment_id].get(current_datetime_utc, None)
564
                    if meta_data_dict is not None and len(meta_data_dict) > 0:
565
                        for energy_item_id, actual_value in meta_data_dict.items():
566
                            aggregated_value['meta_data'][energy_item_id] = \
567
                                aggregated_value['meta_data'].get(energy_item_id, Decimal(0.0)) + actual_value
568
569
            aggregated_values.append(aggregated_value)
570
571
            current_datetime_utc += timedelta(minutes=config.minutes_to_count)
572
573
    except Exception as e:
574
        error_string = "Error in step 11 of shopfloor_energy_input_item.worker " + str(e)
575
        if cursor_energy_db:
576
            cursor_energy_db.close()
577
        if cnx_energy_db:
578
            cnx_energy_db.close()
579
        print(error_string)
580
        return error_string
581
582
    ####################################################################################################################
583
    # Step 12: save energy data to energy database
584
    ####################################################################################################################
585
    print("Step 12: save energy data to energy database")
586
587
    while len(aggregated_values) > 0:
588
        insert_100 = aggregated_values[:100]
589
        aggregated_values = aggregated_values[100:]
590
        try:
591
            add_values = (" INSERT INTO tbl_shopfloor_input_item_hourly "
592
                          "             (shopfloor_id, "
593
                          "              energy_item_id, "
594
                          "              start_datetime_utc, "
595
                          "              actual_value) "
596
                          " VALUES  ")
597
598
            for aggregated_value in insert_100:
599
                for energy_item_id, actual_value in aggregated_value['meta_data'].items():
600
                    add_values += " (" + str(shopfloor['id']) + ","
601
                    add_values += " " + str(energy_item_id) + ","
602
                    add_values += "'" + aggregated_value['start_datetime_utc'].isoformat()[0:19] + "',"
603
                    add_values += str(actual_value) + "), "
604
            # print("add_values:" + add_values)
605
            # trim ", " at the end of string and then execute
606
            cursor_energy_db.execute(add_values[:-2])
607
            cnx_energy_db.commit()
608
609
        except Exception as e:
610
            error_string = "Error in step 12.1 of shopfloor_energy_input_item.worker " + str(e)
611
            print(error_string)
612
            if cursor_energy_db:
613
                cursor_energy_db.close()
614
            if cnx_energy_db:
615
                cnx_energy_db.close()
616
            return error_string
617
618
    if cursor_energy_db:
619
        cursor_energy_db.close()
620
    if cnx_energy_db:
621
        cnx_energy_db.close()
622
    return None
623

myems-aggregation/shopfloor_energy_input_category.py 1 location

@@ 110-619 (lines=510) @@
107
# NOTE: returns None or the error string because that the logger object cannot be passed in as parameter
108
########################################################################################################################
109
110
def worker(shopfloor):
111
    ####################################################################################################################
112
    # Step 1: get all input meters associated with the shopfloor
113
    ####################################################################################################################
114
    print("Step 1: get all input meters associated with the shopfloor " + str(shopfloor['name']))
115
116
    meter_list = list()
117
    cnx_system_db = None
118
    cursor_system_db = None
119
    try:
120
        cnx_system_db = mysql.connector.connect(**config.myems_system_db)
121
        cursor_system_db = cnx_system_db.cursor()
122
    except Exception as e:
123
        error_string = "Error in step 1.1 of shopfloor_energy_input_category.worker " + str(e)
124
        if cursor_system_db:
125
            cursor_system_db.close()
126
        if cnx_system_db:
127
            cnx_system_db.close()
128
        print(error_string)
129
        return error_string
130
131
    try:
132
        cursor_system_db.execute(" SELECT m.id, m.name, m.energy_category_id "
133
                                 " FROM tbl_meters m, tbl_shopfloors_meters tm "
134
                                 " WHERE m.id = tm.meter_id "
135
                                 "       AND m.is_counted = 1 "
136
                                 "       AND tm.shopfloor_id = %s ",
137
                                 (shopfloor['id'],))
138
        rows_meters = cursor_system_db.fetchall()
139
140
        if rows_meters is not None and len(rows_meters) > 0:
141
            for row in rows_meters:
142
                meter_list.append({"id": row[0],
143
                                   "name": row[1],
144
                                   "energy_category_id": row[2]})
145
146
    except Exception as e:
147
        error_string = "Error in step 1.2 of shopfloor_energy_input_category.worker " + str(e)
148
        if cursor_system_db:
149
            cursor_system_db.close()
150
        if cnx_system_db:
151
            cnx_system_db.close()
152
        print(error_string)
153
        return error_string
154
155
    ####################################################################################################################
156
    # Step 2: get all input virtual meters associated with the shopfloor
157
    ####################################################################################################################
158
    print("Step 2: get all input virtual meters associated with the shopfloor")
159
    virtual_meter_list = list()
160
161
    try:
162
        cursor_system_db.execute(" SELECT m.id, m.name, m.energy_category_id "
163
                                 " FROM tbl_virtual_meters m, tbl_shopfloors_virtual_meters tm "
164
                                 " WHERE m.id = tm.virtual_meter_id "
165
                                 "       AND m.is_counted = 1 "
166
                                 "       AND tm.shopfloor_id = %s ",
167
                                 (shopfloor['id'],))
168
        rows_virtual_meters = cursor_system_db.fetchall()
169
170
        if rows_virtual_meters is not None and len(rows_virtual_meters) > 0:
171
            for row in rows_virtual_meters:
172
                virtual_meter_list.append({"id": row[0],
173
                                           "name": row[1],
174
                                           "energy_category_id": row[2]})
175
176
    except Exception as e:
177
        error_string = "Error in step 2.1 of shopfloor_energy_input_category.worker " + str(e)
178
        if cursor_system_db:
179
            cursor_system_db.close()
180
        if cnx_system_db:
181
            cnx_system_db.close()
182
        print(error_string)
183
        return error_string
184
185
    ####################################################################################################################
186
    # Step 3: get all input offline meters associated with the shopfloor
187
    ####################################################################################################################
188
    print("Step 3: get all input offline meters associated with the shopfloor")
189
190
    offline_meter_list = list()
191
192
    try:
193
        cursor_system_db.execute(" SELECT m.id, m.name, m.energy_category_id "
194
                                 " FROM tbl_offline_meters m, tbl_shopfloors_offline_meters tm "
195
                                 " WHERE m.id = tm.offline_meter_id "
196
                                 "       AND m.is_counted = 1 "
197
                                 "       AND tm.shopfloor_id = %s ",
198
                                 (shopfloor['id'],))
199
        rows_offline_meters = cursor_system_db.fetchall()
200
201
        if rows_offline_meters is not None and len(rows_offline_meters) > 0:
202
            for row in rows_offline_meters:
203
                offline_meter_list.append({"id": row[0],
204
                                           "name": row[1],
205
                                           "energy_category_id": row[2]})
206
207
    except Exception as e:
208
        error_string = "Error in step 3.1 of shopfloor_energy_input_category.worker " + str(e)
209
        if cursor_system_db:
210
            cursor_system_db.close()
211
        if cnx_system_db:
212
            cnx_system_db.close()
213
        print(error_string)
214
        return error_string
215
216
    ####################################################################################################################
217
    # Step 4: get all equipments associated with the shopfloor
218
    ####################################################################################################################
219
    print("Step 4: get all equipments associated with the shopfloor")
220
221
    equipment_list = list()
222
223
    try:
224
        cursor_system_db.execute(" SELECT e.id, e.name "
225
                                 " FROM tbl_equipments e, tbl_shopfloors_equipments se "
226
                                 " WHERE e.id = se.equipment_id "
227
                                 "       AND e.is_input_counted = 1 "
228
                                 "       AND se.shopfloor_id = %s ",
229
                                 (shopfloor['id'],))
230
        rows_equipments = cursor_system_db.fetchall()
231
232
        if rows_equipments is not None and len(rows_equipments) > 0:
233
            for row in rows_equipments:
234
                equipment_list.append({"id": row[0],
235
                                       "name": row[1]})
236
237
    except Exception as e:
238
        error_string = "Error in step 4 of shopfloor_energy_input_category.worker " + str(e)
239
        print(error_string)
240
        return error_string
241
    finally:
242
        if cursor_system_db:
243
            cursor_system_db.close()
244
        if cnx_system_db:
245
            cnx_system_db.close()
246
247
    ####################################################################################################################
248
    # stop to the next shopfloor if this shopfloor is empty
249
    ####################################################################################################################
250
    if (meter_list is None or len(meter_list) == 0) and \
251
            (virtual_meter_list is None or len(virtual_meter_list) == 0) and \
252
            (offline_meter_list is None or len(offline_meter_list) == 0) and \
253
            (equipment_list is None or len(equipment_list) == 0):
254
        print("This is an empty shopfloor ")
255
        return None
256
257
    ####################################################################################################################
258
    # Step 5: determine start datetime and end datetime to aggregate
259
    ####################################################################################################################
260
    print("Step 5: determine start datetime and end datetime to aggregate")
261
    cnx_energy_db = None
262
    cursor_energy_db = None
263
    try:
264
        cnx_energy_db = mysql.connector.connect(**config.myems_energy_db)
265
        cursor_energy_db = cnx_energy_db.cursor()
266
    except Exception as e:
267
        error_string = "Error in step 5.1 of shopfloor_energy_input_category.worker " + str(e)
268
        if cursor_energy_db:
269
            cursor_energy_db.close()
270
        if cnx_energy_db:
271
            cnx_energy_db.close()
272
        print(error_string)
273
        return error_string
274
275
    try:
276
        query = (" SELECT MAX(start_datetime_utc) "
277
                 " FROM tbl_shopfloor_input_category_hourly "
278
                 " WHERE shopfloor_id = %s ")
279
        cursor_energy_db.execute(query, (shopfloor['id'],))
280
        row_datetime = cursor_energy_db.fetchone()
281
        start_datetime_utc = datetime.strptime(config.start_datetime_utc, '%Y-%m-%d %H:%M:%S')
282
        start_datetime_utc = start_datetime_utc.replace(minute=0, second=0, microsecond=0, tzinfo=None)
283
284
        if row_datetime is not None and len(row_datetime) > 0 and isinstance(row_datetime[0], datetime):
285
            # replace second and microsecond with 0
286
            # note: do not replace minute in case of calculating in half hourly
287
            start_datetime_utc = row_datetime[0].replace(second=0, microsecond=0, tzinfo=None)
288
            # start from the next time slot
289
            start_datetime_utc += timedelta(minutes=config.minutes_to_count)
290
291
        end_datetime_utc = datetime.utcnow().replace(second=0, microsecond=0, tzinfo=None)
292
293
        print("start_datetime_utc: " + start_datetime_utc.isoformat()[0:19]
294
              + "end_datetime_utc: " + end_datetime_utc.isoformat()[0:19])
295
296
    except Exception as e:
297
        error_string = "Error in step 5.2 of shopfloor_energy_input_category.worker " + str(e)
298
        if cursor_energy_db:
299
            cursor_energy_db.close()
300
        if cnx_energy_db:
301
            cnx_energy_db.close()
302
        print(error_string)
303
        return error_string
304
305
    ####################################################################################################################
306
    # Step 6: for each meter in list, get energy input data from energy database
307
    ####################################################################################################################
308
    energy_meter_hourly = dict()
309
    try:
310
        if meter_list is not None and len(meter_list) > 0:
311
            for meter in meter_list:
312
                meter_id = str(meter['id'])
313
314
                query = (" SELECT start_datetime_utc, actual_value "
315
                         " FROM tbl_meter_hourly "
316
                         " WHERE meter_id = %s "
317
                         "       AND start_datetime_utc >= %s "
318
                         "       AND start_datetime_utc < %s "
319
                         " ORDER BY start_datetime_utc ")
320
                cursor_energy_db.execute(query, (meter_id, start_datetime_utc, end_datetime_utc,))
321
                rows_energy_values = cursor_energy_db.fetchall()
322
                if rows_energy_values is None or len(rows_energy_values) == 0:
323
                    energy_meter_hourly[meter_id] = None
324
                else:
325
                    energy_meter_hourly[meter_id] = dict()
326
                    for row_energy_value in rows_energy_values:
327
                        energy_meter_hourly[meter_id][row_energy_value[0]] = row_energy_value[1]
328
    except Exception as e:
329
        error_string = "Error in step 6.1 of shopfloor_energy_input_category.worker " + str(e)
330
        if cursor_energy_db:
331
            cursor_energy_db.close()
332
        if cnx_energy_db:
333
            cnx_energy_db.close()
334
        print(error_string)
335
        return error_string
336
337
    ####################################################################################################################
338
    # Step 7: for each virtual meter in list, get energy input data from energy database
339
    ####################################################################################################################
340
    energy_virtual_meter_hourly = dict()
341
    if virtual_meter_list is not None and len(virtual_meter_list) > 0:
342
        try:
343
            for virtual_meter in virtual_meter_list:
344
                virtual_meter_id = str(virtual_meter['id'])
345
346
                query = (" SELECT start_datetime_utc, actual_value "
347
                         " FROM tbl_virtual_meter_hourly "
348
                         " WHERE virtual_meter_id = %s "
349
                         "       AND start_datetime_utc >= %s "
350
                         "       AND start_datetime_utc < %s "
351
                         " ORDER BY start_datetime_utc ")
352
                cursor_energy_db.execute(query, (virtual_meter_id, start_datetime_utc, end_datetime_utc,))
353
                rows_energy_values = cursor_energy_db.fetchall()
354
                if rows_energy_values is None or len(rows_energy_values) == 0:
355
                    energy_virtual_meter_hourly[virtual_meter_id] = None
356
                else:
357
                    energy_virtual_meter_hourly[virtual_meter_id] = dict()
358
                    for row_energy_value in rows_energy_values:
359
                        energy_virtual_meter_hourly[virtual_meter_id][row_energy_value[0]] = row_energy_value[1]
360
        except Exception as e:
361
            error_string = "Error in step 7.1 of shopfloor_energy_input_category.worker " + str(e)
362
            if cursor_energy_db:
363
                cursor_energy_db.close()
364
            if cnx_energy_db:
365
                cnx_energy_db.close()
366
            print(error_string)
367
            return error_string
368
369
    ####################################################################################################################
370
    # Step 8: for each offline meter in list, get energy input data from energy database
371
    ####################################################################################################################
372
    energy_offline_meter_hourly = dict()
373
    if offline_meter_list is not None and len(offline_meter_list) > 0:
374
        try:
375
            for offline_meter in offline_meter_list:
376
                offline_meter_id = str(offline_meter['id'])
377
378
                query = (" SELECT start_datetime_utc, actual_value "
379
                         " FROM tbl_offline_meter_hourly "
380
                         " WHERE offline_meter_id = %s "
381
                         "       AND start_datetime_utc >= %s "
382
                         "       AND start_datetime_utc < %s "
383
                         " ORDER BY start_datetime_utc ")
384
                cursor_energy_db.execute(query, (offline_meter_id, start_datetime_utc, end_datetime_utc,))
385
                rows_energy_values = cursor_energy_db.fetchall()
386
                if rows_energy_values is None or len(rows_energy_values) == 0:
387
                    energy_offline_meter_hourly[offline_meter_id] = None
388
                else:
389
                    energy_offline_meter_hourly[offline_meter_id] = dict()
390
                    for row_energy_value in rows_energy_values:
391
                        energy_offline_meter_hourly[offline_meter_id][row_energy_value[0]] = row_energy_value[1]
392
393
        except Exception as e:
394
            error_string = "Error in step 8.1 of shopfloor_energy_input_category.worker " + str(e)
395
            if cursor_energy_db:
396
                cursor_energy_db.close()
397
            if cnx_energy_db:
398
                cnx_energy_db.close()
399
            print(error_string)
400
            return error_string
401
402
    ####################################################################################################################
403
    # Step 9: for each equipment in list, get energy input data from energy database
404
    ####################################################################################################################
405
    energy_equipment_hourly = dict()
406
    if equipment_list is not None and len(equipment_list) > 0:
407
        try:
408
            for equipment in equipment_list:
409
                equipment_id = str(equipment['id'])
410
                query = (" SELECT start_datetime_utc, energy_category_id, actual_value "
411
                         " FROM tbl_equipment_input_category_hourly "
412
                         " WHERE equipment_id = %s "
413
                         "       AND start_datetime_utc >= %s "
414
                         "       AND start_datetime_utc < %s "
415
                         " ORDER BY start_datetime_utc ")
416
                cursor_energy_db.execute(query, (equipment_id, start_datetime_utc, end_datetime_utc,))
417
                rows_energy_values = cursor_energy_db.fetchall()
418
                if rows_energy_values is None or len(rows_energy_values) == 0:
419
                    energy_equipment_hourly[equipment_id] = None
420
                else:
421
                    energy_equipment_hourly[equipment_id] = dict()
422
                    for row_value in rows_energy_values:
423
                        current_datetime_utc = row_value[0]
424
                        if current_datetime_utc not in energy_equipment_hourly[equipment_id]:
425
                            energy_equipment_hourly[equipment_id][current_datetime_utc] = dict()
426
                        energy_category_id = row_value[1]
427
                        actual_value = row_value[2]
428
                        energy_equipment_hourly[equipment_id][current_datetime_utc][energy_category_id] = \
429
                            actual_value
430
        except Exception as e:
431
            error_string = "Error in step 9 of shopfloor_energy_input_category.worker " + str(e)
432
            if cursor_energy_db:
433
                cursor_energy_db.close()
434
            if cnx_energy_db:
435
                cnx_energy_db.close()
436
            print(error_string)
437
            return error_string
438
439
    ####################################################################################################################
440
    # Step 10: determine common time slot to aggregate
441
    ####################################################################################################################
442
443
    common_start_datetime_utc = start_datetime_utc
444
    common_end_datetime_utc = end_datetime_utc
445
446
    print("Getting common time slot of energy values for all meters")
447
    if energy_meter_hourly is not None and len(energy_meter_hourly) > 0:
448
        for meter_id, energy_hourly in energy_meter_hourly.items():
449
            if energy_hourly is None or len(energy_hourly) == 0:
450
                common_start_datetime_utc = None
451
                common_end_datetime_utc = None
452
                break
453
            else:
454
                if common_start_datetime_utc < min(energy_hourly.keys()):
455
                    common_start_datetime_utc = min(energy_hourly.keys())
456
                if common_end_datetime_utc > max(energy_hourly.keys()):
457
                    common_end_datetime_utc = max(energy_hourly.keys())
458
459
    print("Getting common time slot of energy values for all virtual meters")
460
    if common_start_datetime_utc is not None and common_end_datetime_utc is not None:
461
        if energy_virtual_meter_hourly is not None and len(energy_virtual_meter_hourly) > 0:
462
            for meter_id, energy_hourly in energy_virtual_meter_hourly.items():
463
                if energy_hourly is None or len(energy_hourly) == 0:
464
                    common_start_datetime_utc = None
465
                    common_end_datetime_utc = None
466
                    break
467
                else:
468
                    if common_start_datetime_utc < min(energy_hourly.keys()):
469
                        common_start_datetime_utc = min(energy_hourly.keys())
470
                    if common_end_datetime_utc > max(energy_hourly.keys()):
471
                        common_end_datetime_utc = max(energy_hourly.keys())
472
473
    print("Getting common time slot of energy values for all offline meters")
474
    if common_start_datetime_utc is not None and common_end_datetime_utc is not None:
475
        if energy_offline_meter_hourly is not None and len(energy_offline_meter_hourly) > 0:
476
            for meter_id, energy_hourly in energy_offline_meter_hourly.items():
477
                if energy_hourly is None or len(energy_hourly) == 0:
478
                    common_start_datetime_utc = None
479
                    common_end_datetime_utc = None
480
                    break
481
                else:
482
                    if common_start_datetime_utc < min(energy_hourly.keys()):
483
                        common_start_datetime_utc = min(energy_hourly.keys())
484
                    if common_end_datetime_utc > max(energy_hourly.keys()):
485
                        common_end_datetime_utc = max(energy_hourly.keys())
486
487
    print("Getting common time slot of energy values for all equipments...")
488
    if common_start_datetime_utc is not None and common_end_datetime_utc is not None:
489
        if energy_equipment_hourly is not None and len(energy_equipment_hourly) > 0:
490
            for equipment_id, energy_hourly in energy_equipment_hourly.items():
491
                if energy_hourly is None or len(energy_hourly) == 0:
492
                    common_start_datetime_utc = None
493
                    common_end_datetime_utc = None
494
                    break
495
                else:
496
                    if common_start_datetime_utc < min(energy_hourly.keys()):
497
                        common_start_datetime_utc = min(energy_hourly.keys())
498
                    if common_end_datetime_utc > max(energy_hourly.keys()):
499
                        common_end_datetime_utc = max(energy_hourly.keys())
500
501
    if (energy_meter_hourly is None or len(energy_meter_hourly) == 0) and \
502
            (energy_virtual_meter_hourly is None or len(energy_virtual_meter_hourly) == 0) and \
503
            (energy_offline_meter_hourly is None or len(energy_offline_meter_hourly) == 0) and \
504
            (energy_equipment_hourly is None or len(energy_equipment_hourly) == 0):
505
        # There isn't any energy data
506
        print("There isn't any energy data")
507
        # continue the for shopfloor loop to the next shopfloor
508
        print("continue the for shopfloor loop to the next shopfloor")
509
        if cursor_energy_db:
510
            cursor_energy_db.close()
511
        if cnx_energy_db:
512
            cnx_energy_db.close()
513
        return None
514
515
    print("common_start_datetime_utc: " + str(common_start_datetime_utc))
516
    print("common_end_datetime_utc: " + str(common_end_datetime_utc))
517
518
    ####################################################################################################################
519
    # Step 11: aggregate energy data in the common time slot by energy categories and hourly
520
    ####################################################################################################################
521
522
    print("Step 11: aggregate energy data in the common time slot by energy categories and hourly")
523
    aggregated_values = list()
524
    try:
525
        current_datetime_utc = common_start_datetime_utc
526
        while common_start_datetime_utc is not None \
527
                and common_end_datetime_utc is not None \
528
                and current_datetime_utc <= common_end_datetime_utc:
529
            aggregated_value = dict()
530
            aggregated_value['start_datetime_utc'] = current_datetime_utc
531
            aggregated_value['meta_data'] = dict()
532
533
            if meter_list is not None and len(meter_list) > 0:
534
                for meter in meter_list:
535
                    meter_id = str(meter['id'])
536
                    energy_category_id = meter['energy_category_id']
537
                    actual_value = energy_meter_hourly[meter_id].get(current_datetime_utc, Decimal(0.0))
538
                    aggregated_value['meta_data'][energy_category_id] = \
539
                        aggregated_value['meta_data'].get(energy_category_id, Decimal(0.0)) + actual_value
540
541
            if virtual_meter_list is not None and len(virtual_meter_list) > 0:
542
                for virtual_meter in virtual_meter_list:
543
                    virtual_meter_id = str(virtual_meter['id'])
544
                    energy_category_id = virtual_meter['energy_category_id']
545
                    actual_value = energy_virtual_meter_hourly[virtual_meter_id].get(current_datetime_utc, Decimal(0.0))
546
                    aggregated_value['meta_data'][energy_category_id] = \
547
                        aggregated_value['meta_data'].get(energy_category_id, Decimal(0.0)) + actual_value
548
549
            if offline_meter_list is not None and len(offline_meter_list) > 0:
550
                for offline_meter in offline_meter_list:
551
                    offline_meter_id = str(offline_meter['id'])
552
                    energy_category_id = offline_meter['energy_category_id']
553
                    actual_value = energy_offline_meter_hourly[offline_meter_id].get(current_datetime_utc, Decimal(0.0))
554
                    aggregated_value['meta_data'][energy_category_id] = \
555
                        aggregated_value['meta_data'].get(energy_category_id, Decimal(0.0)) + actual_value
556
557
            if equipment_list is not None and len(equipment_list) > 0:
558
                for equipment in equipment_list:
559
                    equipment_id = str(equipment['id'])
560
                    meta_data_dict = energy_equipment_hourly[equipment_id].get(current_datetime_utc, None)
561
                    if meta_data_dict is not None and len(meta_data_dict) > 0:
562
                        for energy_category_id, actual_value in meta_data_dict.items():
563
                            aggregated_value['meta_data'][energy_category_id] = \
564
                                aggregated_value['meta_data'].get(energy_category_id, Decimal(0.0)) + actual_value
565
566
            aggregated_values.append(aggregated_value)
567
568
            current_datetime_utc += timedelta(minutes=config.minutes_to_count)
569
570
    except Exception as e:
571
        error_string = "Error in step 11 of shopfloor_energy_input_category.worker " + str(e)
572
        if cursor_energy_db:
573
            cursor_energy_db.close()
574
        if cnx_energy_db:
575
            cnx_energy_db.close()
576
        print(error_string)
577
        return error_string
578
579
    ####################################################################################################################
580
    # Step 12: save energy data to energy database
581
    ####################################################################################################################
582
    print("Step 12: save energy data to energy database")
583
584
    while len(aggregated_values) > 0:
585
        insert_100 = aggregated_values[:100]
586
        aggregated_values = aggregated_values[100:]
587
        try:
588
            add_values = (" INSERT INTO tbl_shopfloor_input_category_hourly "
589
                          "             (shopfloor_id, "
590
                          "              energy_category_id, "
591
                          "              start_datetime_utc, "
592
                          "              actual_value) "
593
                          " VALUES  ")
594
595
            for aggregated_value in insert_100:
596
                for energy_category_id, actual_value in aggregated_value['meta_data'].items():
597
                    add_values += " (" + str(shopfloor['id']) + ","
598
                    add_values += " " + str(energy_category_id) + ","
599
                    add_values += "'" + aggregated_value['start_datetime_utc'].isoformat()[0:19] + "',"
600
                    add_values += str(actual_value) + "), "
601
            # print("add_values:" + add_values)
602
            # trim ", " at the end of string and then execute
603
            cursor_energy_db.execute(add_values[:-2])
604
            cnx_energy_db.commit()
605
606
        except Exception as e:
607
            error_string = "Error in step 12.1 of shopfloor_energy_input_category.worker " + str(e)
608
            print(error_string)
609
            if cursor_energy_db:
610
                cursor_energy_db.close()
611
            if cnx_energy_db:
612
                cnx_energy_db.close()
613
            return error_string
614
615
    if cursor_energy_db:
616
        cursor_energy_db.close()
617
    if cnx_energy_db:
618
        cnx_energy_db.close()
619
    return None
620