Passed
Push — master ( 3d0162...da93a4 )
by Guangyu
07:26 queued 13s
created

reports.metercarbon.Reporting.on_get()   F

Complexity

Conditions 82

Size

Total Lines 462
Code Lines 333

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 333
dl 0
loc 462
rs 0
c 0
b 0
f 0
cc 82
nop 2

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

Complexity

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

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

1
import re
2
import falcon
3
import simplejson as json
4
import mysql.connector
5
import config
6
from datetime import datetime, timedelta, timezone
7
from core import utilities
8
from decimal import Decimal
9
import excelexporters.metercarbon
10
11
12
class Reporting:
13
    @staticmethod
14
    def __init__():
15
        """"Initializes Reporting"""
16
        pass
17
18
    @staticmethod
19
    def on_options(req, resp):
20
        resp.status = falcon.HTTP_200
21
22
    ####################################################################################################################
23
    # PROCEDURES
24
    # Step 1: valid parameters
25
    # Step 2: query the meter and energy category
26
    # Step 3: query associated points
27
    # Step 4: query base period energy consumption
28
    # Step 5: query base period carbon dioxide emission
29
    # Step 6: query reporting period energy consumption
30
    # Step 7: query reporting period carbon dioxide emission
31
    # Step 8: query tariff data
32
    # Step 9: query associated points data
33
    # Step 10: construct the report
34
    ####################################################################################################################
35
    @staticmethod
36
    def on_get(req, resp):
37
        print(req.params)
38
        meter_id = req.params.get('meterid')
39
        meter_uuid = req.params.get('meteruuid')
40
        period_type = req.params.get('periodtype')
41
        base_period_start_datetime_local = req.params.get('baseperiodstartdatetime')
42
        base_period_end_datetime_local = req.params.get('baseperiodenddatetime')
43
        reporting_period_start_datetime_local = req.params.get('reportingperiodstartdatetime')
44
        reporting_period_end_datetime_local = req.params.get('reportingperiodenddatetime')
45
46
        ################################################################################################################
47
        # Step 1: valid parameters
48
        ################################################################################################################
49
        if meter_id is None and meter_uuid is None:
50
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST', description='API.INVALID_METER_ID')
51
52
        if meter_id is not None:
53
            meter_id = str.strip(meter_id)
54
            if not meter_id.isdigit() or int(meter_id) <= 0:
55
                raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST', description='API.INVALID_METER_ID')
56
57
        if meter_uuid is not None:
58
            meter_uuid = str.strip(meter_uuid)
59
            regex = re.compile('^[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)
60
            match = regex.match(meter_uuid)
61
            if not bool(match):
62
                raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST', description='API.INVALID_METER_UUID')
63
64
        if period_type is None:
65
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST', description='API.INVALID_PERIOD_TYPE')
66
        else:
67
            period_type = str.strip(period_type)
68
            if period_type not in ['hourly', 'daily', 'weekly', 'monthly', 'yearly']:
69
                raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST', description='API.INVALID_PERIOD_TYPE')
70
71
        timezone_offset = int(config.utc_offset[1:3]) * 60 + int(config.utc_offset[4:6])
72
        if config.utc_offset[0] == '-':
73
            timezone_offset = -timezone_offset
74
75
        base_start_datetime_utc = None
76
        if base_period_start_datetime_local is not None and len(str.strip(base_period_start_datetime_local)) > 0:
77
            base_period_start_datetime_local = str.strip(base_period_start_datetime_local)
78
            try:
79
                base_start_datetime_utc = datetime.strptime(base_period_start_datetime_local, '%Y-%m-%dT%H:%M:%S')
80
            except ValueError:
81
                raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
82
                                       description="API.INVALID_BASE_PERIOD_START_DATETIME")
83
            base_start_datetime_utc = base_start_datetime_utc.replace(tzinfo=timezone.utc) - \
84
                timedelta(minutes=timezone_offset)
85
86
        base_end_datetime_utc = None
87
        if base_period_end_datetime_local is not None and len(str.strip(base_period_end_datetime_local)) > 0:
88
            base_period_end_datetime_local = str.strip(base_period_end_datetime_local)
89
            try:
90
                base_end_datetime_utc = datetime.strptime(base_period_end_datetime_local, '%Y-%m-%dT%H:%M:%S')
91
            except ValueError:
92
                raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
93
                                       description="API.INVALID_BASE_PERIOD_END_DATETIME")
94
            base_end_datetime_utc = base_end_datetime_utc.replace(tzinfo=timezone.utc) - \
95
                timedelta(minutes=timezone_offset)
96
97
        if base_start_datetime_utc is not None and base_end_datetime_utc is not None and \
98
                base_start_datetime_utc >= base_end_datetime_utc:
99
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
100
                                   description='API.INVALID_BASE_PERIOD_END_DATETIME')
101
102
        if reporting_period_start_datetime_local is None:
103
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
104
                                   description="API.INVALID_REPORTING_PERIOD_START_DATETIME")
105
        else:
106
            reporting_period_start_datetime_local = str.strip(reporting_period_start_datetime_local)
107
            try:
108
                reporting_start_datetime_utc = datetime.strptime(reporting_period_start_datetime_local,
109
                                                                 '%Y-%m-%dT%H:%M:%S')
110
            except ValueError:
111
                raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
112
                                       description="API.INVALID_REPORTING_PERIOD_START_DATETIME")
113
            reporting_start_datetime_utc = reporting_start_datetime_utc.replace(tzinfo=timezone.utc) - \
114
                timedelta(minutes=timezone_offset)
115
116
        if reporting_period_end_datetime_local is None:
117
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
118
                                   description="API.INVALID_REPORTING_PERIOD_END_DATETIME")
119
        else:
120
            reporting_period_end_datetime_local = str.strip(reporting_period_end_datetime_local)
121
            try:
122
                reporting_end_datetime_utc = datetime.strptime(reporting_period_end_datetime_local,
123
                                                               '%Y-%m-%dT%H:%M:%S')
124
            except ValueError:
125
                raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
126
                                       description="API.INVALID_REPORTING_PERIOD_END_DATETIME")
127
            reporting_end_datetime_utc = reporting_end_datetime_utc.replace(tzinfo=timezone.utc) - \
128
                timedelta(minutes=timezone_offset)
129
130
        if reporting_start_datetime_utc >= reporting_end_datetime_utc:
131
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
132
                                   description='API.INVALID_REPORTING_PERIOD_END_DATETIME')
133
134
        ################################################################################################################
135
        # Step 2: query the meter and energy category
136
        ################################################################################################################
137
        cnx_system = mysql.connector.connect(**config.myems_system_db)
138
        cursor_system = cnx_system.cursor()
139
140
        cnx_energy = mysql.connector.connect(**config.myems_energy_db)
141
        cursor_energy = cnx_energy.cursor()
142
143
        cnx_carbon = mysql.connector.connect(**config.myems_carbon_db)
144
        cursor_carbon = cnx_carbon.cursor()
145
146
        cnx_historical = mysql.connector.connect(**config.myems_historical_db)
147
        cursor_historical = cnx_historical.cursor()
148
        if meter_id is not None:
149
            cursor_system.execute(" SELECT m.id, m.name, m.cost_center_id, m.energy_category_id, "
150
                                  "        ec.name, ec.unit_of_measure, ec.kgce, ec.kgco2e "
151
                                  " FROM tbl_meters m, tbl_energy_categories ec "
152
                                  " WHERE m.id = %s AND m.energy_category_id = ec.id ", (meter_id,))
153
            row_meter = cursor_system.fetchone()
154
        elif meter_uuid is not None:
155
            cursor_system.execute(" SELECT m.id, m.name, m.cost_center_id, m.energy_category_id, "
156
                                  "        ec.name, ec.unit_of_measure, ec.kgce, ec.kgco2e "
157
                                  " FROM tbl_meters m, tbl_energy_categories ec "
158
                                  " WHERE m.uuid = %s AND m.energy_category_id = ec.id ", (meter_uuid,))
159
            row_meter = cursor_system.fetchone()
160
161
        if row_meter is None:
0 ignored issues
show
introduced by
The variable row_meter does not seem to be defined for all execution paths.
Loading history...
162
            if cursor_system:
163
                cursor_system.close()
164
            if cnx_system:
165
                cnx_system.disconnect()
166
167
            if cursor_energy:
168
                cursor_energy.close()
169
            if cnx_energy:
170
                cnx_energy.disconnect()
171
172
            if cursor_carbon:
173
                cursor_carbon.close()
174
            if cnx_carbon:
175
                cnx_carbon.disconnect()
176
177
            if cursor_historical:
178
                cursor_historical.close()
179
            if cnx_historical:
180
                cnx_historical.disconnect()
181
            raise falcon.HTTPError(falcon.HTTP_404, title='API.NOT_FOUND', description='API.METER_NOT_FOUND')
182
        if meter_id is not None and int(meter_id) != int(row_meter[0]):
183
            raise falcon.HTTPError(falcon.HTTP_404, title='API.NOT_FOUND', description='API.METER_NOT_FOUND')
184
        meter = dict()
185
        meter['id'] = row_meter[0]
186
        meter['name'] = row_meter[1]
187
        meter['cost_center_id'] = row_meter[2]
188
        meter['energy_category_id'] = row_meter[3]
189
        meter['energy_category_name'] = row_meter[4]
190
        meter['unit_of_measure'] = config.currency_unit
191
        meter['kgce'] = row_meter[6]
192
        meter['kgco2e'] = row_meter[7]
193
194
        ################################################################################################################
195
        # Step 3: query associated points
196
        ################################################################################################################
197
        point_list = list()
198
        cursor_system.execute(" SELECT p.id, p.name, p.units, p.object_type  "
199
                              " FROM tbl_meters m, tbl_meters_points mp, tbl_points p "
200
                              " WHERE m.id = %s AND m.id = mp.meter_id AND mp.point_id = p.id "
201
                              " ORDER BY p.id ", (meter['id'],))
202
        rows_points = cursor_system.fetchall()
203
        if rows_points is not None and len(rows_points) > 0:
204
            for row in rows_points:
205
                point_list.append({"id": row[0], "name": row[1], "units": row[2], "object_type": row[3]})
206
207
        ################################################################################################################
208
        # Step 4: query base period energy consumption
209
        ################################################################################################################
210
        query = (" SELECT start_datetime_utc, actual_value "
211
                 " FROM tbl_meter_hourly "
212
                 " WHERE meter_id = %s "
213
                 " AND start_datetime_utc >= %s "
214
                 " AND start_datetime_utc < %s "
215
                 " ORDER BY start_datetime_utc ")
216
        cursor_energy.execute(query, (meter['id'], base_start_datetime_utc, base_end_datetime_utc))
217
        rows_meter_hourly = cursor_energy.fetchall()
218
219
        rows_meter_periodically = utilities.aggregate_hourly_data_by_period(rows_meter_hourly,
220
                                                                            base_start_datetime_utc,
221
                                                                            base_end_datetime_utc,
222
                                                                            period_type)
223
        base = dict()
224
        base['timestamps'] = list()
225
        base['values'] = list()
226
        base['total_in_category'] = Decimal(0.0)
227
        base['total_in_kgce'] = Decimal(0.0)
228
        base['total_in_kgco2e'] = Decimal(0.0)
229
230
        for row_meter_periodically in rows_meter_periodically:
231
            current_datetime_local = row_meter_periodically[0].replace(tzinfo=timezone.utc) + \
232
                                     timedelta(minutes=timezone_offset)
233
            if period_type == 'hourly':
234
                current_datetime = current_datetime_local.strftime('%Y-%m-%dT%H:%M:%S')
235
            elif period_type == 'daily':
236
                current_datetime = current_datetime_local.strftime('%Y-%m-%d')
237
            elif period_type == 'weekly':
238
                current_datetime = current_datetime_local.strftime('%Y-%m-%d')
239
            elif period_type == 'monthly':
240
                current_datetime = current_datetime_local.strftime('%Y-%m')
241
            elif period_type == 'yearly':
242
                current_datetime = current_datetime_local.strftime('%Y')
243
244
            actual_value = Decimal(0.0) if row_meter_periodically[1] is None \
245
                else row_meter_periodically[1]
246
            base['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...
247
            base['total_in_kgce'] += actual_value * meter['kgce']
248
            base['total_in_kgco2e'] += actual_value * meter['kgco2e']
249
250
        ################################################################################################################
251
        # Step 5: query base period carbon dioxide emission
252
        ################################################################################################################
253
        query = (" SELECT start_datetime_utc, actual_value "
254
                 " FROM tbl_meter_hourly "
255
                 " WHERE meter_id = %s "
256
                 " AND start_datetime_utc >= %s "
257
                 " AND start_datetime_utc < %s "
258
                 " ORDER BY start_datetime_utc ")
259
        cursor_carbon.execute(query, (meter['id'], base_start_datetime_utc, base_end_datetime_utc))
260
        rows_meter_hourly = cursor_carbon.fetchall()
261
262
        rows_meter_periodically = utilities.aggregate_hourly_data_by_period(rows_meter_hourly,
263
                                                                            base_start_datetime_utc,
264
                                                                            base_end_datetime_utc,
265
                                                                            period_type)
266
267
        base['values'] = list()
268
        base['total_in_category'] = Decimal(0.0)
269
270
        for row_meter_periodically in rows_meter_periodically:
271
            actual_value = Decimal(0.0) if row_meter_periodically[1] is None \
272
                else row_meter_periodically[1]
273
            base['values'].append(actual_value)
274
            base['total_in_category'] += actual_value
275
276
        ################################################################################################################
277
        # Step 6: query reporting period energy consumption
278
        ################################################################################################################
279
        query = (" SELECT start_datetime_utc, actual_value "
280
                 " FROM tbl_meter_hourly "
281
                 " WHERE meter_id = %s "
282
                 " AND start_datetime_utc >= %s "
283
                 " AND start_datetime_utc < %s "
284
                 " ORDER BY start_datetime_utc ")
285
        cursor_energy.execute(query, (meter['id'], reporting_start_datetime_utc, reporting_end_datetime_utc))
286
        rows_meter_hourly = cursor_energy.fetchall()
287
288
        rows_meter_periodically = utilities.aggregate_hourly_data_by_period(rows_meter_hourly,
289
                                                                            reporting_start_datetime_utc,
290
                                                                            reporting_end_datetime_utc,
291
                                                                            period_type)
292
        reporting = dict()
293
        reporting['timestamps'] = list()
294
        reporting['values'] = list()
295
        reporting['total_in_category'] = Decimal(0.0)
296
        reporting['total_in_kgce'] = Decimal(0.0)
297
        reporting['total_in_kgco2e'] = Decimal(0.0)
298
299
        for row_meter_periodically in rows_meter_periodically:
300
            current_datetime_local = row_meter_periodically[0].replace(tzinfo=timezone.utc) + \
301
                timedelta(minutes=timezone_offset)
302
            if period_type == 'hourly':
303
                current_datetime = current_datetime_local.strftime('%Y-%m-%dT%H:%M:%S')
304
            elif period_type == 'daily':
305
                current_datetime = current_datetime_local.strftime('%Y-%m-%d')
306
            elif period_type == 'weekly':
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_meter_periodically[1] is None \
314
                else row_meter_periodically[1]
315
316
            reporting['timestamps'].append(current_datetime)
317
            reporting['total_in_kgce'] += actual_value * meter['kgce']
318
            reporting['total_in_kgco2e'] += actual_value * meter['kgco2e']
319
320
        ################################################################################################################
321
        # Step 7: query reporting period carbon dioxide emission
322
        ################################################################################################################
323
        query = (" SELECT start_datetime_utc, actual_value "
324
                 " FROM tbl_meter_hourly "
325
                 " WHERE meter_id = %s "
326
                 " AND start_datetime_utc >= %s "
327
                 " AND start_datetime_utc < %s "
328
                 " ORDER BY start_datetime_utc ")
329
        cursor_carbon.execute(query, (meter['id'], reporting_start_datetime_utc, reporting_end_datetime_utc))
330
        rows_meter_hourly = cursor_carbon.fetchall()
331
332
        rows_meter_periodically = utilities.aggregate_hourly_data_by_period(rows_meter_hourly,
333
                                                                            reporting_start_datetime_utc,
334
                                                                            reporting_end_datetime_utc,
335
                                                                            period_type)
336
337
        for row_meter_periodically in rows_meter_periodically:
338
            actual_value = Decimal(0.0) if row_meter_periodically[1] is None \
339
                else row_meter_periodically[1]
340
341
            reporting['values'].append(actual_value)
342
            reporting['total_in_category'] += actual_value
343
344
        ################################################################################################################
345
        # Step 8: query tariff data
346
        ################################################################################################################
347
        parameters_data = dict()
348
        parameters_data['names'] = list()
349
        parameters_data['timestamps'] = list()
350
        parameters_data['values'] = list()
351
352
        tariff_dict = utilities.get_energy_category_tariffs(meter['cost_center_id'],
353
                                                            meter['energy_category_id'],
354
                                                            reporting_start_datetime_utc,
355
                                                            reporting_end_datetime_utc)
356
        tariff_timestamp_list = list()
357
        tariff_value_list = list()
358
        for k, v in tariff_dict.items():
359
            # convert k from utc to local
360
            k = k + timedelta(minutes=timezone_offset)
361
            tariff_timestamp_list.append(k.isoformat()[0:19])
362
            tariff_value_list.append(v)
363
364
        parameters_data['names'].append('TARIFF-' + meter['energy_category_name'])
365
        parameters_data['timestamps'].append(tariff_timestamp_list)
366
        parameters_data['values'].append(tariff_value_list)
367
368
        ################################################################################################################
369
        # Step 9: query associated points data
370
        ################################################################################################################
371
        for point in point_list:
372
            point_values = []
373
            point_timestamps = []
374
            if point['object_type'] == 'ANALOG_VALUE':
375
                query = (" SELECT utc_date_time, actual_value "
376
                         " FROM tbl_analog_value "
377
                         " WHERE point_id = %s "
378
                         "       AND utc_date_time BETWEEN %s AND %s "
379
                         " ORDER BY utc_date_time ")
380
                cursor_historical.execute(query, (point['id'],
381
                                                  reporting_start_datetime_utc,
382
                                                  reporting_end_datetime_utc))
383
                rows = cursor_historical.fetchall()
384
385
                if rows is not None and len(rows) > 0:
386
                    for row in rows:
387
                        current_datetime_local = row[0].replace(tzinfo=timezone.utc) + \
388
                                                 timedelta(minutes=timezone_offset)
389
                        current_datetime = current_datetime_local.strftime('%Y-%m-%dT%H:%M:%S')
390
                        point_timestamps.append(current_datetime)
391
                        point_values.append(row[1])
392
393
            elif point['object_type'] == 'ENERGY_VALUE':
394
                query = (" SELECT utc_date_time, actual_value "
395
                         " FROM tbl_energy_value "
396
                         " WHERE point_id = %s "
397
                         "       AND utc_date_time BETWEEN %s AND %s "
398
                         " ORDER BY utc_date_time ")
399
                cursor_historical.execute(query, (point['id'],
400
                                                  reporting_start_datetime_utc,
401
                                                  reporting_end_datetime_utc))
402
                rows = cursor_historical.fetchall()
403
404
                if rows is not None and len(rows) > 0:
405
                    for row in rows:
406
                        current_datetime_local = row[0].replace(tzinfo=timezone.utc) + \
407
                                                 timedelta(minutes=timezone_offset)
408
                        current_datetime = current_datetime_local.strftime('%Y-%m-%dT%H:%M:%S')
409
                        point_timestamps.append(current_datetime)
410
                        point_values.append(row[1])
411
            elif point['object_type'] == 'DIGITAL_VALUE':
412
                query = (" SELECT utc_date_time, actual_value "
413
                         " FROM tbl_digital_value "
414
                         " WHERE point_id = %s "
415
                         "       AND utc_date_time BETWEEN %s AND %s "
416
                         " ORDER BY utc_date_time ")
417
                cursor_historical.execute(query, (point['id'],
418
                                                  reporting_start_datetime_utc,
419
                                                  reporting_end_datetime_utc))
420
                rows = cursor_historical.fetchall()
421
422
                if rows is not None and len(rows) > 0:
423
                    for row in rows:
424
                        current_datetime_local = row[0].replace(tzinfo=timezone.utc) + \
425
                                                 timedelta(minutes=timezone_offset)
426
                        current_datetime = current_datetime_local.strftime('%Y-%m-%dT%H:%M:%S')
427
                        point_timestamps.append(current_datetime)
428
                        point_values.append(row[1])
429
430
            parameters_data['names'].append(point['name'] + ' (' + point['units'] + ')')
431
            parameters_data['timestamps'].append(point_timestamps)
432
            parameters_data['values'].append(point_values)
433
434
        ################################################################################################################
435
        # Step 10: construct the report
436
        ################################################################################################################
437
        if cursor_system:
438
            cursor_system.close()
439
        if cnx_system:
440
            cnx_system.disconnect()
441
442
        if cursor_energy:
443
            cursor_energy.close()
444
        if cnx_energy:
445
            cnx_energy.disconnect()
446
447
        if cursor_carbon:
448
            cursor_carbon.close()
449
        if cnx_carbon:
450
            cnx_carbon.disconnect()
451
452
        if cursor_historical:
453
            cursor_historical.close()
454
        if cnx_historical:
455
            cnx_historical.disconnect()
456
        result = {
457
            "meter": {
458
                "cost_center_id": meter['cost_center_id'],
459
                "energy_category_id": meter['energy_category_id'],
460
                "energy_category_name": meter['energy_category_name'],
461
                "unit_of_measure": 'KG',
462
                "kgce": meter['kgce'],
463
                "kgco2e": meter['kgco2e'],
464
            },
465
            "base_period": {
466
                "total_in_category": base['total_in_category'],
467
                "total_in_kgce": base['total_in_kgce'],
468
                "total_in_kgco2e": base['total_in_kgco2e'],
469
                "timestamps": base['timestamps'],
470
                "values": base['values'],
471
            },
472
            "reporting_period": {
473
                "increment_rate":
474
                    (reporting['total_in_category']-base['total_in_category'])/base['total_in_category']
475
                    if base['total_in_category'] > 0 else None,
476
                "total_in_category": reporting['total_in_category'],
477
                "total_in_kgce": reporting['total_in_kgce'],
478
                "total_in_kgco2e": reporting['total_in_kgco2e'],
479
                "timestamps": reporting['timestamps'],
480
                "values": reporting['values'],
481
            },
482
            "parameters": {
483
                "names": parameters_data['names'],
484
                "timestamps": parameters_data['timestamps'],
485
                "values": parameters_data['values']
486
            },
487
        }
488
        # export result to Excel file and then encode the file to base64 string
489
        result['excel_bytes_base64'] = \
490
            excelexporters.metercarbon.export(result,
491
                                              meter['name'],
492
                                              reporting_period_start_datetime_local,
493
                                              reporting_period_end_datetime_local,
494
                                              period_type)
495
496
        resp.text = json.dumps(result)
497