reports.energystoragepowerstationlist   F
last analyzed

Complexity

Total Complexity 73

Size/Duplication

Total Lines 360
Duplicated Lines 38.61 %

Importance

Changes 0
Metric Value
wmc 73
eloc 263
dl 139
loc 360
rs 2.56
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
A Reporting.__init__() 0 3 1
A Reporting.on_options() 0 4 1
F Reporting.on_get() 139 340 71

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complexity

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like reports.energystoragepowerstationlist 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
from datetime import datetime, timedelta, timezone
3
import mysql.connector
4
import simplejson as json
5
from decimal import Decimal
6
from core.useractivity import access_control
7
import config
8
9
10
class Reporting:
11
    def __init__(self):
12
        """Initializes Class"""
13
        pass
14
15
    @staticmethod
16
    def on_options(req, resp):
17
        _ = req
18
        resp.status = falcon.HTTP_200
19
20
    @staticmethod
21
    def on_get(req, resp):
22
        access_control(req)
23
        # Get user inforamtion
24
        user_uuid = str.strip(req.headers['USER-UUID'])
25
        cnx_user_db = mysql.connector.connect(**config.myems_user_db)
26
        cursor_user_db = cnx_user_db.cursor()
27
        query = (" SELECT id "
28
                 " FROM tbl_users "
29
                 " WHERE uuid = %s ")
30
        cursor_user_db.execute(query, (user_uuid,))
31
        row = cursor_user_db.fetchone()
32
        cursor_user_db.close()
33
        cnx_user_db.close()
34
        if row is None:
35
            raise falcon.HTTPError(status=falcon.HTTP_400,
36
                                   title='API.BAD_REQUEST',
37
                                   description='API.INVALID_PRIVILEGE')
38
        user_id = row[0]
39
40
        # Get all points latest values
41
        digital_value_latest_dict = dict()
42
        analog_value_latest_dict = dict()
43
44
        cnx_historical_db = mysql.connector.connect(**config.myems_historical_db)
45
        cursor_historical_db = cnx_historical_db.cursor()
46
        query = (" SELECT point_id, utc_date_time, actual_value "
47
                 " FROM tbl_digital_value_latest ")
48
        cursor_historical_db.execute(query, )
49
        rows = cursor_historical_db.fetchall()
50
        if rows is not None and len(rows) > 0:
51
            for row in rows:
52
                digital_value_latest_dict[row[0]] = {"utc_date_time": row[1],
53
                                                     "actual_value": row[2]}
54
        query = (" SELECT point_id, utc_date_time, actual_value "
55
                 " FROM tbl_analog_value_latest ")
56
        cursor_historical_db.execute(query,)
57
        rows = cursor_historical_db.fetchall()
58
        cursor_historical_db.close()
59
        cnx_historical_db.close()
60
        if rows is not None and len(rows) > 0:
61
            for row in rows:
62
                analog_value_latest_dict[row[0]] = {"utc_date_time": row[1],
63
                                                    "actual_value": row[2]}
64
65
        # get charge data in latest 24 hours
66
        timezone_offset = int(config.utc_offset[1:3]) * 60 + int(config.utc_offset[4:6])
67
        if config.utc_offset[0] == '-':
68
            timezone_offset = -timezone_offset
69
        reporting_end_datetime_utc = datetime.utcnow().replace(minute=0, second=0, microsecond=0)
70
        reporting_start_datetime_utc = reporting_end_datetime_utc - timedelta(hours=24)
71
        today_start_datetime_local = (reporting_end_datetime_utc.replace(tzinfo=timezone.utc) +
72
                                      timedelta(minutes=timezone_offset)).replace(hour=0, minute=0, second=0,
73
                                                                                  microsecond=0)
74
        charge_report_dict = dict()
75
        cnx_energy_db = mysql.connector.connect(**config.myems_energy_db)
76
        cursor_energy_db = cnx_energy_db.cursor()
77
78
        cursor_energy_db.execute(" SELECT energy_storage_power_station_id, start_datetime_utc, actual_value "
79
                                 " FROM tbl_energy_storage_power_station_charge_hourly "
80
                                 " WHERE start_datetime_utc >= %s "
81
                                 "     AND start_datetime_utc < %s "
82
                                 " ORDER BY energy_storage_power_station_id, start_datetime_utc ",
83
                                 (reporting_start_datetime_utc,
84
                                  reporting_end_datetime_utc))
85
        rows_hourly = cursor_energy_db.fetchall()
86 View Code Duplication
        if rows_hourly is not None and len(rows_hourly) > 0:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
87
            for row_hourly in rows_hourly:
88
                if row_hourly[0] not in charge_report_dict.keys():
89
                    charge_report_dict[row_hourly[0]] = dict()
90
                    charge_report_dict[row_hourly[0]]['charge_times'] = list()
91
                    charge_report_dict[row_hourly[0]]['charge_values'] = list()
92
                    # today total charge, not 24 hours
93
                    charge_report_dict[row_hourly[0]]['today_total_charge'] = Decimal(0.0)
94
95
                current_datetime_local = row_hourly[1].replace(tzinfo=timezone.utc) + timedelta(
96
                    minutes=timezone_offset)
97
                charge_report_dict[row_hourly[0]]['charge_times'].append(
98
                    current_datetime_local.isoformat()[11:16])
99
                actual_value = Decimal(0.0) if row_hourly[2] is None else row_hourly[2]
100
                charge_report_dict[row_hourly[0]]['charge_values'].append(actual_value)
101
                if current_datetime_local >= today_start_datetime_local:
102
                    charge_report_dict[row_hourly[0]]['today_total_charge'] += actual_value
103
104
        # get discharge data in latest 24 hours
105
        discharge_report_dict = dict()
106
        cursor_energy_db.execute(" SELECT energy_storage_power_station_id, start_datetime_utc, actual_value "
107
                                 " FROM tbl_energy_storage_power_station_discharge_hourly "
108
                                 " WHERE start_datetime_utc >= %s "
109
                                 "     AND start_datetime_utc < %s "
110
                                 " ORDER BY energy_storage_power_station_id, start_datetime_utc ",
111
                                 (reporting_start_datetime_utc,
112
                                  reporting_end_datetime_utc))
113
        rows_hourly = cursor_energy_db.fetchall()
114 View Code Duplication
        if rows_hourly is not None and len(rows_hourly) > 0:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
115
            for row_hourly in rows_hourly:
116
                if row_hourly[0] not in discharge_report_dict.keys():
117
                    discharge_report_dict[row_hourly[0]] = dict()
118
                    discharge_report_dict[row_hourly[0]]['discharge_times'] = list()
119
                    discharge_report_dict[row_hourly[0]]['discharge_values'] = list()
120
                    # today total discharge, not 24 hours
121
                    discharge_report_dict[row_hourly[0]]['today_total_discharge'] = Decimal(0.0)
122
123
                current_datetime_local = row_hourly[1].replace(tzinfo=timezone.utc) + timedelta(
124
                    minutes=timezone_offset)
125
                discharge_report_dict[row_hourly[0]]['discharge_times'].append(
126
                    current_datetime_local.isoformat()[11:16])
127
                actual_value = Decimal(0.0) if row_hourly[2] is None else row_hourly[2]
128
                discharge_report_dict[row_hourly[0]]['discharge_values'].append(actual_value)
129
                if current_datetime_local >= today_start_datetime_local:
130
                    discharge_report_dict[row_hourly[0]]['today_total_discharge'] += actual_value
131
132
        cursor_energy_db.close()
133
        cnx_energy_db.close()
134
135
        default_time_list = list()
136
        default_value_list = list()
137
138
        start_datetime_local = reporting_start_datetime_utc.replace(tzinfo=timezone.utc) + timedelta(
139
            minutes=timezone_offset)
140
        end_datetime_local = reporting_end_datetime_utc.replace(tzinfo=timezone.utc) + timedelta(
141
            minutes=timezone_offset)
142
        current_datetime_local = start_datetime_local
143
        while current_datetime_local < end_datetime_local:
144
            default_time_list.append(current_datetime_local.isoformat()[11:16])
145
            default_value_list.append(Decimal(0.0))
146
            current_datetime_local = current_datetime_local + timedelta(hours=1)
147
148
        # get energy storage power stations
149
        cnx_system_db = mysql.connector.connect(**config.myems_system_db)
150
        cursor_system_db = cnx_system_db.cursor()
151
        query = (" SELECT m.id, m.name, m.uuid, "
152
                 "        m.address, m.latitude, m.longitude, m.rated_capacity, m.rated_power, "
153
                 "        m.description, m.phase_of_lifecycle, m.commissioning_date "
154
                 " FROM tbl_energy_storage_power_stations m, tbl_energy_storage_power_stations_users mu "
155
                 " WHERE m.id = mu.energy_storage_power_station_id AND mu.user_id = %s "
156
                 " ORDER BY m.phase_of_lifecycle, m.id ")
157
        cursor_system_db.execute(query, (user_id, ))
158
        rows_energy_storage_power_stations = cursor_system_db.fetchall()
159
        # get all digital value points definitions
160
        point_definition_dict = dict()
161
        query = (" SELECT id, definitions "
162
                 " FROM tbl_points "
163
                 " WHERE object_type = 'DIGITAL_VALUE' AND definitions IS NOT NULL ")
164
        cursor_system_db.execute(query, ())
165
        rows_point_definitions = cursor_system_db.fetchall()
166
        if rows_point_definitions is not None and len(rows_point_definitions) > 0:
167
            for row in rows_point_definitions:
168
                try:
169
                    definition = json.loads(row[1])
170
                except Exception as e:
171
                    print("Invalid point definitions in JSON " + str(e))
172
                    continue
173
                point_definition_dict[row[0]] = definition
174
175
        # construct the report
176
        result = list()
177
        if rows_energy_storage_power_stations is not None and len(rows_energy_storage_power_stations) > 0:
178
            for row in rows_energy_storage_power_stations:
179
                energy_storage_power_station_id = row[0]
180
                # get is_online by data source latest seen datetime
181
                query = (" SELECT tds.last_seen_datetime_utc   "
182
                         " FROM tbl_energy_storage_power_stations_containers tespsesc, "
183
                         "      tbl_energy_storage_containers_power_conversion_systems tescpcs, "
184
                         "      tbl_points tp, tbl_data_sources tds  "
185
                         " WHERE tespsesc.energy_storage_power_station_id  = %s "
186
                         "        AND tespsesc.energy_storage_container_id = tescpcs.energy_storage_container_id  "
187
                         "        AND tescpcs.run_state_point_id = tp.id  "
188
                         "        AND tp.data_source_id = tds.id  "
189
                         " LIMIT 1 ")
190
                cursor_system_db.execute(query, (energy_storage_power_station_id,))
191
                row_datetime = cursor_system_db.fetchone()
192
193
                is_online = False
194
                if row_datetime is not None and len(row_datetime) > 0:
195
                    if isinstance(row_datetime[0], datetime):
196
                        if row_datetime[0] + timedelta(minutes=10) > datetime.utcnow():
197
                            is_online = True
198
199
                # get PCS run state point
200
                pcs_run_state_point_value = None
201 View Code Duplication
                if is_online:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
202
                    query = (" SELECT tescpcs.run_state_point_id "
203
                             " FROM tbl_energy_storage_power_stations_containers tespsesc, "
204
                             "     tbl_energy_storage_containers_power_conversion_systems tescpcs "
205
                             " WHERE tespsesc.energy_storage_power_station_id  = %s "
206
                             "       AND tespsesc.energy_storage_container_id = tescpcs.energy_storage_container_id "
207
                             " LIMIT 1 ")
208
                    cursor_system_db.execute(query, (energy_storage_power_station_id,))
209
                    row_point = cursor_system_db.fetchone()
210
                    if row_point is not None and len(row_point) > 0:
211
                        if digital_value_latest_dict.get(row_point[0]) is not None:
212
                            pcs_run_state_point_value = digital_value_latest_dict.get(row_point[0])['actual_value']
213
214
                    # 0:关闭 Shutdown
215
                    # 1:软启动中 Soft Starting
216
                    # 2:并网充电 On Grid Charging
217
                    # 3:并网放电 On Grid DisCharging
218
                    # 4:离网放电 Off Grid DisCharging
219
                    # 5:降额并网 Derating On Grid
220
                    # 6:待机 Standby
221
                    # 7:离网充电 Off Grid Charging
222
                    print(pcs_run_state_point_value)
223
                    if point_definition_dict.get(row_point[0]) is not None:
224
                        definition = point_definition_dict.get(row_point[0])
225
                        print(definition)
226
                        pcs_run_state = definition.get(str(pcs_run_state_point_value))
227
                    else:
228
                        if pcs_run_state_point_value is None:
229
                            pcs_run_state = 'Unknown'
230
                        elif pcs_run_state_point_value == 0:
231
                            pcs_run_state = 'Shutdown'
232
                        elif pcs_run_state_point_value == 1:
233
                            pcs_run_state = 'Running'
234
                        elif pcs_run_state_point_value == 2:
235
                            pcs_run_state = 'Running'
236
                        elif pcs_run_state_point_value == 3:
237
                            pcs_run_state = 'Running'
238
                        elif pcs_run_state_point_value == 4:
239
                            pcs_run_state = 'Running'
240
                        elif pcs_run_state_point_value == 5:
241
                            pcs_run_state = 'Running'
242
                        elif pcs_run_state_point_value == 6:
243
                            pcs_run_state = 'Standby'
244
                        elif pcs_run_state_point_value == 7:
245
                            pcs_run_state = 'Running'
246
                        else:
247
                            pcs_run_state = 'Running'
248
249
                # get battery state point
250
                battery_state_point_value = None
251 View Code Duplication
                if is_online:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
252
                    query = (" SELECT tescb.battery_state_point_id "
253
                             " FROM tbl_energy_storage_power_stations_containers tespsesc, "
254
                             "      tbl_energy_storage_containers_batteries tescb "
255
                             " WHERE tespsesc.energy_storage_power_station_id = %s "
256
                             "       AND tespsesc.energy_storage_container_id = tescb.energy_storage_container_id "
257
                             " LIMIT 1 ")
258
                    cursor_system_db.execute(query, (energy_storage_power_station_id,))
259
                    row_point = cursor_system_db.fetchone()
260
                    if row_point is not None and len(row_point) > 0:
261
                        if digital_value_latest_dict.get(row_point[0]) is not None:
262
                            battery_state_point_value = digital_value_latest_dict.get(row_point[0])['actual_value']
263
264
                    # 0预留 1故障  2预警  3待机  4禁放  5禁充  6正常 7充电 8放电 9空闲
265
                    print(battery_state_point_value)
266
                    if point_definition_dict.get(row_point[0]) is not None:
267
                        definition = point_definition_dict.get(row_point[0])
268
                        print(definition)
269
                        battery_operating_state = definition.get(str(battery_state_point_value))
270
                    else:
271
                        if battery_state_point_value is None:
272
                            battery_operating_state = 'Unknown'
273
                        elif battery_state_point_value == 0:
274
                            battery_operating_state = 'Reserved'
275
                        elif battery_state_point_value == 1:
276
                            battery_operating_state = 'Fault'
277
                        elif battery_state_point_value == 2:
278
                            battery_operating_state = 'Warning'
279
                        elif battery_state_point_value == 3:
280
                            battery_operating_state = 'Standby'
281
                        elif battery_state_point_value == 4:
282
                            battery_operating_state = 'ProhibitDisCharging'
283
                        elif battery_state_point_value == 5:
284
                            battery_operating_state = 'ProhibitCharging'
285
                        elif battery_state_point_value == 6:
286
                            battery_operating_state = 'Normal'
287
                        elif battery_state_point_value == 7:
288
                            battery_operating_state = 'Charging'
289
                        elif battery_state_point_value == 8:
290
                            battery_operating_state = 'Discharging'
291
                        elif battery_state_point_value == 9:
292
                            battery_operating_state = 'Idle'
293
                        else:
294
                            battery_operating_state = 'Unknown'
295
296
                # get battery soc point, power point
297
                battery_soc_point_value = None
298
                battery_power_point_value = None
299 View Code Duplication
                if is_online:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
300
                    query = (" SELECT tescb.soc_point_id, tescb.power_point_id "
301
                             " FROM tbl_energy_storage_power_stations_containers tespsc, "
302
                             "      tbl_energy_storage_containers_batteries tescb "
303
                             " WHERE tespsc.energy_storage_power_station_id = %s "
304
                             "       AND tespsc.energy_storage_container_id = tescb.energy_storage_container_id "
305
                             " LIMIT 1 ")
306
                    cursor_system_db.execute(query, (energy_storage_power_station_id,))
307
                    row_point = cursor_system_db.fetchone()
308
                    if row_point is not None and len(row_point) > 0:
309
                        if analog_value_latest_dict.get(row_point[0]) is not None:
310
                            battery_soc_point_value = analog_value_latest_dict.get(row_point[0])['actual_value']
311
                        if analog_value_latest_dict.get(row_point[1]) is not None:
312
                            battery_power_point_value = analog_value_latest_dict.get(row_point[1])['actual_value']
313
314
                # complete the charge_report_dict
315
                if energy_storage_power_station_id not in charge_report_dict.keys():
316
                    charge_report_dict[energy_storage_power_station_id] = dict()
317
                    charge_report_dict[energy_storage_power_station_id]['charge_times'] = default_time_list
318
                    charge_report_dict[energy_storage_power_station_id]['charge_values'] = default_value_list
319
                    charge_report_dict[energy_storage_power_station_id]['today_total_charge'] = Decimal(0.0)
320
321
                if energy_storage_power_station_id not in discharge_report_dict.keys():
322
                    discharge_report_dict[energy_storage_power_station_id] = dict()
323
                    discharge_report_dict[energy_storage_power_station_id]['discharge_times'] = default_time_list
324
                    discharge_report_dict[energy_storage_power_station_id]['discharge_values'] = default_value_list
325
                    discharge_report_dict[energy_storage_power_station_id]['today_total_discharge'] = Decimal(0.0)
326
327
                meta_result = {"id": energy_storage_power_station_id,
328
                               "name": row[1],
329
                               "uuid": row[2],
330
                               "address": row[3],
331
                               "latitude": row[4],
332
                               "longitude": row[5],
333
                               "rated_capacity": row[6],
334
                               "rated_power": row[7],
335
                               "description": row[8],
336
                               "phase_of_lifecycle": row[9],
337
                               "commissioning_date": str(row[10]) if row[10] is not None else None,
338
                               "qrcode": 'energystoragepowerstation:' + row[2],
339
                               "is_online": is_online,
340
                               "pcs_run_state": pcs_run_state,
0 ignored issues
show
introduced by
The variable pcs_run_state does not seem to be defined for all execution paths.
Loading history...
341
                               "battery_operating_state": battery_operating_state,
0 ignored issues
show
introduced by
The variable battery_operating_state does not seem to be defined for all execution paths.
Loading history...
342
                               "battery_soc_point_value": battery_soc_point_value,
343
                               "battery_power_point_value": battery_power_point_value,
344
                               "charge_times": charge_report_dict[energy_storage_power_station_id]['charge_times'],
345
                               "charge_values": charge_report_dict[energy_storage_power_station_id]['charge_values'],
346
                               "today_total_charge":
347
                                   charge_report_dict[energy_storage_power_station_id]['today_total_charge'],
348
                               "discharge_times":
349
                                   discharge_report_dict[energy_storage_power_station_id]['discharge_times'],
350
                               "discharge_values":
351
                                   discharge_report_dict[energy_storage_power_station_id]['discharge_values'],
352
                               "today_total_discharge":
353
                                   discharge_report_dict[energy_storage_power_station_id]['today_total_discharge'],
354
                               }
355
                result.append(meta_result)
356
357
        cursor_system_db.close()
358
        cnx_system_db.close()
359
        resp.text = json.dumps(result)
360