Passed
Push — master ( 4d6f13...ccf8db )
by
unknown
11:59
created

reports.equipmentcomparison.Reporting.on_get()   F

Complexity

Conditions 118

Size

Total Lines 777
Code Lines 538

Duplication

Lines 200
Ratio 25.74 %

Importance

Changes 0
Metric Value
eloc 538
dl 200
loc 777
rs 0
c 0
b 0
f 0
cc 118
nop 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like reports.equipmentcomparison.Reporting.on_get() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
import re
2
from datetime import datetime, timedelta, timezone
3
from decimal import Decimal
4
import falcon
5
import mysql.connector
6
import simplejson as json
7
import config
8
import excelexporters.equipmentcomparison
9
from core import utilities
10
from core.useractivity import access_control, api_key_control
11
12
13
class Reporting:
14
    def __init__(self):
15
        """ "Initializes Reporting"""
16
        pass
17
18
    @staticmethod
19
    def on_options(req, resp):
20
        _ = req
21
        resp.status = falcon.HTTP_200
22
23
    ####################################################################################################################
24
    # PROCEDURES
25
    # Step 1: valid parameters
26
    # Step 2: query the equipment and energy category
27
    # Step 3: query equipment input category hourly data (pre-aggregated by background service)
28
    # Step 4: aggregate equipment energy consumption data by period
29
    # Step 5: query equipment associated points data
30
    # Step 6: construct the report
31
    ####################################################################################################################
32
    @staticmethod
33
    def on_get(req, resp):
34
        if (
35
            "API-KEY" not in req.headers
36
            or not isinstance(req.headers["API-KEY"], str)
37
            or len(str.strip(req.headers["API-KEY"])) == 0
38
        ):
39
            access_control(req)
40
        else:
41
            api_key_control(req)
42
        print(req.params)
43
        # this procedure accepts equipment id or equipment uuid to identify a equipment
44
        equipment_id1 = req.params.get("equipmentid1")
45
        equipment_uuid1 = req.params.get("equipmentuuid1")
46
        equipment_id2 = req.params.get("equipmentid2")
47
        equipment_uuid2 = req.params.get("equipmentuuid2")
48
        energy_category_id = req.params.get("energycategoryid")
49
        period_type = req.params.get("periodtype")
50
        reporting_period_start_datetime_local = req.params.get(
51
            "reportingperiodstartdatetime"
52
        )
53
        reporting_period_end_datetime_local = req.params.get(
54
            "reportingperiodenddatetime"
55
        )
56
        language = req.params.get("language")
57
        quick_mode = req.params.get("quickmode")
58
59
        ################################################################################################################
60
        # Step 1: valid parameters
61
        ################################################################################################################
62
        if equipment_id1 is None and equipment_uuid1 is None:
63
            raise falcon.HTTPError(
64
                status=falcon.HTTP_400,
65
                title="API.BAD_REQUEST",
66
                description="API.INVALID_EQUIPMENT_ID",
67
            )
68
69
        if equipment_id1 is not None:
70
            equipment_id1 = str.strip(equipment_id1)
71
            if not equipment_id1.isdigit() or int(equipment_id1) <= 0:
72
                raise falcon.HTTPError(
73
                    status=falcon.HTTP_400,
74
                    title="API.BAD_REQUEST",
75
                    description="API.INVALID_EQUIPMENT_ID",
76
                )
77
78
        if equipment_uuid1 is not None:
79
            regex = re.compile(
80
                r"^[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}\Z",
81
                re.I,
82
            )
83
            match = regex.match(str.strip(equipment_uuid1))
84
            if not bool(match):
85
                raise falcon.HTTPError(
86
                    status=falcon.HTTP_400,
87
                    title="API.BAD_REQUEST",
88
                    description="API.INVALID_EQUIPMENT_UUID",
89
                )
90
91
        if equipment_id2 is None and equipment_uuid2 is None:
92
            raise falcon.HTTPError(
93
                status=falcon.HTTP_400,
94
                title="API.BAD_REQUEST",
95
                description="API.INVALID_EQUIPMENT_ID",
96
            )
97
98
        if equipment_id2 is not None:
99
            equipment_id2 = str.strip(equipment_id2)
100
            if not equipment_id2.isdigit() or int(equipment_id2) <= 0:
101
                raise falcon.HTTPError(
102
                    status=falcon.HTTP_400,
103
                    title="API.BAD_REQUEST",
104
                    description="API.INVALID_EQUIPMENT_ID",
105
                )
106
107
        if equipment_uuid2 is not None:
108
            regex = re.compile(
109
                r"^[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}\Z",
110
                re.I,
111
            )
112
            match = regex.match(str.strip(equipment_uuid2))
113
            if not bool(match):
114
                raise falcon.HTTPError(
115
                    status=falcon.HTTP_400,
116
                    title="API.BAD_REQUEST",
117
                    description="API.INVALID_EQUIPMENT_UUID",
118
                )
119
120
        if energy_category_id is None:
121
            raise falcon.HTTPError(
122
                status=falcon.HTTP_400,
123
                title="API.BAD_REQUEST",
124
                description="API.INVALID_ENERGY_CATEGORY_ID",
125
            )
126
        else:
127
            energy_category_id = str.strip(energy_category_id)
128
            if not energy_category_id.isdigit() or int(energy_category_id) <= 0:
129
                raise falcon.HTTPError(
130
                    status=falcon.HTTP_400,
131
                    title="API.BAD_REQUEST",
132
                    description="API.INVALID_ENERGY_CATEGORY_ID",
133
                )
134
135
        if period_type is None:
136
            raise falcon.HTTPError(
137
                status=falcon.HTTP_400,
138
                title="API.BAD_REQUEST",
139
                description="API.INVALID_PERIOD_TYPE",
140
            )
141
        else:
142
            period_type = str.strip(period_type)
143
            if period_type not in ["hourly", "daily", "weekly", "monthly", "yearly"]:
144
                raise falcon.HTTPError(
145
                    status=falcon.HTTP_400,
146
                    title="API.BAD_REQUEST",
147
                    description="API.INVALID_PERIOD_TYPE",
148
                )
149
150
        timezone_offset = int(config.utc_offset[1:3]) * 60 + int(config.utc_offset[4:6])
151
        if config.utc_offset[0] == "-":
152
            timezone_offset = -timezone_offset
153
154
        if reporting_period_start_datetime_local is None:
155
            raise falcon.HTTPError(
156
                status=falcon.HTTP_400,
157
                title="API.BAD_REQUEST",
158
                description="API.INVALID_REPORTING_PERIOD_START_DATETIME",
159
            )
160
        else:
161
            reporting_period_start_datetime_local = str.strip(
162
                reporting_period_start_datetime_local
163
            )
164
            try:
165
                reporting_start_datetime_utc = datetime.strptime(
166
                    reporting_period_start_datetime_local, "%Y-%m-%dT%H:%M:%S"
167
                )
168
            except ValueError:
169
                raise falcon.HTTPError(
170
                    status=falcon.HTTP_400,
171
                    title="API.BAD_REQUEST",
172
                    description="API.INVALID_REPORTING_PERIOD_START_DATETIME",
173
                )
174
            reporting_start_datetime_utc = reporting_start_datetime_utc.replace(
175
                tzinfo=timezone.utc
176
            ) - timedelta(minutes=timezone_offset)
177
            # nomalize the start datetime
178
            if (
179
                config.minutes_to_count == 30
180
                and reporting_start_datetime_utc.minute >= 30
181
            ):
182
                reporting_start_datetime_utc = reporting_start_datetime_utc.replace(
183
                    minute=30, second=0, microsecond=0
184
                )
185
            else:
186
                reporting_start_datetime_utc = reporting_start_datetime_utc.replace(
187
                    minute=0, second=0, microsecond=0
188
                )
189
190
        if reporting_period_end_datetime_local is None:
191
            raise falcon.HTTPError(
192
                status=falcon.HTTP_400,
193
                title="API.BAD_REQUEST",
194
                description="API.INVALID_REPORTING_PERIOD_END_DATETIME",
195
            )
196
        else:
197
            reporting_period_end_datetime_local = str.strip(
198
                reporting_period_end_datetime_local
199
            )
200
            try:
201
                reporting_end_datetime_utc = datetime.strptime(
202
                    reporting_period_end_datetime_local, "%Y-%m-%dT%H:%M:%S"
203
                )
204
            except ValueError:
205
                raise falcon.HTTPError(
206
                    status=falcon.HTTP_400,
207
                    title="API.BAD_REQUEST",
208
                    description="API.INVALID_REPORTING_PERIOD_END_DATETIME",
209
                )
210
            reporting_end_datetime_utc = reporting_end_datetime_utc.replace(
211
                tzinfo=timezone.utc
212
            ) - timedelta(minutes=timezone_offset)
213
214
        if reporting_start_datetime_utc >= reporting_end_datetime_utc:
215
            raise falcon.HTTPError(
216
                status=falcon.HTTP_400,
217
                title="API.BAD_REQUEST",
218
                description="API.INVALID_REPORTING_PERIOD_END_DATETIME",
219
            )
220
221
        # if turn quick mode on, do not return parameters data and excel file
222
        is_quick_mode = False
223
        if (
224
            quick_mode is not None
225
            and len(str.strip(quick_mode)) > 0
226
            and str.lower(str.strip(quick_mode)) in ("true", "t", "on", "yes", "y")
227
        ):
228
            is_quick_mode = True
229
230
        ################################################################################################################
231
        # Step 2: query the equipment and energy category
232
        ################################################################################################################
233
        cnx_system = mysql.connector.connect(**config.myems_system_db)
234
        cursor_system = cnx_system.cursor()
235
236
        cnx_energy = mysql.connector.connect(**config.myems_energy_db)
237
        cursor_energy = cnx_energy.cursor()
238
239
        cnx_historical = mysql.connector.connect(**config.myems_historical_db)
240
        cursor_historical = cnx_historical.cursor()
241
242
        # Query equipment 1
243
        if equipment_id1 is not None:
244
            cursor_system.execute(
245
                " SELECT id, name FROM tbl_equipments WHERE id = %s ", (equipment_id1,)
246
            )
247
            row_equipment1 = cursor_system.fetchone()
248
        elif equipment_uuid1 is not None:
249
            cursor_system.execute(
250
                " SELECT id, name FROM tbl_equipments WHERE uuid = %s ",
251
                (equipment_uuid1,),
252
            )
253
            row_equipment1 = cursor_system.fetchone()
254
255
        if row_equipment1 is None:
0 ignored issues
show
introduced by
The variable row_equipment1 does not seem to be defined for all execution paths.
Loading history...
256
            if cursor_system:
257
                cursor_system.close()
258
            if cnx_system:
259
                cnx_system.close()
260
261
            if cursor_energy:
262
                cursor_energy.close()
263
            if cnx_energy:
264
                cnx_energy.close()
265
266
            if cursor_historical:
267
                cursor_historical.close()
268
            if cnx_historical:
269
                cnx_historical.close()
270
            raise falcon.HTTPError(
271
                status=falcon.HTTP_404,
272
                title="API.NOT_FOUND",
273
                description="API.EQUIPMENT_NOT_FOUND",
274
            )
275
276
        equipment1 = dict()
277
        equipment1["id"] = row_equipment1[0]
278
        equipment1["name"] = row_equipment1[1]
279
280
        # Query equipment 2
281
        if equipment_id2 is not None:
282
            cursor_system.execute(
283
                " SELECT id, name FROM tbl_equipments WHERE id = %s ", (equipment_id2,)
284
            )
285
            row_equipment2 = cursor_system.fetchone()
286
        elif equipment_uuid2 is not None:
287
            cursor_system.execute(
288
                " SELECT id, name FROM tbl_equipments WHERE uuid = %s ",
289
                (equipment_uuid2,),
290
            )
291
            row_equipment2 = cursor_system.fetchone()
292
293
        if row_equipment2 is None:
0 ignored issues
show
introduced by
The variable row_equipment2 does not seem to be defined for all execution paths.
Loading history...
294
            if cursor_system:
295
                cursor_system.close()
296
            if cnx_system:
297
                cnx_system.close()
298
299
            if cursor_energy:
300
                cursor_energy.close()
301
            if cnx_energy:
302
                cnx_energy.close()
303
304
            if cursor_historical:
305
                cursor_historical.close()
306
            if cnx_historical:
307
                cnx_historical.close()
308
            raise falcon.HTTPError(
309
                status=falcon.HTTP_404,
310
                title="API.NOT_FOUND",
311
                description="API.EQUIPMENT_NOT_FOUND",
312
            )
313
314
        equipment2 = dict()
315
        equipment2["id"] = row_equipment2[0]
316
        equipment2["name"] = row_equipment2[1]
317
318
        # Query energy category
319
        cursor_system.execute(
320
            " SELECT id, name, unit_of_measure FROM tbl_energy_categories WHERE id = %s ",
321
            (energy_category_id,),
322
        )
323
        row_energy_category = cursor_system.fetchone()
324
325
        if row_energy_category is None:
326
            if cursor_system:
327
                cursor_system.close()
328
            if cnx_system:
329
                cnx_system.close()
330
331
            if cursor_energy:
332
                cursor_energy.close()
333
            if cnx_energy:
334
                cnx_energy.close()
335
336
            if cursor_historical:
337
                cursor_historical.close()
338
            if cnx_historical:
339
                cnx_historical.close()
340
            raise falcon.HTTPError(
341
                status=falcon.HTTP_404,
342
                title="API.NOT_FOUND",
343
                description="API.ENERGY_CATEGORY_NOT_FOUND",
344
            )
345
346
        energy_category = dict()
347
        energy_category["id"] = row_energy_category[0]
348
        energy_category["name"] = row_energy_category[1]
349
        energy_category["unit_of_measure"] = row_energy_category[2]
350
351
        ################################################################################################################
352
        # Step 3: query equipment input category hourly data (pre-aggregated by background service)
353
        ################################################################################################################
354
        # Query equipment 1 input category hourly data
355
        cursor_energy.execute(
356
            " SELECT start_datetime_utc, actual_value "
357
            " FROM tbl_equipment_input_category_hourly "
358
            " WHERE equipment_id = %s "
359
            "     AND energy_category_id = %s "
360
            "     AND start_datetime_utc >= %s "
361
            "     AND start_datetime_utc < %s "
362
            " ORDER BY start_datetime_utc ",
363
            (
364
                equipment1["id"],
365
                energy_category_id,
366
                reporting_start_datetime_utc,
367
                reporting_end_datetime_utc,
368
            ),
369
        )
370
        rows_equipment1_hourly = cursor_energy.fetchall()
371
372
        # Query equipment 2 input category hourly data
373
        cursor_energy.execute(
374
            " SELECT start_datetime_utc, actual_value "
375
            " FROM tbl_equipment_input_category_hourly "
376
            " WHERE equipment_id = %s "
377
            "     AND energy_category_id = %s "
378
            "     AND start_datetime_utc >= %s "
379
            "     AND start_datetime_utc < %s "
380
            " ORDER BY start_datetime_utc ",
381
            (
382
                equipment2["id"],
383
                energy_category_id,
384
                reporting_start_datetime_utc,
385
                reporting_end_datetime_utc,
386
            ),
387
        )
388
        rows_equipment2_hourly = cursor_energy.fetchall()
389
390
        ################################################################################################################
391
        # Step 4: aggregate equipment energy consumption data by period
392
        ################################################################################################################
393
        # Aggregate energy consumption for equipment 1
394
        equipment1_energy_data = dict()
395
        equipment1_energy_data["timestamps"] = list()
396
        equipment1_energy_data["values"] = list()
397
        equipment1_energy_data["total_in_category"] = Decimal(0.0)
398
399
        # Aggregate equipment 1 hourly data by period
400
        rows_equipment1_periodically = utilities.aggregate_hourly_data_by_period(
401
            rows_equipment1_hourly,
402
            reporting_start_datetime_utc,
403
            reporting_end_datetime_utc,
404
            period_type,
405
        )
406
407
        for row_equipment1_periodically in rows_equipment1_periodically:
408
            current_datetime_local = row_equipment1_periodically[0].replace(
409
                tzinfo=timezone.utc
410
            ) + timedelta(minutes=timezone_offset)
411
            if period_type == "hourly":
412
                current_datetime = current_datetime_local.isoformat()[0:19]
413
            elif period_type == "daily":
414
                current_datetime = current_datetime_local.isoformat()[0:10]
415
            elif period_type == "weekly":
416
                current_datetime = current_datetime_local.isoformat()[0:10]
417
            elif period_type == "monthly":
418
                current_datetime = current_datetime_local.isoformat()[0:7]
419
            elif period_type == "yearly":
420
                current_datetime = current_datetime_local.isoformat()[0:4]
421
422
            actual_value = row_equipment1_periodically[1]
423
424
            equipment1_energy_data["timestamps"].append(current_datetime)
0 ignored issues
show
introduced by
The variable current_datetime does not seem to be defined for all execution paths.
Loading history...
425
            equipment1_energy_data["values"].append(actual_value)
426
            if actual_value is not None:
427
                equipment1_energy_data["total_in_category"] += actual_value
428
429
        # Aggregate energy consumption for equipment 2
430
        equipment2_energy_data = dict()
431
        equipment2_energy_data["timestamps"] = list()
432
        equipment2_energy_data["values"] = list()
433
        equipment2_energy_data["total_in_category"] = Decimal(0.0)
434
435
        # Aggregate equipment 2 hourly data by period
436
        rows_equipment2_periodically = utilities.aggregate_hourly_data_by_period(
437
            rows_equipment2_hourly,
438
            reporting_start_datetime_utc,
439
            reporting_end_datetime_utc,
440
            period_type,
441
        )
442
443
        for row_equipment2_periodically in rows_equipment2_periodically:
444
            current_datetime_local = row_equipment2_periodically[0].replace(
445
                tzinfo=timezone.utc
446
            ) + timedelta(minutes=timezone_offset)
447
            if period_type == "hourly":
448
                current_datetime = current_datetime_local.isoformat()[0:19]
449
            elif period_type == "daily":
450
                current_datetime = current_datetime_local.isoformat()[0:10]
451
            elif period_type == "weekly":
452
                current_datetime = current_datetime_local.isoformat()[0:10]
453
            elif period_type == "monthly":
454
                current_datetime = current_datetime_local.isoformat()[0:7]
455
            elif period_type == "yearly":
456
                current_datetime = current_datetime_local.isoformat()[0:4]
457
458
            actual_value = row_equipment2_periodically[1]
459
460
            equipment2_energy_data["timestamps"].append(current_datetime)
461
            equipment2_energy_data["values"].append(actual_value)
462
            if actual_value is not None:
463
                equipment2_energy_data["total_in_category"] += actual_value
464
465
        # Calculate difference
466
        diff = dict()
467
        diff["values"] = list()
468
        diff["total_in_category"] = Decimal(0.0)
469
470
        # Ensure both equipments have the same number of data points
471
        min_length = min(
472
            len(equipment1_energy_data["values"]), len(equipment2_energy_data["values"])
473
        )
474
        for i in range(min_length):
475
            equipment1_value = (
476
                equipment1_energy_data["values"][i]
477
                if i < len(equipment1_energy_data["values"])
478
                else None
479
            )
480
            equipment2_value = (
481
                equipment2_energy_data["values"][i]
482
                if i < len(equipment2_energy_data["values"])
483
                else None
484
            )
485
            
486
            # Calculate difference, handling None values
487
            if equipment1_value is None and equipment2_value is None:
488
                diff_value = None
489
            elif equipment1_value is None:
490
                diff_value = None  # Cannot calculate difference when one value is missing
491
            elif equipment2_value is None:
492
                diff_value = None  # Cannot calculate difference when one value is missing
493
            else:
494
                diff_value = equipment1_value - equipment2_value
495
                diff["total_in_category"] += diff_value
496
                
497
            diff["values"].append(diff_value)
498
499
        ################################################################################################################
500
        # Step 5: query equipment associated points data (for detailed parameters)
501
        ################################################################################################################
502
        parameters_data1 = dict()
503
        parameters_data1["names"] = list()
504
        parameters_data1["timestamps"] = list()
505
        parameters_data1["values"] = list()
506
507
        parameters_data2 = dict()
508
        parameters_data2["names"] = list()
509
        parameters_data2["timestamps"] = list()
510
        parameters_data2["values"] = list()
511
512
        if not is_quick_mode:
513
            # Query points for equipment 1
514
            cursor_system.execute(
515
                " SELECT p.id, ep.name, p.units, p.object_type "
516
                " FROM tbl_equipments e, tbl_equipments_parameters ep, tbl_points p "
517
                " WHERE e.id = %s AND e.id = ep.equipment_id AND ep.parameter_type = 'point' "
518
                "       AND ep.point_id = p.id "
519
                " ORDER BY p.id ",
520
                (equipment1["id"],),
521
            )
522
            rows_points1 = cursor_system.fetchall()
523
524 View Code Duplication
            if rows_points1 is not None and len(rows_points1) > 0:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
525
                for point_row in rows_points1:
526
                    point_values = []
527
                    point_timestamps = []
528
529
                    if point_row[3] == "ENERGY_VALUE":
530
                        query = (
531
                            " SELECT utc_date_time, actual_value "
532
                            " FROM tbl_energy_value "
533
                            " WHERE point_id = %s "
534
                            " AND utc_date_time BETWEEN %s AND %s "
535
                            " ORDER BY utc_date_time "
536
                        )
537
                        cursor_historical.execute(
538
                            query,
539
                            (
540
                                point_row[0],
541
                                reporting_start_datetime_utc,
542
                                reporting_end_datetime_utc,
543
                            ),
544
                        )
545
                        rows = cursor_historical.fetchall()
546
547
                        if rows is not None and len(rows) > 0:
548
                            for row in rows:
549
                                current_datetime_local = row[0].replace(
550
                                    tzinfo=timezone.utc
551
                                ) + timedelta(minutes=timezone_offset)
552
                                current_datetime = current_datetime_local.isoformat()[
553
                                    0:19
554
                                ]
555
                                point_timestamps.append(current_datetime)
556
                                point_values.append(row[1])
557
                    elif point_row[3] == "ANALOG_VALUE":
558
                        query = (
559
                            " SELECT utc_date_time, actual_value "
560
                            " FROM tbl_analog_value "
561
                            " WHERE point_id = %s "
562
                            " AND utc_date_time BETWEEN %s AND %s "
563
                            " ORDER BY utc_date_time "
564
                        )
565
                        cursor_historical.execute(
566
                            query,
567
                            (
568
                                point_row[0],
569
                                reporting_start_datetime_utc,
570
                                reporting_end_datetime_utc,
571
                            ),
572
                        )
573
                        rows = cursor_historical.fetchall()
574
575
                        if rows is not None and len(rows) > 0:
576
                            for row in rows:
577
                                current_datetime_local = row[0].replace(
578
                                    tzinfo=timezone.utc
579
                                ) + timedelta(minutes=timezone_offset)
580
                                current_datetime = current_datetime_local.isoformat()[
581
                                    0:19
582
                                ]
583
                                point_timestamps.append(current_datetime)
584
                                point_values.append(row[1])
585
                    elif point_row[3] == "DIGITAL_VALUE":
586
                        query = (
587
                            " SELECT utc_date_time, actual_value "
588
                            " FROM tbl_digital_value "
589
                            " WHERE point_id = %s "
590
                            " AND utc_date_time BETWEEN %s AND %s "
591
                            " ORDER BY utc_date_time "
592
                        )
593
                        cursor_historical.execute(
594
                            query,
595
                            (
596
                                point_row[0],
597
                                reporting_start_datetime_utc,
598
                                reporting_end_datetime_utc,
599
                            ),
600
                        )
601
                        rows = cursor_historical.fetchall()
602
603
                        if rows is not None and len(rows) > 0:
604
                            for row in rows:
605
                                current_datetime_local = row[0].replace(
606
                                    tzinfo=timezone.utc
607
                                ) + timedelta(minutes=timezone_offset)
608
                                current_datetime = current_datetime_local.isoformat()[
609
                                    0:19
610
                                ]
611
                                point_timestamps.append(current_datetime)
612
                                point_values.append(row[1])
613
614
                    parameters_data1["names"].append(
615
                        equipment1["name"]
616
                        + " - "
617
                        + point_row[1]
618
                        + " ("
619
                        + point_row[2]
620
                        + ")"
621
                    )
622
                    parameters_data1["timestamps"].append(point_timestamps)
623
                    parameters_data1["values"].append(point_values)
624
625
            # Query points for equipment 2
626
            cursor_system.execute(
627
                " SELECT p.id, ep.name, p.units, p.object_type "
628
                " FROM tbl_equipments e, tbl_equipments_parameters ep, tbl_points p "
629
                " WHERE e.id = %s AND e.id = ep.equipment_id AND ep.parameter_type = 'point' "
630
                "       AND ep.point_id = p.id "
631
                " ORDER BY p.id ",
632
                (equipment2["id"],),
633
            )
634
            rows_points2 = cursor_system.fetchall()
635
636 View Code Duplication
            if rows_points2 is not None and len(rows_points2) > 0:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
637
                for point_row in rows_points2:
638
                    point_values = []
639
                    point_timestamps = []
640
641
                    if point_row[3] == "ENERGY_VALUE":
642
                        query = (
643
                            " SELECT utc_date_time, actual_value "
644
                            " FROM tbl_energy_value "
645
                            " WHERE point_id = %s "
646
                            " AND utc_date_time BETWEEN %s AND %s "
647
                            " ORDER BY utc_date_time "
648
                        )
649
                        cursor_historical.execute(
650
                            query,
651
                            (
652
                                point_row[0],
653
                                reporting_start_datetime_utc,
654
                                reporting_end_datetime_utc,
655
                            ),
656
                        )
657
                        rows = cursor_historical.fetchall()
658
659
                        if rows is not None and len(rows) > 0:
660
                            for row in rows:
661
                                current_datetime_local = row[0].replace(
662
                                    tzinfo=timezone.utc
663
                                ) + timedelta(minutes=timezone_offset)
664
                                current_datetime = current_datetime_local.isoformat()[
665
                                    0:19
666
                                ]
667
                                point_timestamps.append(current_datetime)
668
                                point_values.append(row[1])
669
                    elif point_row[3] == "ANALOG_VALUE":
670
                        query = (
671
                            " SELECT utc_date_time, actual_value "
672
                            " FROM tbl_analog_value "
673
                            " WHERE point_id = %s "
674
                            " AND utc_date_time BETWEEN %s AND %s "
675
                            " ORDER BY utc_date_time "
676
                        )
677
                        cursor_historical.execute(
678
                            query,
679
                            (
680
                                point_row[0],
681
                                reporting_start_datetime_utc,
682
                                reporting_end_datetime_utc,
683
                            ),
684
                        )
685
                        rows = cursor_historical.fetchall()
686
687
                        if rows is not None and len(rows) > 0:
688
                            for row in rows:
689
                                current_datetime_local = row[0].replace(
690
                                    tzinfo=timezone.utc
691
                                ) + timedelta(minutes=timezone_offset)
692
                                current_datetime = current_datetime_local.isoformat()[
693
                                    0:19
694
                                ]
695
                                point_timestamps.append(current_datetime)
696
                                point_values.append(row[1])
697
                    elif point_row[3] == "DIGITAL_VALUE":
698
                        query = (
699
                            " SELECT utc_date_time, actual_value "
700
                            " FROM tbl_digital_value "
701
                            " WHERE point_id = %s "
702
                            " AND utc_date_time BETWEEN %s AND %s "
703
                            " ORDER BY utc_date_time "
704
                        )
705
                        cursor_historical.execute(
706
                            query,
707
                            (
708
                                point_row[0],
709
                                reporting_start_datetime_utc,
710
                                reporting_end_datetime_utc,
711
                            ),
712
                        )
713
                        rows = cursor_historical.fetchall()
714
715
                        if rows is not None and len(rows) > 0:
716
                            for row in rows:
717
                                current_datetime_local = row[0].replace(
718
                                    tzinfo=timezone.utc
719
                                ) + timedelta(minutes=timezone_offset)
720
                                current_datetime = current_datetime_local.isoformat()[
721
                                    0:19
722
                                ]
723
                                point_timestamps.append(current_datetime)
724
                                point_values.append(row[1])
725
726
                    parameters_data2["names"].append(
727
                        equipment2["name"]
728
                        + " - "
729
                        + point_row[1]
730
                        + " ("
731
                        + point_row[2]
732
                        + ")"
733
                    )
734
                    parameters_data2["timestamps"].append(point_timestamps)
735
                    parameters_data2["values"].append(point_values)
736
737
        ################################################################################################################
738
        # Step 6: construct the report
739
        ################################################################################################################
740
        if cursor_system:
741
            cursor_system.close()
742
        if cnx_system:
743
            cnx_system.close()
744
745
        if cursor_energy:
746
            cursor_energy.close()
747
        if cnx_energy:
748
            cnx_energy.close()
749
750
        if cursor_historical:
751
            cursor_historical.close()
752
        if cnx_historical:
753
            cnx_historical.close()
754
755
        result = {
756
            "equipment1": {
757
                "id": equipment1["id"],
758
                "name": equipment1["name"],
759
            },
760
            "equipment2": {
761
                "id": equipment2["id"],
762
                "name": equipment2["name"],
763
            },
764
            "energy_category": {
765
                "id": energy_category["id"],
766
                "name": energy_category["name"],
767
                "unit_of_measure": energy_category["unit_of_measure"],
768
            },
769
            "reporting_period1": {
770
                "total_in_category": equipment1_energy_data["total_in_category"],
771
                "timestamps": equipment1_energy_data["timestamps"],
772
                "values": equipment1_energy_data["values"],
773
            },
774
            "reporting_period2": {
775
                "total_in_category": equipment2_energy_data["total_in_category"],
776
                "timestamps": equipment2_energy_data["timestamps"],
777
                "values": equipment2_energy_data["values"],
778
            },
779
            "parameters1": {
780
                "names": parameters_data1["names"],
781
                "timestamps": parameters_data1["timestamps"],
782
                "values": parameters_data1["values"],
783
            },
784
            "parameters2": {
785
                "names": parameters_data2["names"],
786
                "timestamps": parameters_data2["timestamps"],
787
                "values": parameters_data2["values"],
788
            },
789
            "diff": {
790
                "values": diff["values"],
791
                "total_in_category": diff["total_in_category"],
792
            },
793
        }
794
795
        # export result to Excel file and then encode the file to base64 string
796
        if not is_quick_mode:
797
            result["excel_bytes_base64"] = excelexporters.equipmentcomparison.export(
798
                result,
799
                equipment1["name"],
800
                equipment2["name"],
801
                energy_category["name"],
802
                reporting_period_start_datetime_local,
803
                reporting_period_end_datetime_local,
804
                period_type,
805
                language,
806
            )
807
808
        resp.text = json.dumps(result)
809