Issues (1656)

myems-api/reports/equipmentefficiency.py (7 issues)

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