reports.spaceefficiency   F
last analyzed

Complexity

Total Complexity 146

Size/Duplication

Total Lines 726
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 529
dl 0
loc 726
rs 2
c 0
b 0
f 0
wmc 146

3 Methods

Rating   Name   Duplication   Size   Complexity  
A Reporting.__init__() 0 3 1
A Reporting.on_options() 0 3 1
F Reporting.on_get() 0 692 144

How to fix   Complexity   

Complexity

Complex classes like reports.spaceefficiency 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 falcon
2
import simplejson as json
3
import mysql.connector
4
import config
5
from datetime import datetime, timedelta, timezone
6
from core import utilities
7
from decimal import Decimal
8
9
10
class Reporting:
11
    @staticmethod
12
    def __init__():
13
        pass
14
15
    @staticmethod
16
    def on_options(req, resp):
17
        resp.status = falcon.HTTP_200
18
19
    ####################################################################################################################
20
    # PROCEDURES
21
    # Step 1: valid parameters
22
    # Step 2: query the space
23
    # Step 3: query energy categories
24
    # Step 4: query associated sensors
25
    # Step 5: query associated points
26
    # Step 6: query base period energy input
27
    # Step 7: query base period energy output
28
    # Step 8: query reporting period energy input
29
    # Step 9: query reporting period energy output
30
    # Step 10: query tariff data
31
    # Step 11: query associated sensors and points data
32
    # Step 12: construct the report
33
    ####################################################################################################################
34
    @staticmethod
35
    def on_get(req, resp):
36
        print(req.params)
37
        space_id = req.params.get('spaceid')
38
        period_type = req.params.get('periodtype')
39
        base_start_datetime_local = req.params.get('baseperiodstartdatetime')
40
        base_end_datetime_local = req.params.get('baseperiodenddatetime')
41
        reporting_start_datetime_local = req.params.get('reportingperiodstartdatetime')
42
        reporting_end_datetime_local = req.params.get('reportingperiodenddatetime')
43
44
        ################################################################################################################
45
        # Step 1: valid parameters
46
        ################################################################################################################
47
        if space_id is None:
48
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST', description='API.INVALID_SPACE_ID')
49
        else:
50
            space_id = str.strip(space_id)
51
            if not space_id.isdigit() or int(space_id) <= 0:
52
                raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST', description='API.INVALID_SPACE_ID')
53
54
        if period_type is None:
55
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST', description='API.INVALID_PERIOD_TYPE')
56
        else:
57
            period_type = str.strip(period_type)
58
            if period_type not in ['hourly', 'daily', 'monthly', 'yearly']:
59
                raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST', description='API.INVALID_PERIOD_TYPE')
60
61
        timezone_offset = int(config.utc_offset[1:3]) * 60 + int(config.utc_offset[4:6])
62
        if config.utc_offset[0] == '-':
63
            timezone_offset = -timezone_offset
64
65
        base_start_datetime_utc = None
66
        if base_start_datetime_local is not None and len(str.strip(base_start_datetime_local)) > 0:
67
            base_start_datetime_local = str.strip(base_start_datetime_local)
68
            try:
69
                base_start_datetime_utc = datetime.strptime(base_start_datetime_local,
70
                                                            '%Y-%m-%dT%H:%M:%S').replace(tzinfo=timezone.utc) - \
71
                    timedelta(minutes=timezone_offset)
72
            except ValueError:
73
                raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
74
                                       description="API.INVALID_BASE_PERIOD_START_DATETIME")
75
76
        base_end_datetime_utc = None
77
        if base_end_datetime_local is not None and len(str.strip(base_end_datetime_local)) > 0:
78
            base_end_datetime_local = str.strip(base_end_datetime_local)
79
            try:
80
                base_end_datetime_utc = datetime.strptime(base_end_datetime_local,
81
                                                          '%Y-%m-%dT%H:%M:%S').replace(tzinfo=timezone.utc) - \
82
                    timedelta(minutes=timezone_offset)
83
            except ValueError:
84
                raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
85
                                       description="API.INVALID_BASE_PERIOD_END_DATETIME")
86
87
        if base_start_datetime_utc is not None and base_end_datetime_utc is not None and \
88
                base_start_datetime_utc >= base_end_datetime_utc:
89
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
90
                                   description='API.INVALID_BASE_PERIOD_END_DATETIME')
91
92
        if reporting_start_datetime_local is None:
93
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
94
                                   description="API.INVALID_REPORTING_PERIOD_START_DATETIME")
95
        else:
96
            reporting_start_datetime_local = str.strip(reporting_start_datetime_local)
97
            try:
98
                reporting_start_datetime_utc = datetime.strptime(reporting_start_datetime_local,
99
                                                                 '%Y-%m-%dT%H:%M:%S').replace(tzinfo=timezone.utc) - \
100
                    timedelta(minutes=timezone_offset)
101
            except ValueError:
102
                raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
103
                                       description="API.INVALID_REPORTING_PERIOD_START_DATETIME")
104
105
        if reporting_end_datetime_local is None:
106
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
107
                                   description="API.INVALID_REPORTING_PERIOD_END_DATETIME")
108
        else:
109
            reporting_end_datetime_local = str.strip(reporting_end_datetime_local)
110
            try:
111
                reporting_end_datetime_utc = datetime.strptime(reporting_end_datetime_local,
112
                                                               '%Y-%m-%dT%H:%M:%S').replace(tzinfo=timezone.utc) - \
113
                    timedelta(minutes=timezone_offset)
114
            except ValueError:
115
                raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
116
                                       description="API.INVALID_REPORTING_PERIOD_END_DATETIME")
117
118
        if reporting_start_datetime_utc >= reporting_end_datetime_utc:
119
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
120
                                   description='API.INVALID_REPORTING_PERIOD_END_DATETIME')
121
122
        ################################################################################################################
123
        # Step 2: query the space
124
        ################################################################################################################
125
        cnx_system = mysql.connector.connect(**config.myems_system_db)
126
        cursor_system = cnx_system.cursor()
127
128
        cnx_energy = mysql.connector.connect(**config.myems_energy_db)
129
        cursor_energy = cnx_energy.cursor()
130
131
        cnx_historical = mysql.connector.connect(**config.myems_historical_db)
132
        cursor_historical = cnx_historical.cursor()
133
134
        cursor_system.execute(" SELECT id, name, area, cost_center_id "
135
                              " FROM tbl_spaces "
136
                              " WHERE id = %s ", (space_id,))
137
        row_space = cursor_system.fetchone()
138
        if row_space is None:
139
            if cursor_system:
140
                cursor_system.close()
141
            if cnx_system:
142
                cnx_system.disconnect()
143
144
            if cursor_energy:
145
                cursor_energy.close()
146
            if cnx_energy:
147
                cnx_energy.disconnect()
148
149
            if cnx_historical:
150
                cnx_historical.close()
151
            if cursor_historical:
152
                cursor_historical.disconnect()
153
            raise falcon.HTTPError(falcon.HTTP_404, title='API.NOT_FOUND', description='API.SPACE_NOT_FOUND')
154
155
        space = dict()
156
        space['id'] = row_space[0]
157
        space['name'] = row_space[1]
158
        space['area'] = row_space[2]
159
        space['cost_center_id'] = row_space[3]
160
161
        ################################################################################################################
162
        # Step 3: query input energy categories and output energy categories
163
        ################################################################################################################
164
        energy_category_set_input = set()
165
        energy_category_set_output = set()
166
        # query input energy categories in base period
167
        cursor_energy.execute(" SELECT DISTINCT(energy_category_id) "
168
                              " FROM tbl_space_input_category_hourly "
169
                              " WHERE space_id = %s "
170
                              "     AND start_datetime_utc >= %s "
171
                              "     AND start_datetime_utc < %s ",
172
                              (space['id'], base_start_datetime_utc, base_end_datetime_utc))
173
        rows_energy_categories = cursor_energy.fetchall()
174
        if rows_energy_categories is not None or len(rows_energy_categories) > 0:
175
            for row_energy_category in rows_energy_categories:
176
                energy_category_set_input.add(row_energy_category[0])
177
178
        # query input energy categories in reporting period
179
        cursor_energy.execute(" SELECT DISTINCT(energy_category_id) "
180
                              " FROM tbl_space_input_category_hourly "
181
                              " WHERE space_id = %s "
182
                              "     AND start_datetime_utc >= %s "
183
                              "     AND start_datetime_utc < %s ",
184
                              (space['id'], reporting_start_datetime_utc, reporting_end_datetime_utc))
185
        rows_energy_categories = cursor_energy.fetchall()
186
        if rows_energy_categories is not None or len(rows_energy_categories) > 0:
187
            for row_energy_category in rows_energy_categories:
188
                energy_category_set_input.add(row_energy_category[0])
189
190
        # query output energy categories in base period
191
        cursor_energy.execute(" SELECT DISTINCT(energy_category_id) "
192
                              " FROM tbl_space_output_category_hourly "
193
                              " WHERE space_id = %s "
194
                              "     AND start_datetime_utc >= %s "
195
                              "     AND start_datetime_utc < %s ",
196
                              (space['id'], base_start_datetime_utc, base_end_datetime_utc))
197
        rows_energy_categories = cursor_energy.fetchall()
198
        if rows_energy_categories is not None or len(rows_energy_categories) > 0:
199
            for row_energy_category in rows_energy_categories:
200
                energy_category_set_output.add(row_energy_category[0])
201
202
        # query output energy categories in reporting period
203
        cursor_energy.execute(" SELECT DISTINCT(energy_category_id) "
204
                              " FROM tbl_space_output_category_hourly "
205
                              " WHERE space_id = %s "
206
                              "     AND start_datetime_utc >= %s "
207
                              "     AND start_datetime_utc < %s ",
208
                              (space['id'], reporting_start_datetime_utc, reporting_end_datetime_utc))
209
        rows_energy_categories = cursor_energy.fetchall()
210
        if rows_energy_categories is not None or len(rows_energy_categories) > 0:
211
            for row_energy_category in rows_energy_categories:
212
                energy_category_set_output.add(row_energy_category[0])
213
214
        # query properties of all energy categories above
215
        cursor_system.execute(" SELECT id, name, unit_of_measure, kgce, kgco2e "
216
                              " FROM tbl_energy_categories "
217
                              " ORDER BY id ", )
218
        rows_energy_categories = cursor_system.fetchall()
219
        if rows_energy_categories is None or len(rows_energy_categories) == 0:
220
            if cursor_system:
221
                cursor_system.close()
222
            if cnx_system:
223
                cnx_system.disconnect()
224
225
            if cursor_energy:
226
                cursor_energy.close()
227
            if cnx_energy:
228
                cnx_energy.disconnect()
229
230
            if cnx_historical:
231
                cnx_historical.close()
232
            if cursor_historical:
233
                cursor_historical.disconnect()
234
            raise falcon.HTTPError(falcon.HTTP_404,
235
                                   title='API.NOT_FOUND',
236
                                   description='API.ENERGY_CATEGORY_NOT_FOUND')
237
        energy_category_dict = dict()
238
        for row_energy_category in rows_energy_categories:
239
            if row_energy_category[0] in energy_category_set_input or \
240
                    row_energy_category[0] in energy_category_set_output:
241
                energy_category_dict[row_energy_category[0]] = {"name": row_energy_category[1],
242
                                                                "unit_of_measure": row_energy_category[2],
243
                                                                "kgce": row_energy_category[3],
244
                                                                "kgco2e": row_energy_category[4]}
245
246
        ################################################################################################################
247
        # Step 4: query associated sensors
248
        ################################################################################################################
249
        point_list = list()
250
        cursor_system.execute(" SELECT po.id, po.name, po.units, po.object_type  "
251
                              " FROM tbl_spaces sp, tbl_sensors se, tbl_spaces_sensors spse, "
252
                              "      tbl_points po, tbl_sensors_points sepo "
253
                              " WHERE sp.id = %s AND sp.id = spse.space_id AND spse.sensor_id = se.id "
254
                              "       AND se.id = sepo.sensor_id AND sepo.point_id = po.id "
255
                              " ORDER BY po.id ", (space['id'], ))
256
        rows_points = cursor_system.fetchall()
257
        if rows_points is not None and len(rows_points) > 0:
258
            for row in rows_points:
259
                point_list.append({"id": row[0], "name": row[1], "units": row[2], "object_type": row[3]})
260
261
        ################################################################################################################
262
        # Step 5: query associated points
263
        ################################################################################################################
264
        cursor_system.execute(" SELECT po.id, po.name, po.units, po.object_type  "
265
                              " FROM tbl_spaces sp, tbl_spaces_points sppo, tbl_points po "
266
                              " WHERE sp.id = %s AND sp.id = sppo.space_id AND sppo.point_id = po.id "
267
                              " ORDER BY po.id ", (space['id'], ))
268
        rows_points = cursor_system.fetchall()
269
        if rows_points is not None and len(rows_points) > 0:
270
            for row in rows_points:
271
                point_list.append({"id": row[0], "name": row[1], "units": row[2], "object_type": row[3]})
272
273
        ################################################################################################################
274
        # Step 6: query base period energy input
275
        ################################################################################################################
276
        base_input = dict()
277
        if energy_category_set_input is not None and len(energy_category_set_input) > 0:
278
            for energy_category_id in energy_category_set_input:
279
                base_input[energy_category_id] = dict()
280
                base_input[energy_category_id]['timestamps'] = list()
281
                base_input[energy_category_id]['values'] = list()
282
                base_input[energy_category_id]['subtotal'] = Decimal(0.0)
283
284
                cursor_energy.execute(" SELECT start_datetime_utc, actual_value "
285
                                      " FROM tbl_space_input_category_hourly "
286
                                      " WHERE space_id = %s "
287
                                      "     AND energy_category_id = %s "
288
                                      "     AND start_datetime_utc >= %s "
289
                                      "     AND start_datetime_utc < %s "
290
                                      " ORDER BY start_datetime_utc ",
291
                                      (space['id'],
292
                                       energy_category_id,
293
                                       base_start_datetime_utc,
294
                                       base_end_datetime_utc))
295
                rows_space_hourly = cursor_energy.fetchall()
296
297
                rows_space_periodically = utilities.aggregate_hourly_data_by_period(rows_space_hourly,
298
                                                                                    base_start_datetime_utc,
299
                                                                                    base_end_datetime_utc,
300
                                                                                    period_type)
301
                for row_space_periodically in rows_space_periodically:
302
                    current_datetime_local = row_space_periodically[0].replace(tzinfo=timezone.utc) + \
303
                                             timedelta(minutes=timezone_offset)
304
                    if period_type == 'hourly':
305
                        current_datetime = current_datetime_local.strftime('%Y-%m-%dT%H:%M:%S')
306
                    elif period_type == 'daily':
307
                        current_datetime = current_datetime_local.strftime('%Y-%m-%d')
308
                    elif period_type == 'monthly':
309
                        current_datetime = current_datetime_local.strftime('%Y-%m')
310
                    elif period_type == 'yearly':
311
                        current_datetime = current_datetime_local.strftime('%Y')
312
313
                    actual_value = Decimal(0.0) if row_space_periodically[1] is None else row_space_periodically[1]
314
                    base_input[energy_category_id]['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...
315
                    base_input[energy_category_id]['values'].append(actual_value)
316
                    base_input[energy_category_id]['subtotal'] += actual_value
317
318
        ################################################################################################################
319
        # Step 7: query base period energy output
320
        ################################################################################################################
321
        base_output = dict()
322
        if energy_category_set_output is not None and len(energy_category_set_output) > 0:
323
            for energy_category_id in energy_category_set_output:
324
                base_output[energy_category_id] = dict()
325
                base_output[energy_category_id]['timestamps'] = list()
326
                base_output[energy_category_id]['values'] = list()
327
                base_output[energy_category_id]['subtotal'] = Decimal(0.0)
328
329
                cursor_energy.execute(" SELECT start_datetime_utc, actual_value "
330
                                      " FROM tbl_space_output_category_hourly "
331
                                      " WHERE space_id = %s "
332
                                      "     AND energy_category_id = %s "
333
                                      "     AND start_datetime_utc >= %s "
334
                                      "     AND start_datetime_utc < %s "
335
                                      " ORDER BY start_datetime_utc ",
336
                                      (space['id'],
337
                                       energy_category_id,
338
                                       base_start_datetime_utc,
339
                                       base_end_datetime_utc))
340
                rows_space_hourly = cursor_energy.fetchall()
341
342
                rows_space_periodically = utilities.aggregate_hourly_data_by_period(rows_space_hourly,
343
                                                                                    base_start_datetime_utc,
344
                                                                                    base_end_datetime_utc,
345
                                                                                    period_type)
346
                for row_space_periodically in rows_space_periodically:
347
                    current_datetime_local = row_space_periodically[0].replace(tzinfo=timezone.utc) + \
348
                                             timedelta(minutes=timezone_offset)
349
                    if period_type == 'hourly':
350
                        current_datetime = current_datetime_local.strftime('%Y-%m-%dT%H:%M:%S')
351
                    elif period_type == 'daily':
352
                        current_datetime = current_datetime_local.strftime('%Y-%m-%d')
353
                    elif period_type == 'monthly':
354
                        current_datetime = current_datetime_local.strftime('%Y-%m')
355
                    elif period_type == 'yearly':
356
                        current_datetime = current_datetime_local.strftime('%Y')
357
358
                    actual_value = Decimal(0.0) if row_space_periodically[1] is None else row_space_periodically[1]
359
                    base_output[energy_category_id]['timestamps'].append(current_datetime)
360
                    base_output[energy_category_id]['values'].append(actual_value)
361
                    base_output[energy_category_id]['subtotal'] += actual_value
362
        ################################################################################################################
363
        # Step 8: query reporting period energy input
364
        ################################################################################################################
365
        reporting_input = dict()
366
        if energy_category_set_input is not None and len(energy_category_set_input) > 0:
367
            for energy_category_id in energy_category_set_input:
368
369
                reporting_input[energy_category_id] = dict()
370
                reporting_input[energy_category_id]['timestamps'] = list()
371
                reporting_input[energy_category_id]['values'] = list()
372
                reporting_input[energy_category_id]['subtotal'] = Decimal(0.0)
373
374
                cursor_energy.execute(" SELECT start_datetime_utc, actual_value "
375
                                      " FROM tbl_space_input_category_hourly "
376
                                      " WHERE space_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
                                      (space['id'],
382
                                       energy_category_id,
383
                                       reporting_start_datetime_utc,
384
                                       reporting_end_datetime_utc))
385
                rows_space_hourly = cursor_energy.fetchall()
386
387
                rows_space_periodically = utilities.aggregate_hourly_data_by_period(rows_space_hourly,
388
                                                                                    reporting_start_datetime_utc,
389
                                                                                    reporting_end_datetime_utc,
390
                                                                                    period_type)
391
                for row_space_periodically in rows_space_periodically:
392
                    current_datetime_local = row_space_periodically[0].replace(tzinfo=timezone.utc) + \
393
                                             timedelta(minutes=timezone_offset)
394
                    if period_type == 'hourly':
395
                        current_datetime = current_datetime_local.strftime('%Y-%m-%dT%H:%M:%S')
396
                    elif period_type == 'daily':
397
                        current_datetime = current_datetime_local.strftime('%Y-%m-%d')
398
                    elif period_type == 'monthly':
399
                        current_datetime = current_datetime_local.strftime('%Y-%m')
400
                    elif period_type == 'yearly':
401
                        current_datetime = current_datetime_local.strftime('%Y')
402
403
                    actual_value = Decimal(0.0) if row_space_periodically[1] is None else row_space_periodically[1]
404
                    reporting_input[energy_category_id]['timestamps'].append(current_datetime)
405
                    reporting_input[energy_category_id]['values'].append(actual_value)
406
                    reporting_input[energy_category_id]['subtotal'] += actual_value
407
408
        ################################################################################################################
409
        # Step 9: query reporting period energy output
410
        ################################################################################################################
411
        reporting_output = dict()
412
        if energy_category_set_output is not None and len(energy_category_set_output) > 0:
413
            for energy_category_id in energy_category_set_output:
414
415
                reporting_output[energy_category_id] = dict()
416
                reporting_output[energy_category_id]['timestamps'] = list()
417
                reporting_output[energy_category_id]['values'] = list()
418
                reporting_output[energy_category_id]['subtotal'] = Decimal(0.0)
419
420
                cursor_energy.execute(" SELECT start_datetime_utc, actual_value "
421
                                      " FROM tbl_space_output_category_hourly "
422
                                      " WHERE space_id = %s "
423
                                      "     AND energy_category_id = %s "
424
                                      "     AND start_datetime_utc >= %s "
425
                                      "     AND start_datetime_utc < %s "
426
                                      " ORDER BY start_datetime_utc ",
427
                                      (space['id'],
428
                                       energy_category_id,
429
                                       reporting_start_datetime_utc,
430
                                       reporting_end_datetime_utc))
431
                rows_space_hourly = cursor_energy.fetchall()
432
433
                rows_space_periodically = utilities.aggregate_hourly_data_by_period(rows_space_hourly,
434
                                                                                    reporting_start_datetime_utc,
435
                                                                                    reporting_end_datetime_utc,
436
                                                                                    period_type)
437
                for row_space_periodically in rows_space_periodically:
438
                    current_datetime_local = row_space_periodically[0].replace(tzinfo=timezone.utc) + \
439
                                             timedelta(minutes=timezone_offset)
440
                    if period_type == 'hourly':
441
                        current_datetime = current_datetime_local.strftime('%Y-%m-%dT%H:%M:%S')
442
                    elif period_type == 'daily':
443
                        current_datetime = current_datetime_local.strftime('%Y-%m-%d')
444
                    elif period_type == 'monthly':
445
                        current_datetime = current_datetime_local.strftime('%Y-%m')
446
                    elif period_type == 'yearly':
447
                        current_datetime = current_datetime_local.strftime('%Y')
448
449
                    actual_value = Decimal(0.0) if row_space_periodically[1] is None else row_space_periodically[1]
450
                    reporting_output[energy_category_id]['timestamps'].append(current_datetime)
451
                    reporting_output[energy_category_id]['values'].append(actual_value)
452
                    reporting_output[energy_category_id]['subtotal'] += actual_value
453
454
        ################################################################################################################
455
        # Step 10: query tariff data
456
        ################################################################################################################
457
        parameters_data = dict()
458
        parameters_data['names'] = list()
459
        parameters_data['timestamps'] = list()
460
        parameters_data['values'] = list()
461
        if energy_category_set_input is not None and len(energy_category_set_input) > 0:
462
            for energy_category_id in energy_category_set_input:
463
                energy_category_tariff_dict = utilities.get_energy_category_tariffs(space['cost_center_id'],
464
                                                                                    energy_category_id,
465
                                                                                    reporting_start_datetime_utc,
466
                                                                                    reporting_end_datetime_utc)
467
                tariff_timestamp_list = list()
468
                tariff_value_list = list()
469
                for k, v in energy_category_tariff_dict.items():
470
                    # convert k from utc to local
471
                    k = k + timedelta(minutes=timezone_offset)
472
                    tariff_timestamp_list.append(k.isoformat()[0:19][0:19])
473
                    tariff_value_list.append(v)
474
475
                parameters_data['names'].append('TARIFF-' + energy_category_dict[energy_category_id]['name'])
476
                parameters_data['timestamps'].append(tariff_timestamp_list)
477
                parameters_data['values'].append(tariff_value_list)
478
479
        ################################################################################################################
480
        # Step 11: query associated sensors and points data
481
        ################################################################################################################
482
        for point in point_list:
483
            point_values = []
484
            point_timestamps = []
485
            if point['object_type'] == 'ANALOG_VALUE':
486
                query = (" SELECT utc_date_time, actual_value "
487
                         " FROM tbl_analog_value "
488
                         " WHERE point_id = %s "
489
                         "       AND utc_date_time BETWEEN %s AND %s "
490
                         " ORDER BY utc_date_time ")
491
                cursor_historical.execute(query, (point['id'],
492
                                                  reporting_start_datetime_utc,
493
                                                  reporting_end_datetime_utc))
494
                rows = cursor_historical.fetchall()
495
496
                if rows is not None and len(rows) > 0:
497
                    for row in rows:
498
                        current_datetime_local = row[0].replace(tzinfo=timezone.utc) + \
499
                                                 timedelta(minutes=timezone_offset)
500
                        current_datetime = current_datetime_local.strftime('%Y-%m-%dT%H:%M:%S')
501
                        point_timestamps.append(current_datetime)
502
                        point_values.append(row[1])
503
504
            elif point['object_type'] == 'ENERGY_VALUE':
505
                query = (" SELECT utc_date_time, actual_value "
506
                         " FROM tbl_energy_value "
507
                         " WHERE point_id = %s "
508
                         "       AND utc_date_time BETWEEN %s AND %s "
509
                         " ORDER BY utc_date_time ")
510
                cursor_historical.execute(query, (point['id'],
511
                                                  reporting_start_datetime_utc,
512
                                                  reporting_end_datetime_utc))
513
                rows = cursor_historical.fetchall()
514
515
                if rows is not None and len(rows) > 0:
516
                    for row in rows:
517
                        current_datetime_local = row[0].replace(tzinfo=timezone.utc) + \
518
                                                 timedelta(minutes=timezone_offset)
519
                        current_datetime = current_datetime_local.strftime('%Y-%m-%dT%H:%M:%S')
520
                        point_timestamps.append(current_datetime)
521
                        point_values.append(row[1])
522
            elif point['object_type'] == 'DIGITAL_VALUE':
523
                query = (" SELECT utc_date_time, actual_value "
524
                         " FROM tbl_digital_value "
525
                         " WHERE point_id = %s "
526
                         "       AND utc_date_time BETWEEN %s AND %s ")
527
                cursor_historical.execute(query, (point['id'],
528
                                                  reporting_start_datetime_utc,
529
                                                  reporting_end_datetime_utc))
530
                rows = cursor_historical.fetchall()
531
532
                if rows is not None and len(rows) > 0:
533
                    for row in rows:
534
                        current_datetime_local = row[0].replace(tzinfo=timezone.utc) + \
535
                                                 timedelta(minutes=timezone_offset)
536
                        current_datetime = current_datetime_local.strftime('%Y-%m-%dT%H:%M:%S')
537
                        point_timestamps.append(current_datetime)
538
                        point_values.append(row[1])
539
540
            parameters_data['names'].append(point['name'] + ' (' + point['units'] + ')')
541
            parameters_data['timestamps'].append(point_timestamps)
542
            parameters_data['values'].append(point_values)
543
544
        ################################################################################################################
545
        # Step 12: construct the report
546
        ################################################################################################################
547
        if cursor_system:
548
            cursor_system.close()
549
        if cnx_system:
550
            cnx_system.disconnect()
551
552
        if cursor_energy:
553
            cursor_energy.close()
554
        if cnx_energy:
555
            cnx_energy.disconnect()
556
557
        result = dict()
558
559
        result['space'] = dict()
560
        result['space']['name'] = space['name']
561
        result['space']['area'] = space['area']
562
563
        result['base_period_input'] = dict()
564
        result['base_period_input']['names'] = list()
565
        result['base_period_input']['units'] = list()
566
        result['base_period_input']['timestamps'] = list()
567
        result['base_period_input']['values'] = list()
568
        result['base_period_input']['subtotals'] = list()
569
        if energy_category_set_input is not None and len(energy_category_set_input) > 0:
570
            for energy_category_id in energy_category_set_input:
571
                result['base_period_input']['names'].append(energy_category_dict[energy_category_id]['name'])
572
                result['base_period_input']['units'].append(energy_category_dict[energy_category_id]['unit_of_measure'])
573
                result['base_period_input']['timestamps'].append(base_input[energy_category_id]['timestamps'])
574
                result['base_period_input']['values'].append(base_input[energy_category_id]['values'])
575
                result['base_period_input']['subtotals'].append(base_input[energy_category_id]['subtotal'])
576
577
        result['base_period_output'] = dict()
578
        result['base_period_output']['names'] = list()
579
        result['base_period_output']['units'] = list()
580
        result['base_period_output']['timestamps'] = list()
581
        result['base_period_output']['values'] = list()
582
        result['base_period_output']['subtotals'] = list()
583
584
        if energy_category_set_output is not None and len(energy_category_set_output) > 0:
585
            for energy_category_id in energy_category_set_output:
586
                result['base_period_output']['names'].append(energy_category_dict[energy_category_id]['name'])
587
                result['base_period_output']['units'].append(
588
                    energy_category_dict[energy_category_id]['unit_of_measure'])
589
                result['base_period_output']['timestamps'].append(base_output[energy_category_id]['timestamps'])
590
                result['base_period_output']['values'].append(base_output[energy_category_id]['values'])
591
                result['base_period_output']['subtotals'].append(base_output[energy_category_id]['subtotal'])
592
593
        result['base_period_efficiency'] = dict()
594
        result['base_period_efficiency']['names'] = list()
595
        result['base_period_efficiency']['units'] = list()
596
        result['base_period_efficiency']['timestamps'] = list()
597
        result['base_period_efficiency']['values'] = list()
598
        result['base_period_efficiency']['cumulations'] = list()
599
600
        if energy_category_set_output is not None and len(energy_category_set_output) > 0:
601
            for energy_category_id_output in energy_category_set_output:
602
                for energy_category_id_input in energy_category_set_input:
603
                    result['base_period_efficiency']['names'].append(
604
                        energy_category_dict[energy_category_id_output]['name'] + '/' +
605
                        energy_category_dict[energy_category_id_input]['name'])
606
                    result['base_period_efficiency']['units'].append(
607
                        energy_category_dict[energy_category_id_output]['unit_of_measure'] + '/' +
608
                        energy_category_dict[energy_category_id_input]['unit_of_measure'])
609
                    result['base_period_efficiency']['timestamps'].append(
610
                        base_output[energy_category_id_output]['timestamps'])
611
                    efficiency_values = list()
612
                    for i in range(len(base_output[energy_category_id_output]['timestamps'])):
613
                        efficiency_values.append((base_output[energy_category_id_output]['values'][i] /
614
                                                  base_input[energy_category_id_input]['values'][i])
615
                                                 if base_input[energy_category_id_input]['values'][i] > Decimal(0.0)
616
                                                 else None)
617
                    result['base_period_efficiency']['values'].append(efficiency_values)
618
619
                    base_cumulation = (base_output[energy_category_id_output]['subtotal'] /
620
                                       base_input[energy_category_id_input]['subtotal']) if \
621
                        base_input[energy_category_id_input]['subtotal'] > Decimal(0.0) else None
622
                    result['base_period_efficiency']['cumulations'].append(base_cumulation)
623
624
        result['reporting_period_input'] = dict()
625
        result['reporting_period_input']['names'] = list()
626
        result['reporting_period_input']['energy_category_ids'] = list()
627
        result['reporting_period_input']['units'] = list()
628
        result['reporting_period_input']['timestamps'] = list()
629
        result['reporting_period_input']['values'] = list()
630
        result['reporting_period_input']['subtotals'] = list()
631
        result['reporting_period_input']['subtotals_per_unit_area'] = list()
632
        result['reporting_period_input']['increment_rates'] = list()
633
634
        if energy_category_set_input is not None and len(energy_category_set_input) > 0:
635
            for energy_category_id in energy_category_set_input:
636
                result['reporting_period_input']['names'].append(energy_category_dict[energy_category_id]['name'])
637
                result['reporting_period_input']['energy_category_ids'].append(energy_category_id)
638
                result['reporting_period_input']['units'].append(
639
                    energy_category_dict[energy_category_id]['unit_of_measure'])
640
                result['reporting_period_input']['timestamps'].append(
641
                    reporting_input[energy_category_id]['timestamps'])
642
                result['reporting_period_input']['values'].append(
643
                    reporting_input[energy_category_id]['values'])
644
                result['reporting_period_input']['subtotals'].append(
645
                    reporting_input[energy_category_id]['subtotal'])
646
                result['reporting_period_input']['increment_rates'].append(
647
                    (reporting_input[energy_category_id]['subtotal'] -
648
                     base_input[energy_category_id]['subtotal']) /
649
                    base_input[energy_category_id]['subtotal']
650
                    if base_input[energy_category_id]['subtotal'] > 0.0 else None)
651
652
        result['reporting_period_output'] = dict()
653
        result['reporting_period_output']['names'] = list()
654
        result['reporting_period_output']['energy_category_ids'] = list()
655
        result['reporting_period_output']['units'] = list()
656
        result['reporting_period_output']['timestamps'] = list()
657
        result['reporting_period_output']['values'] = list()
658
        result['reporting_period_output']['subtotals'] = list()
659
        result['reporting_period_output']['subtotals_per_unit_area'] = list()
660
        result['reporting_period_output']['increment_rates'] = list()
661
662
        if energy_category_set_output is not None and len(energy_category_set_output) > 0:
663
            for energy_category_id in energy_category_set_output:
664
                result['reporting_period_output']['names'].append(energy_category_dict[energy_category_id]['name'])
665
                result['reporting_period_output']['energy_category_ids'].append(energy_category_id)
666
                result['reporting_period_output']['units'].append(
667
                    energy_category_dict[energy_category_id]['unit_of_measure'])
668
                result['reporting_period_output']['timestamps'].append(
669
                    reporting_output[energy_category_id]['timestamps'])
670
                result['reporting_period_output']['values'].append(reporting_output[energy_category_id]['values'])
671
                result['reporting_period_output']['subtotals'].append(reporting_output[energy_category_id]['subtotal'])
672
                result['reporting_period_output']['increment_rates'].append(
673
                    (reporting_output[energy_category_id]['subtotal'] -
674
                     base_output[energy_category_id]['subtotal']) /
675
                    base_output[energy_category_id]['subtotal']
676
                    if base_output[energy_category_id]['subtotal'] > 0.0 else None)
677
678
        result['reporting_period_efficiency'] = dict()
679
        result['reporting_period_efficiency']['names'] = list()
680
        result['reporting_period_efficiency']['units'] = list()
681
        result['reporting_period_efficiency']['timestamps'] = list()
682
        result['reporting_period_efficiency']['values'] = list()
683
        result['reporting_period_efficiency']['cumulations'] = list()
684
        result['reporting_period_efficiency']['increment_rates'] = list()
685
686
        if energy_category_set_output is not None and len(energy_category_set_output) > 0:
687
            for energy_category_id_output in energy_category_set_output:
688
                for energy_category_id_input in energy_category_set_input:
689
                    result['reporting_period_efficiency']['names'].append(
690
                        energy_category_dict[energy_category_id_output]['name'] + '/' +
691
                        energy_category_dict[energy_category_id_input]['name'])
692
                    result['reporting_period_efficiency']['units'].append(
693
                        energy_category_dict[energy_category_id_output]['unit_of_measure'] + '/' +
694
                        energy_category_dict[energy_category_id_input]['unit_of_measure'])
695
                    result['reporting_period_efficiency']['timestamps'].append(
696
                        reporting_output[energy_category_id_output]['timestamps'])
697
                    efficiency_values = list()
698
                    for i in range(len(reporting_output[energy_category_id_output]['timestamps'])):
699
                        efficiency_values.append((reporting_output[energy_category_id_output]['values'][i] /
700
                                                 reporting_input[energy_category_id_input]['values'][i])
701
                                                 if reporting_input[energy_category_id_input]['values'][i] >
702
                                                 Decimal(0.0) else None)
703
                    result['reporting_period_efficiency']['values'].append(efficiency_values)
704
705
                    base_cumulation = (base_output[energy_category_id_output]['subtotal'] /
706
                                       base_input[energy_category_id_input]['subtotal']) if \
707
                        base_input[energy_category_id_input]['subtotal'] > Decimal(0.0) else None
708
709
                    reporting_cumulation = (reporting_output[energy_category_id_output]['subtotal'] /
710
                                            reporting_input[energy_category_id_input]['subtotal']) if \
711
                        reporting_input[energy_category_id_input]['subtotal'] > Decimal(0.0) else None
712
713
                    result['reporting_period_efficiency']['cumulations'].append(reporting_cumulation)
714
                    result['reporting_period_efficiency']['increment_rates'].append(
715
                        ((reporting_cumulation - base_cumulation) / base_cumulation if (base_cumulation > Decimal(0.0))
716
                         else None)
717
                    )
718
719
        result['parameters'] = {
720
            "names": parameters_data['names'],
721
            "timestamps": parameters_data['timestamps'],
722
            "values": parameters_data['values']
723
        }
724
725
        resp.body = json.dumps(result)
726